├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── doc ├── Makefile ├── README ├── make.bat └── source │ ├── conf.py │ ├── examples.rst │ ├── index.rst │ ├── modules.rst │ └── mpl_finance.rst ├── examples ├── data │ ├── yahoofinance-AAPL-20040819-20180120.csv │ ├── yahoofinance-GOOG-20040819-20180120.csv │ ├── yahoofinance-INTC-19950101-20040412.csv │ └── yahoofinance-SPY-20080101-20180101.csv ├── date_demo1.py ├── date_demo2.py ├── finance_demo.py ├── finance_work2.py ├── longshort.py └── plot_day_summary_oclh_demo.py ├── mpl_finance.py ├── setup.py ├── tests.py └── tox.ini /.gitignore: -------------------------------------------------------------------------------- 1 | doc/build 2 | doc/examples 3 | _as_gen 4 | __pycache__ 5 | *.pyc 6 | *.egg-info 7 | .tox/ 8 | .cache/ 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | sudo: false 3 | language: python 4 | matrix: 5 | include: 6 | - python: 3.6 7 | - python: 3.7 8 | - python: 3.8 9 | install: 10 | - pip install tox-travis 11 | script: tox 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | License agreement for mpl-finance 2 | ================================= 3 | 4 | 1. This LICENSE AGREEMENT is between the Matplotlib Development Team 5 | ("MDT"), and the Individual or Organization ("Licensee") accessing and 6 | otherwise using matplotlib software in source or binary form and its 7 | associated documentation. 8 | 9 | 2. Subject to the terms and conditions of this License Agreement, MDT 10 | hereby grants Licensee a nonexclusive, royalty-free, world-wide license 11 | to reproduce, analyze, test, perform and/or display publicly, prepare 12 | derivative works, distribute, and otherwise use matplotlib 13 | alone or in any derivative version, provided, however, that MDT's 14 | License Agreement and MDT's notice of copyright, i.e., "Copyright (c) 15 | 2012- Matplotlib Development Team; All Rights Reserved" are retained in 16 | matplotlib alone or in any derivative version prepared by 17 | Licensee. 18 | 19 | 3. In the event Licensee prepares a derivative work that is based on or 20 | incorporates matplotlib or any part thereof, and wants to 21 | make the derivative work available to others as provided herein, then 22 | Licensee hereby agrees to include in any such work a brief summary of 23 | the changes made to matplotlib . 24 | 25 | 4. MDT is making matplotlib available to Licensee on an "AS 26 | IS" basis. MDT MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR 27 | IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, MDT MAKES NO AND 28 | DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS 29 | FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB 30 | WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 31 | 32 | 5. MDT SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB 33 | FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR 34 | LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING 35 | MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF 36 | THE POSSIBILITY THEREOF. 37 | 38 | 6. This License Agreement will automatically terminate upon a material 39 | breach of its terms and conditions. 40 | 41 | 7. Nothing in this License Agreement shall be deemed to create any 42 | relationship of agency, partnership, or joint venture between MDT and 43 | Licensee. This License Agreement does not grant permission to use MDT 44 | trademarks or trade name in a trademark sense to endorse or promote 45 | products or services of Licensee, or any third party. 46 | 47 | 8. By copying, installing or otherwise using matplotlib , 48 | Licensee agrees to be bound by the terms and conditions of this License 49 | Agreement. 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/matplotlib/mpl-finance.svg?branch=master)](https://travis-ci.org/matplotlib/mpl-finance) 2 | 3 | # This package is deprecated. Please go here for the new version: https://github.com/matplotlib/mplfinance 4 | 5 | --- 6 | 7 | ## To Install: 8 | ## [`pip install --upgrade mplfinance`](https://pypi.org/project/mplfinance/) 9 | 10 | --- 11 | 12 |



13 | 14 | ## Background 15 | My name is Daniel Goldfarb. In November 2019, I became the maintainer of `matplotlib/mpl-finance`, and immediately began work on a new version of the module, with an all new API. The old API is still available in the new package, and will likely remain so for several months, at least until we are confident that the new API provides all of the old API's functionality (and more). **This package is now deprecated. [Please follow the above links to the new module.](https://github.com/matplotlib/mplfinance)** (This deprecated package consisted of code extracted from the deprecated `matplotlib.finance` module along with a few examples of usage. The code was un-maintained for over three years.) 16 | 17 | ## Purpose 18 | It's good to have a single statement of purpose, to guide development. The original documention for the (now twice deprecated) `matplotlib.finance` says that it was a set of functions "*for collecting, analyzing and plotting financial data.*" --- I disagree with the "*for collecting*" part: **   `mplfinance` is part of `matplotlib`.**   Therefore, I would say **the primary purpose of mplfinance is the visualization of financial data.** However, since analyzing financial data often involves visualization (for example moving averages, oscillators, bollinger bands, etc.) let's say this **also includes analyzing financial data** (at least to the extent that such analysis involves visualization). Putting this into a single statement to guide development going forward: 19 | 20 | --- 21 | **The `mplfinance` package provides utilities for the visualization, and visual analysis, of financial data** 22 | 23 | --- 24 | 25 | Let's leave the collection and acquistion of financial data to other packages. We will focus on visualization, and visual analysis, while other packages can focus on various ways of acquiring the data. That said, we can certainly provide APIs for interfacing with packages that acquire financial data, in order to more easily and directly visualize and analyze that data. 26 | 27 | **For more information, please see the following links:** 28 | 29 | - **[`pip install --upgrade mplfinance`](https://pypi.org/project/mplfinance/)** 30 | - **[The New API](https://github.com/matplotlib/mplfinance#newapi)** 31 | - **[Latest Release Info](https://github.com/matplotlib/mplfinance#release)** 32 | - **[Some Background History About This Package](https://github.com/matplotlib/mplfinance#history)** 33 | - **[Old API Availability](https://github.com/matplotlib/mplfinance#oldapi)** 34 | - **[README](https://github.com/matplotlib/mplfinance/blob/master/README.md)** 35 | 36 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 16 | 17 | .PHONY: help 18 | help: 19 | @echo "Please use \`make ' where is one of" 20 | @echo " html to make standalone HTML files" 21 | @echo " dirhtml to make HTML files named index.html in directories" 22 | @echo " singlehtml to make a single large HTML file" 23 | @echo " pickle to make pickle files" 24 | @echo " json to make JSON files" 25 | @echo " htmlhelp to make HTML files and a HTML help project" 26 | @echo " qthelp to make HTML files and a qthelp project" 27 | @echo " applehelp to make an Apple Help Book" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " epub3 to make an epub3" 31 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 32 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 33 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 34 | @echo " text to make text files" 35 | @echo " man to make manual pages" 36 | @echo " texinfo to make Texinfo files" 37 | @echo " info to make Texinfo files and run them through makeinfo" 38 | @echo " gettext to make PO message catalogs" 39 | @echo " changes to make an overview of all changed/added/deprecated items" 40 | @echo " xml to make Docutils-native XML files" 41 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 42 | @echo " linkcheck to check all external links for integrity" 43 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 44 | @echo " coverage to run coverage check of the documentation (if enabled)" 45 | @echo " dummy to check syntax errors of document sources" 46 | 47 | .PHONY: clean 48 | clean: 49 | rm -rf $(BUILDDIR)/* 50 | 51 | .PHONY: html 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | .PHONY: dirhtml 58 | dirhtml: 59 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 60 | @echo 61 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 62 | 63 | .PHONY: singlehtml 64 | singlehtml: 65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 66 | @echo 67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 68 | 69 | .PHONY: pickle 70 | pickle: 71 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 72 | @echo 73 | @echo "Build finished; now you can process the pickle files." 74 | 75 | .PHONY: json 76 | json: 77 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 78 | @echo 79 | @echo "Build finished; now you can process the JSON files." 80 | 81 | .PHONY: htmlhelp 82 | htmlhelp: 83 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 84 | @echo 85 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 86 | ".hhp project file in $(BUILDDIR)/htmlhelp." 87 | 88 | .PHONY: qthelp 89 | qthelp: 90 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 91 | @echo 92 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 93 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 94 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/mpl_finance.qhcp" 95 | @echo "To view the help file:" 96 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/mpl_finance.qhc" 97 | 98 | .PHONY: applehelp 99 | applehelp: 100 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 101 | @echo 102 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 103 | @echo "N.B. You won't be able to view it unless you put it in" \ 104 | "~/Library/Documentation/Help or install it in your application" \ 105 | "bundle." 106 | 107 | .PHONY: devhelp 108 | devhelp: 109 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 110 | @echo 111 | @echo "Build finished." 112 | @echo "To view the help file:" 113 | @echo "# mkdir -p $$HOME/.local/share/devhelp/mpl_finance" 114 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/mpl_finance" 115 | @echo "# devhelp" 116 | 117 | .PHONY: epub 118 | epub: 119 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 120 | @echo 121 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 122 | 123 | .PHONY: epub3 124 | epub3: 125 | $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 126 | @echo 127 | @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." 128 | 129 | .PHONY: latex 130 | latex: 131 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 132 | @echo 133 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 134 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 135 | "(use \`make latexpdf' here to do that automatically)." 136 | 137 | .PHONY: latexpdf 138 | latexpdf: 139 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 140 | @echo "Running LaTeX files through pdflatex..." 141 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 142 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 143 | 144 | .PHONY: latexpdfja 145 | latexpdfja: 146 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 147 | @echo "Running LaTeX files through platex and dvipdfmx..." 148 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 149 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 150 | 151 | .PHONY: text 152 | text: 153 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 154 | @echo 155 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 156 | 157 | .PHONY: man 158 | man: 159 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 160 | @echo 161 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 162 | 163 | .PHONY: texinfo 164 | texinfo: 165 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 166 | @echo 167 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 168 | @echo "Run \`make' in that directory to run these through makeinfo" \ 169 | "(use \`make info' here to do that automatically)." 170 | 171 | .PHONY: info 172 | info: 173 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 174 | @echo "Running Texinfo files through makeinfo..." 175 | make -C $(BUILDDIR)/texinfo info 176 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 177 | 178 | .PHONY: gettext 179 | gettext: 180 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 181 | @echo 182 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 183 | 184 | .PHONY: changes 185 | changes: 186 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 187 | @echo 188 | @echo "The overview file is in $(BUILDDIR)/changes." 189 | 190 | .PHONY: linkcheck 191 | linkcheck: 192 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 193 | @echo 194 | @echo "Link check complete; look for any errors in the above output " \ 195 | "or in $(BUILDDIR)/linkcheck/output.txt." 196 | 197 | .PHONY: doctest 198 | doctest: 199 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 200 | @echo "Testing of doctests in the sources finished, look at the " \ 201 | "results in $(BUILDDIR)/doctest/output.txt." 202 | 203 | .PHONY: coverage 204 | coverage: 205 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 206 | @echo "Testing of coverage in the sources finished, look at the " \ 207 | "results in $(BUILDDIR)/coverage/python.txt." 208 | 209 | .PHONY: xml 210 | xml: 211 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 212 | @echo 213 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 214 | 215 | .PHONY: pseudoxml 216 | pseudoxml: 217 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 218 | @echo 219 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 220 | 221 | .PHONY: dummy 222 | dummy: 223 | $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy 224 | @echo 225 | @echo "Build finished. Dummy builder generates no files." 226 | -------------------------------------------------------------------------------- /doc/README: -------------------------------------------------------------------------------- 1 | The module documentation is generated with Sphinx. 2 | 3 | Run "make html" to generate HTML. Then view build/index.html. 4 | 5 | -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source 10 | set I18NSPHINXOPTS=%SPHINXOPTS% source 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. epub3 to make an epub3 31 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 32 | echo. text to make text files 33 | echo. man to make manual pages 34 | echo. texinfo to make Texinfo files 35 | echo. gettext to make PO message catalogs 36 | echo. changes to make an overview over all changed/added/deprecated items 37 | echo. xml to make Docutils-native XML files 38 | echo. pseudoxml to make pseudoxml-XML files for display purposes 39 | echo. linkcheck to check all external links for integrity 40 | echo. doctest to run all doctests embedded in the documentation if enabled 41 | echo. coverage to run coverage check of the documentation if enabled 42 | echo. dummy to check syntax errors of document sources 43 | goto end 44 | ) 45 | 46 | if "%1" == "clean" ( 47 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 48 | del /q /s %BUILDDIR%\* 49 | goto end 50 | ) 51 | 52 | 53 | REM Check if sphinx-build is available and fallback to Python version if any 54 | %SPHINXBUILD% 1>NUL 2>NUL 55 | if errorlevel 9009 goto sphinx_python 56 | goto sphinx_ok 57 | 58 | :sphinx_python 59 | 60 | set SPHINXBUILD=python -m sphinx.__init__ 61 | %SPHINXBUILD% 2> nul 62 | if errorlevel 9009 ( 63 | echo. 64 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 65 | echo.installed, then set the SPHINXBUILD environment variable to point 66 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 67 | echo.may add the Sphinx directory to PATH. 68 | echo. 69 | echo.If you don't have Sphinx installed, grab it from 70 | echo.http://sphinx-doc.org/ 71 | exit /b 1 72 | ) 73 | 74 | :sphinx_ok 75 | 76 | 77 | if "%1" == "html" ( 78 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 79 | if errorlevel 1 exit /b 1 80 | echo. 81 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 82 | goto end 83 | ) 84 | 85 | if "%1" == "dirhtml" ( 86 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 87 | if errorlevel 1 exit /b 1 88 | echo. 89 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 90 | goto end 91 | ) 92 | 93 | if "%1" == "singlehtml" ( 94 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 95 | if errorlevel 1 exit /b 1 96 | echo. 97 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 98 | goto end 99 | ) 100 | 101 | if "%1" == "pickle" ( 102 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 103 | if errorlevel 1 exit /b 1 104 | echo. 105 | echo.Build finished; now you can process the pickle files. 106 | goto end 107 | ) 108 | 109 | if "%1" == "json" ( 110 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 111 | if errorlevel 1 exit /b 1 112 | echo. 113 | echo.Build finished; now you can process the JSON files. 114 | goto end 115 | ) 116 | 117 | if "%1" == "htmlhelp" ( 118 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 119 | if errorlevel 1 exit /b 1 120 | echo. 121 | echo.Build finished; now you can run HTML Help Workshop with the ^ 122 | .hhp project file in %BUILDDIR%/htmlhelp. 123 | goto end 124 | ) 125 | 126 | if "%1" == "qthelp" ( 127 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 128 | if errorlevel 1 exit /b 1 129 | echo. 130 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 131 | .qhcp project file in %BUILDDIR%/qthelp, like this: 132 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\mpl_finance.qhcp 133 | echo.To view the help file: 134 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\mpl_finance.ghc 135 | goto end 136 | ) 137 | 138 | if "%1" == "devhelp" ( 139 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 140 | if errorlevel 1 exit /b 1 141 | echo. 142 | echo.Build finished. 143 | goto end 144 | ) 145 | 146 | if "%1" == "epub" ( 147 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 148 | if errorlevel 1 exit /b 1 149 | echo. 150 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 151 | goto end 152 | ) 153 | 154 | if "%1" == "epub3" ( 155 | %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 156 | if errorlevel 1 exit /b 1 157 | echo. 158 | echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. 159 | goto end 160 | ) 161 | 162 | if "%1" == "latex" ( 163 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 164 | if errorlevel 1 exit /b 1 165 | echo. 166 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 167 | goto end 168 | ) 169 | 170 | if "%1" == "latexpdf" ( 171 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 172 | cd %BUILDDIR%/latex 173 | make all-pdf 174 | cd %~dp0 175 | echo. 176 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 177 | goto end 178 | ) 179 | 180 | if "%1" == "latexpdfja" ( 181 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 182 | cd %BUILDDIR%/latex 183 | make all-pdf-ja 184 | cd %~dp0 185 | echo. 186 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 187 | goto end 188 | ) 189 | 190 | if "%1" == "text" ( 191 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 192 | if errorlevel 1 exit /b 1 193 | echo. 194 | echo.Build finished. The text files are in %BUILDDIR%/text. 195 | goto end 196 | ) 197 | 198 | if "%1" == "man" ( 199 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 200 | if errorlevel 1 exit /b 1 201 | echo. 202 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 203 | goto end 204 | ) 205 | 206 | if "%1" == "texinfo" ( 207 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 208 | if errorlevel 1 exit /b 1 209 | echo. 210 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 211 | goto end 212 | ) 213 | 214 | if "%1" == "gettext" ( 215 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 216 | if errorlevel 1 exit /b 1 217 | echo. 218 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 219 | goto end 220 | ) 221 | 222 | if "%1" == "changes" ( 223 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 224 | if errorlevel 1 exit /b 1 225 | echo. 226 | echo.The overview file is in %BUILDDIR%/changes. 227 | goto end 228 | ) 229 | 230 | if "%1" == "linkcheck" ( 231 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 232 | if errorlevel 1 exit /b 1 233 | echo. 234 | echo.Link check complete; look for any errors in the above output ^ 235 | or in %BUILDDIR%/linkcheck/output.txt. 236 | goto end 237 | ) 238 | 239 | if "%1" == "doctest" ( 240 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 241 | if errorlevel 1 exit /b 1 242 | echo. 243 | echo.Testing of doctests in the sources finished, look at the ^ 244 | results in %BUILDDIR%/doctest/output.txt. 245 | goto end 246 | ) 247 | 248 | if "%1" == "coverage" ( 249 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 250 | if errorlevel 1 exit /b 1 251 | echo. 252 | echo.Testing of coverage in the sources finished, look at the ^ 253 | results in %BUILDDIR%/coverage/python.txt. 254 | goto end 255 | ) 256 | 257 | if "%1" == "xml" ( 258 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 259 | if errorlevel 1 exit /b 1 260 | echo. 261 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 262 | goto end 263 | ) 264 | 265 | if "%1" == "pseudoxml" ( 266 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 267 | if errorlevel 1 exit /b 1 268 | echo. 269 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 270 | goto end 271 | ) 272 | 273 | if "%1" == "dummy" ( 274 | %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy 275 | if errorlevel 1 exit /b 1 276 | echo. 277 | echo.Build finished. Dummy builder generates no files. 278 | goto end 279 | ) 280 | 281 | :end 282 | -------------------------------------------------------------------------------- /doc/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # mpl_finance documentation build configuration file, created by 4 | # sphinx-quickstart on Sat Jan 7 14:48:13 2017. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | # If extensions (or modules to document with autodoc) are in another directory, 16 | # add these directories to sys.path here. If the directory is relative to the 17 | # documentation root, use os.path.abspath to make it absolute, like shown here. 18 | # 19 | # import os 20 | # import sys 21 | # sys.path.insert(0, os.path.abspath('.')) 22 | 23 | # -- General configuration ------------------------------------------------ 24 | 25 | # If your documentation needs a minimal Sphinx version, state it here. 26 | # 27 | # needs_sphinx = '1.0' 28 | 29 | # Add any Sphinx extension module names here, as strings. They can be 30 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 31 | # ones. 32 | extensions = [ 33 | 'sphinx.ext.autodoc', 'numpydoc', 'sphinx.ext.intersphinx', 34 | 'sphinx.ext.autosummary', 'matplotlib.sphinxext.plot_directive', 35 | ] 36 | 37 | autosummary_generate = True 38 | 39 | # Add any paths that contain templates here, relative to this directory. 40 | templates_path = ['_templates'] 41 | 42 | # The suffix(es) of source filenames. 43 | # You can specify multiple suffix as a list of string: 44 | # 45 | # source_suffix = ['.rst', '.md'] 46 | source_suffix = '.rst' 47 | 48 | # The encoding of source files. 49 | # 50 | # source_encoding = 'utf-8-sig' 51 | 52 | # The master toctree document. 53 | master_doc = 'index' 54 | 55 | # General information about the project. 56 | project = u'mpl_finance' 57 | copyright = u'2018, Matplotlib Developers' 58 | author = u'Matplotlib Developers' 59 | 60 | # The version info for the project you're documenting, acts as replacement for 61 | # |version| and |release|, also used in various other places throughout the 62 | # built documents. 63 | # 64 | # The short X.Y version. 65 | version = u'0.10.0' 66 | # The full version, including alpha/beta/rc tags. 67 | release = u'0.10.0' 68 | 69 | # The language for content autogenerated by Sphinx. Refer to documentation 70 | # for a list of supported languages. 71 | # 72 | # This is also used if you do content translation via gettext catalogs. 73 | # Usually you set "language" from the command line for these cases. 74 | language = None 75 | 76 | # There are two options for replacing |today|: either, you set today to some 77 | # non-false value, then it is used: 78 | # 79 | # today = '' 80 | # 81 | # Else, today_fmt is used as the format for a strftime call. 82 | # 83 | # today_fmt = '%B %d, %Y' 84 | 85 | # List of patterns, relative to source directory, that match files and 86 | # directories to ignore when looking for source files. 87 | # This patterns also effect to html_static_path and html_extra_path 88 | exclude_patterns = [] 89 | 90 | # The reST default role (used for this markup: `text`) to use for all 91 | # documents. 92 | # 93 | # default_role = None 94 | 95 | # If true, '()' will be appended to :func: etc. cross-reference text. 96 | # 97 | # add_function_parentheses = True 98 | 99 | # If true, the current module name will be prepended to all description 100 | # unit titles (such as .. function::). 101 | # 102 | # add_module_names = True 103 | 104 | # If true, sectionauthor and moduleauthor directives will be shown in the 105 | # output. They are ignored by default. 106 | # 107 | # show_authors = False 108 | 109 | # The name of the Pygments (syntax highlighting) style to use. 110 | pygments_style = 'sphinx' 111 | 112 | # A list of ignored prefixes for module index sorting. 113 | # modindex_common_prefix = [] 114 | 115 | # If true, keep warnings as "system message" paragraphs in the built documents. 116 | # keep_warnings = False 117 | 118 | # If true, `todo` and `todoList` produce output, else they produce nothing. 119 | todo_include_todos = False 120 | 121 | 122 | # -- Options for HTML output ---------------------------------------------- 123 | 124 | # The theme to use for HTML and HTML Help pages. See the documentation for 125 | # a list of builtin themes. 126 | # 127 | # html_theme = 'alabaster' 128 | 129 | # Theme options are theme-specific and customize the look and feel of a theme 130 | # further. For a list of options available for each theme, see the 131 | # documentation. 132 | # 133 | # html_theme_options = {} 134 | 135 | # Add any paths that contain custom themes here, relative to this directory. 136 | # html_theme_path = [] 137 | 138 | # The name for this set of Sphinx documents. 139 | # " v documentation" by default. 140 | # 141 | # html_title = u'mpl_finance v0.10.0' 142 | 143 | # A shorter title for the navigation bar. Default is the same as html_title. 144 | # 145 | # html_short_title = None 146 | 147 | # The name of an image file (relative to this directory) to place at the top 148 | # of the sidebar. 149 | # 150 | # html_logo = None 151 | 152 | # The name of an image file (relative to this directory) to use as a favicon of 153 | # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 154 | # pixels large. 155 | # 156 | # html_favicon = None 157 | 158 | # Add any paths that contain custom static files (such as style sheets) here, 159 | # relative to this directory. They are copied after the builtin static files, 160 | # so a file named "default.css" will overwrite the builtin "default.css". 161 | html_static_path = [] 162 | 163 | # Add any extra paths that contain custom files (such as robots.txt or 164 | # .htaccess) here, relative to this directory. These files are copied 165 | # directly to the root of the documentation. 166 | # 167 | # html_extra_path = [] 168 | 169 | # If not None, a 'Last updated on:' timestamp is inserted at every page 170 | # bottom, using the given strftime format. 171 | # The empty string is equivalent to '%b %d, %Y'. 172 | # 173 | # html_last_updated_fmt = None 174 | 175 | # If true, SmartyPants will be used to convert quotes and dashes to 176 | # typographically correct entities. 177 | # 178 | # html_use_smartypants = True 179 | 180 | # Custom sidebar templates, maps document names to template names. 181 | # 182 | # html_sidebars = {} 183 | 184 | # Additional templates that should be rendered to pages, maps page names to 185 | # template names. 186 | # 187 | # html_additional_pages = {} 188 | 189 | # If false, no module index is generated. 190 | # 191 | # html_domain_indices = True 192 | 193 | # If false, no index is generated. 194 | # 195 | # html_use_index = True 196 | 197 | # If true, the index is split into individual pages for each letter. 198 | # 199 | # html_split_index = False 200 | 201 | # If true, links to the reST sources are added to the pages. 202 | # 203 | # html_show_sourcelink = True 204 | 205 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 206 | # 207 | # html_show_sphinx = True 208 | 209 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 210 | # 211 | # html_show_copyright = True 212 | 213 | # If true, an OpenSearch description file will be output, and all pages will 214 | # contain a tag referring to it. The value of this option must be the 215 | # base URL from which the finished HTML is served. 216 | # 217 | # html_use_opensearch = '' 218 | 219 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 220 | # html_file_suffix = None 221 | 222 | # Language to be used for generating the HTML full-text search index. 223 | # Sphinx supports the following languages: 224 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' 225 | # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' 226 | # 227 | # html_search_language = 'en' 228 | 229 | # A dictionary with options for the search language support, empty by default. 230 | # 'ja' uses this config value. 231 | # 'zh' user can custom change `jieba` dictionary path. 232 | # 233 | # html_search_options = {'type': 'default'} 234 | 235 | # The name of a javascript file (relative to the configuration directory) that 236 | # implements a search results scorer. If empty, the default will be used. 237 | # 238 | # html_search_scorer = 'scorer.js' 239 | 240 | # Output file base name for HTML help builder. 241 | htmlhelp_basename = 'mpl_financedoc' 242 | 243 | # -- Options for LaTeX output --------------------------------------------- 244 | 245 | latex_elements = { 246 | # The paper size ('letterpaper' or 'a4paper'). 247 | # 248 | # 'papersize': 'letterpaper', 249 | 250 | # The font size ('10pt', '11pt' or '12pt'). 251 | # 252 | # 'pointsize': '10pt', 253 | 254 | # Additional stuff for the LaTeX preamble. 255 | # 256 | # 'preamble': '', 257 | 258 | # Latex figure (float) alignment 259 | # 260 | # 'figure_align': 'htbp', 261 | } 262 | 263 | # Grouping the document tree into LaTeX files. List of tuples 264 | # (source start file, target name, title, 265 | # author, documentclass [howto, manual, or own class]). 266 | latex_documents = [ 267 | (master_doc, 'mpl_finance.tex', u'mpl\\_finance Documentation', 268 | u'Matplotlib Developers', 'manual'), 269 | ] 270 | 271 | # The name of an image file (relative to this directory) to place at the top of 272 | # the title page. 273 | # 274 | # latex_logo = None 275 | 276 | # For "manual" documents, if this is true, then toplevel headings are parts, 277 | # not chapters. 278 | # 279 | # latex_use_parts = False 280 | 281 | # If true, show page references after internal links. 282 | # 283 | # latex_show_pagerefs = False 284 | 285 | # If true, show URL addresses after external links. 286 | # 287 | # latex_show_urls = False 288 | 289 | # Documents to append as an appendix to all manuals. 290 | # 291 | # latex_appendices = [] 292 | 293 | # It false, will not define \strong, \code, itleref, \crossref ... but only 294 | # \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added 295 | # packages. 296 | # 297 | # latex_keep_old_macro_names = True 298 | 299 | # If false, no module index is generated. 300 | # 301 | # latex_domain_indices = True 302 | 303 | 304 | # -- Options for manual page output --------------------------------------- 305 | 306 | # One entry per manual page. List of tuples 307 | # (source start file, name, description, authors, manual section). 308 | man_pages = [ 309 | (master_doc, 'mpl_finance', u'mpl_finance Documentation', 310 | [author], 1) 311 | ] 312 | 313 | # If true, show URL addresses after external links. 314 | # 315 | # man_show_urls = False 316 | 317 | 318 | # -- Options for Texinfo output ------------------------------------------- 319 | 320 | # Grouping the document tree into Texinfo files. List of tuples 321 | # (source start file, target name, title, author, 322 | # dir menu entry, description, category) 323 | texinfo_documents = [ 324 | (master_doc, 'mpl_finance', u'mpl_finance Documentation', 325 | author, 'mpl_finance', 'One line description of project.', 326 | 'Miscellaneous'), 327 | ] 328 | 329 | # Documents to append as an appendix to all manuals. 330 | # 331 | # texinfo_appendices = [] 332 | 333 | # If false, no module index is generated. 334 | # 335 | # texinfo_domain_indices = True 336 | 337 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 338 | # 339 | # texinfo_show_urls = 'footnote' 340 | 341 | # If true, do not generate a @detailmenu in the "Top" node's menu. 342 | # 343 | # texinfo_no_detailmenu = False 344 | intersphinx_mapping = { 345 | 'python': ('https://docs.python.org/3/', None), 346 | 'numpy': ('https://docs.scipy.org/doc/numpy/', None), 347 | 'scipy': ('https://docs.scipy.org/doc/scipy/reference/', None), 348 | 'pandas': ('http://pandas.pydata.org/pandas-docs/stable', None) 349 | } 350 | -------------------------------------------------------------------------------- /doc/source/examples.rst: -------------------------------------------------------------------------------- 1 | Examples 2 | ======== 3 | 4 | .. plot:: ../../examples/date_demo1.py 5 | :include-source: 6 | 7 | .. plot:: ../../examples/date_demo2.py 8 | :include-source: 9 | 10 | .. plot:: ../../examples/finance_demo.py 11 | :include-source: 12 | 13 | .. plot:: ../../examples/finance_work2.py 14 | :include-source: 15 | 16 | .. plot:: ../../examples/longshort.py 17 | :include-source: 18 | 19 | .. plot:: ../../examples/plot_day_summary_oclh_demo.py 20 | :include-source: 21 | -------------------------------------------------------------------------------- /doc/source/index.rst: -------------------------------------------------------------------------------- 1 | .. mpl_finance documentation master file, created by 2 | sphinx-quickstart on Sat Jan 7 14:48:13 2017. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | mpl_finance: financial helpers for matplotlib 7 | ============================================= 8 | 9 | A collection of functions for analyzing and plotting financial data 10 | in combination with matplotlib. 11 | 12 | .. toctree:: 13 | :maxdepth: 2 14 | 15 | examples 16 | modules 17 | 18 | 19 | This module has been extracted from the core Matplotlib code base 20 | unchanged. Now that this code is separate from the core it can pick 21 | up dependencies, like :mod:`pandas` or :mod:`scipy` and expose a more 22 | powerful API to the user. 23 | 24 | We are looking for a finance domain-expert to lead this effort! 25 | 26 | 27 | * :ref:`genindex` 28 | * :ref:`search` 29 | -------------------------------------------------------------------------------- /doc/source/modules.rst: -------------------------------------------------------------------------------- 1 | mpl_finance 2 | =========== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | mpl_finance 8 | -------------------------------------------------------------------------------- /doc/source/mpl_finance.rst: -------------------------------------------------------------------------------- 1 | mpl_finance module 2 | ================== 3 | 4 | .. automodule:: mpl_finance 5 | :no-members: 6 | 7 | 8 | Daily Summary 9 | ------------- 10 | 11 | .. autosummary:: 12 | :toctree: _as_gen 13 | :nosignatures: 14 | 15 | 16 | plot_day_summary_oclh 17 | plot_day_summary_ohlc 18 | plot_day_summary2_ochl 19 | plot_day_summary2_ohlc 20 | 21 | Candlesticks 22 | ------------ 23 | 24 | 25 | .. autosummary:: 26 | :toctree: _as_gen 27 | :nosignatures: 28 | 29 | candlestick_ochl 30 | candlestick_ohlc 31 | 32 | 33 | candlestick2_ochl 34 | candlestick2_ohlc 35 | 36 | Volume Overlay 37 | -------------- 38 | 39 | 40 | .. autosummary:: 41 | :toctree: _as_gen 42 | :nosignatures: 43 | 44 | volume_overlay 45 | volume_overlay2 46 | volume_overlay3 47 | 48 | Other 49 | ----- 50 | 51 | .. autosummary:: 52 | :toctree: _as_gen 53 | :nosignatures: 54 | 55 | index_bar 56 | -------------------------------------------------------------------------------- /examples/date_demo1.py: -------------------------------------------------------------------------------- 1 | """ 2 | Show how to make date plots in matplotlib using date tick locators and 3 | formatters. See major_minor_demo1.py for more information on 4 | controlling major and minor ticks 5 | 6 | All matplotlib date plotting is done by converting date instances into 7 | days since the 0001-01-01 UTC. The conversion, tick locating and 8 | formatting is done behind the scenes so this is most transparent to 9 | you. The dates module provides several converter functions date2num 10 | and num2date 11 | 12 | This example requires an active internet connection since it uses 13 | yahoo finance to get the data for plotting 14 | """ 15 | 16 | import matplotlib.pyplot as plt 17 | import pandas as pd 18 | from matplotlib.dates import DateFormatter, MonthLocator, YearLocator 19 | 20 | years = YearLocator() # every year 21 | months = MonthLocator() # every month 22 | yearsFmt = DateFormatter('%Y') 23 | 24 | quotes = pd.read_csv('data/yahoofinance-INTC-19950101-20040412.csv', 25 | index_col=0, 26 | parse_dates=True, 27 | infer_datetime_format=True) 28 | 29 | dates = quotes.index 30 | opens = quotes['Open'] 31 | 32 | fig, ax = plt.subplots() 33 | ax.plot_date(dates, opens, '-') 34 | 35 | # format the ticks 36 | ax.xaxis.set_major_locator(years) 37 | ax.xaxis.set_major_formatter(yearsFmt) 38 | ax.xaxis.set_minor_locator(months) 39 | ax.autoscale_view() 40 | 41 | 42 | # format the coords message box 43 | def price(x): 44 | return '$%1.2f' % x 45 | 46 | 47 | ax.fmt_xdata = DateFormatter('%Y-%m-%d') 48 | ax.fmt_ydata = price 49 | ax.grid(True) 50 | 51 | fig.autofmt_xdate() 52 | plt.show() 53 | -------------------------------------------------------------------------------- /examples/date_demo2.py: -------------------------------------------------------------------------------- 1 | """ 2 | Show how to make date plots in matplotlib using date tick locators and 3 | formatters. See major_minor_demo1.py for more information on 4 | controlling major and minor ticks 5 | """ 6 | 7 | import matplotlib.pyplot as plt 8 | import pandas as pd 9 | from matplotlib.dates import (MONDAY, DateFormatter, MonthLocator, 10 | WeekdayLocator) 11 | 12 | date1 = "2002-1-5" 13 | date2 = "2003-12-1" 14 | 15 | # every monday 16 | mondays = WeekdayLocator(MONDAY) 17 | 18 | # every 3rd month 19 | months = MonthLocator(range(1, 13), bymonthday=1, interval=3) 20 | monthsFmt = DateFormatter("%b '%y") 21 | 22 | 23 | quotes = pd.read_csv('data/yahoofinance-INTC-19950101-20040412.csv', 24 | index_col=0, 25 | parse_dates=True, 26 | infer_datetime_format=True) 27 | 28 | # select desired range of dates 29 | quotes = quotes[(quotes.index >= date1) & (quotes.index <= date2)] 30 | 31 | dates = quotes.index 32 | opens = quotes['Open'] 33 | 34 | 35 | fig, ax = plt.subplots() 36 | ax.plot_date(dates, opens, '-') 37 | ax.xaxis.set_major_locator(months) 38 | ax.xaxis.set_major_formatter(monthsFmt) 39 | ax.xaxis.set_minor_locator(mondays) 40 | ax.autoscale_view() 41 | # ax.xaxis.grid(False, 'major') 42 | # ax.xaxis.grid(True, 'minor') 43 | ax.grid(True) 44 | 45 | fig.autofmt_xdate() 46 | 47 | plt.show() 48 | -------------------------------------------------------------------------------- /examples/finance_demo.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | import matplotlib.dates as mdates 4 | import matplotlib.pyplot as plt 5 | import pandas as pd 6 | from matplotlib.dates import MONDAY, DateFormatter, DayLocator, WeekdayLocator 7 | 8 | from mpl_finance import candlestick_ohlc 9 | 10 | date1 = "2004-2-1" 11 | date2 = "2004-4-12" 12 | 13 | 14 | mondays = WeekdayLocator(MONDAY) # major ticks on the mondays 15 | alldays = DayLocator() # minor ticks on the days 16 | weekFormatter = DateFormatter('%b %d') # e.g., Jan 12 17 | dayFormatter = DateFormatter('%d') # e.g., 12 18 | 19 | quotes = pd.read_csv('data/yahoofinance-INTC-19950101-20040412.csv', 20 | index_col=0, 21 | parse_dates=True, 22 | infer_datetime_format=True) 23 | 24 | # select desired range of dates 25 | quotes = quotes[(quotes.index >= date1) & (quotes.index <= date2)] 26 | 27 | fig, ax = plt.subplots() 28 | fig.subplots_adjust(bottom=0.2) 29 | ax.xaxis.set_major_locator(mondays) 30 | ax.xaxis.set_minor_locator(alldays) 31 | ax.xaxis.set_major_formatter(weekFormatter) 32 | # ax.xaxis.set_minor_formatter(dayFormatter) 33 | 34 | # plot_day_summary(ax, quotes, ticksize=3) 35 | candlestick_ohlc(ax, zip(mdates.date2num(quotes.index.to_pydatetime()), 36 | quotes['Open'], quotes['High'], 37 | quotes['Low'], quotes['Close']), 38 | width=0.6) 39 | 40 | ax.xaxis_date() 41 | ax.autoscale_view() 42 | plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right') 43 | 44 | plt.show() 45 | -------------------------------------------------------------------------------- /examples/finance_work2.py: -------------------------------------------------------------------------------- 1 | import matplotlib.dates as mdates 2 | import matplotlib.font_manager as font_manager 3 | import matplotlib.pyplot as plt 4 | import matplotlib.ticker as mticker 5 | import numpy as np 6 | import pandas as pd 7 | 8 | ticker = 'SPY' 9 | r = pd.read_csv('data/yahoofinance-SPY-20080101-20180101.csv', 10 | index_col=0, 11 | parse_dates=True, 12 | infer_datetime_format=True) 13 | 14 | 15 | def moving_average(x, n, type='simple'): 16 | """ 17 | compute an n period moving average. 18 | 19 | type is 'simple' | 'exponential' 20 | 21 | """ 22 | x = np.asarray(x) 23 | if type == 'simple': 24 | weights = np.ones(n) 25 | else: 26 | weights = np.exp(np.linspace(-1., 0., n)) 27 | 28 | weights /= weights.sum() 29 | 30 | a = np.convolve(x, weights, mode='full')[:len(x)] 31 | a[:n] = a[n] 32 | return a 33 | 34 | 35 | def relative_strength(prices, n=14): 36 | """ 37 | compute the n period relative strength indicator 38 | http://stockcharts.com/school/doku.php?id=chart_school:glossary_r#relativestrengthindex 39 | http://www.investopedia.com/terms/r/rsi.asp 40 | """ 41 | 42 | deltas = np.diff(prices) 43 | seed = deltas[:n + 1] 44 | up = seed[seed >= 0].sum() / n 45 | down = -seed[seed < 0].sum() / n 46 | rs = up / down 47 | rsi = np.zeros_like(prices) 48 | rsi[:n] = 100. - 100. / (1. + rs) 49 | 50 | for i in range(n, len(prices)): 51 | delta = deltas[i - 1] # cause the diff is 1 shorter 52 | 53 | if delta > 0: 54 | upval = delta 55 | downval = 0. 56 | else: 57 | upval = 0. 58 | downval = -delta 59 | 60 | up = (up * (n - 1) + upval) / n 61 | down = (down * (n - 1) + downval) / n 62 | 63 | rs = up / down 64 | rsi[i] = 100. - 100. / (1. + rs) 65 | 66 | return rsi 67 | 68 | 69 | def moving_average_convergence(x, nslow=26, nfast=12): 70 | """ 71 | compute the MACD (Moving Average Convergence/Divergence) using a fast and 72 | slow exponential moving avg 73 | 74 | return value is emaslow, emafast, macd which are len(x) arrays 75 | """ 76 | emaslow = moving_average(x, nslow, type='exponential') 77 | emafast = moving_average(x, nfast, type='exponential') 78 | return emaslow, emafast, emafast - emaslow 79 | 80 | 81 | plt.rc('axes', grid=True) 82 | plt.rc('grid', color='0.75', linestyle='-', linewidth=0.5) 83 | 84 | textsize = 9 85 | left, width = 0.1, 0.8 86 | rect1 = [left, 0.7, width, 0.2] 87 | rect2 = [left, 0.3, width, 0.4] 88 | rect3 = [left, 0.1, width, 0.2] 89 | 90 | 91 | fig = plt.figure(facecolor='white') 92 | axescolor = '#f6f6f6' # the axes background color 93 | 94 | ax1 = fig.add_axes(rect1, facecolor=axescolor) # left, bottom, width, height 95 | ax2 = fig.add_axes(rect2, facecolor=axescolor, sharex=ax1) 96 | ax2t = ax2.twinx() 97 | ax3 = fig.add_axes(rect3, facecolor=axescolor, sharex=ax1) 98 | 99 | 100 | # plot the relative strength indicator 101 | prices = r["Adj Close"] 102 | rsi = relative_strength(prices) 103 | fillcolor = 'darkgoldenrod' 104 | 105 | ax1.plot(r.index, rsi, color=fillcolor) 106 | ax1.axhline(70, color=fillcolor) 107 | ax1.axhline(30, color=fillcolor) 108 | ax1.fill_between(r.index, rsi, 70, where=(rsi >= 70), 109 | facecolor=fillcolor, edgecolor=fillcolor) 110 | ax1.fill_between(r.index, rsi, 30, where=(rsi <= 30), 111 | facecolor=fillcolor, edgecolor=fillcolor) 112 | ax1.text(0.6, 0.9, '>70 = overbought', va='top', 113 | transform=ax1.transAxes, fontsize=textsize) 114 | ax1.text(0.6, 0.1, '<30 = oversold', 115 | transform=ax1.transAxes, fontsize=textsize) 116 | ax1.set_ylim(0, 100) 117 | ax1.set_yticks([30, 70]) 118 | ax1.text(0.025, 0.95, 'RSI (14)', va='top', 119 | transform=ax1.transAxes, fontsize=textsize) 120 | ax1.set_title('%s daily' % ticker) 121 | 122 | # plot the price and volume data 123 | dx = r["Adj Close"] - r.Close 124 | low = r.Low + dx 125 | high = r.High + dx 126 | 127 | deltas = np.zeros_like(prices) 128 | deltas[1:] = np.diff(prices) 129 | up = deltas > 0 130 | ax2.vlines(r.index[up], low[up], high[up], color='black', label='_nolegend_') 131 | ax2.vlines(r.index[~up], low[~up], high[~up], 132 | color='black', label='_nolegend_') 133 | ma20 = moving_average(prices, 20, type='simple') 134 | ma200 = moving_average(prices, 200, type='simple') 135 | 136 | linema20, = ax2.plot(r.index, ma20, color='blue', lw=2, label='MA (20)') 137 | linema200, = ax2.plot(r.index, ma200, color='red', lw=2, label='MA (200)') 138 | 139 | last = r.tail(1) 140 | s = '%s O:%1.2f H:%1.2f L:%1.2f C:%1.2f, V:%1.1fM Chg:%+1.2f' % ( 141 | last.index.strftime('%Y.%m.%d')[0], 142 | last.Open, last.High, 143 | last.Low, last.Close, 144 | last.Volume * 1e-6, 145 | last.Close - last.Open) 146 | t4 = ax2.text(0.3, 0.9, s, transform=ax2.transAxes, fontsize=textsize) 147 | 148 | props = font_manager.FontProperties(size=10) 149 | leg = ax2.legend(loc='center left', shadow=True, fancybox=True, prop=props) 150 | leg.get_frame().set_alpha(0.5) 151 | 152 | 153 | volume = (r.Close * r.Volume) / 1e6 # dollar volume in millions 154 | vmax = volume.max() 155 | poly = ax2t.fill_between(r.index, volume, 0, label='Volume', 156 | facecolor=fillcolor, edgecolor=fillcolor) 157 | ax2t.set_ylim(0, 5 * vmax) 158 | ax2t.set_yticks([]) 159 | 160 | 161 | # compute the MACD indicator 162 | fillcolor = 'darkslategrey' 163 | nslow = 26 164 | nfast = 12 165 | nema = 9 166 | emaslow, emafast, macd = moving_average_convergence( 167 | prices, nslow=nslow, nfast=nfast) 168 | ema9 = moving_average(macd, nema, type='exponential') 169 | ax3.plot(r.index, macd, color='black', lw=2) 170 | ax3.plot(r.index, ema9, color='blue', lw=1) 171 | ax3.fill_between(r.index, macd - ema9, 0, alpha=0.5, 172 | facecolor=fillcolor, edgecolor=fillcolor) 173 | 174 | 175 | ax3.text(0.025, 0.95, 'MACD (%d, %d, %d)' % (nfast, nslow, nema), va='top', 176 | transform=ax3.transAxes, fontsize=textsize) 177 | 178 | # ax3.set_yticks([]) 179 | # turn off upper axis tick labels, rotate the lower ones, etc 180 | for ax in ax1, ax2, ax2t, ax3: 181 | if ax != ax3: 182 | for label in ax.get_xticklabels(): 183 | label.set_visible(False) 184 | else: 185 | for label in ax.get_xticklabels(): 186 | label.set_rotation(30) 187 | label.set_horizontalalignment('right') 188 | 189 | ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d') 190 | 191 | 192 | class MyLocator(mticker.MaxNLocator): 193 | def __init__(self, *args, **kwargs): 194 | mticker.MaxNLocator.__init__(self, *args, **kwargs) 195 | 196 | def __call__(self, *args, **kwargs): 197 | return mticker.MaxNLocator.__call__(self, *args, **kwargs) 198 | 199 | # at most 5 ticks, pruning the upper and lower so they don't overlap 200 | # with other ticks 201 | # ax2.yaxis.set_major_locator(mticker.MaxNLocator(5, prune='both')) 202 | # ax3.yaxis.set_major_locator(mticker.MaxNLocator(5, prune='both')) 203 | 204 | 205 | ax2.yaxis.set_major_locator(MyLocator(5, prune='both')) 206 | ax3.yaxis.set_major_locator(MyLocator(5, prune='both')) 207 | 208 | plt.show() 209 | -------------------------------------------------------------------------------- /examples/longshort.py: -------------------------------------------------------------------------------- 1 | """ 2 | Illustrate the rec array utility funcitons by loading prices from a 3 | csv file, computing the daily returns, appending the results to the 4 | record arrays, joining on date 5 | """ 6 | import matplotlib.mlab as mlab 7 | import matplotlib.pyplot as plt 8 | import numpy as np 9 | import pandas as pd 10 | 11 | from six.moves import urllib 12 | 13 | start_date = "2004-8-19" 14 | end_date = '2018-1-20' 15 | 16 | # grab the price data off yahoo csv quotes 17 | r1 = pd.read_csv('data/yahoofinance-AAPL-20040819-20180120.csv', 18 | index_col=0, 19 | parse_dates=True, 20 | infer_datetime_format=True) 21 | r2 = pd.read_csv('data/yahoofinance-GOOG-20040819-20180120.csv', 22 | index_col=0, 23 | parse_dates=True, 24 | infer_datetime_format=True) 25 | 26 | 27 | # compute the daily returns and add these columns to the arrays 28 | gains1 = np.zeros_like(r1["Adj Close"]) 29 | gains2 = np.zeros_like(r2["Adj Close"]) 30 | gains1[1:] = np.diff(r1["Adj Close"]) / r1["Adj Close"][:-1] 31 | gains2[1:] = np.diff(r2["Adj Close"]) / r2["Adj Close"][:-1] 32 | r1['gains'] = gains1 33 | r2['gains'] = gains2 34 | 35 | 36 | # now join them by date 37 | r = pd.merge(r1, r2, left_index=True, right_index=True, 38 | suffixes=(['1', '2']), sort=True) 39 | 40 | 41 | # long appl, short goog 42 | g = r.gains1 - r.gains2 43 | tr = (1 + g).cumprod() # the total return 44 | 45 | # plot the return 46 | fig, ax = plt.subplots() 47 | ax.plot(r.index, tr) 48 | ax.set_title('total return: long APPL, short GOOG') 49 | ax.grid() 50 | fig.autofmt_xdate() 51 | plt.show() 52 | -------------------------------------------------------------------------------- /examples/plot_day_summary_oclh_demo.py: -------------------------------------------------------------------------------- 1 | """ 2 | Show how to use plot_day_summary_oclh function 3 | """ 4 | import matplotlib.pyplot as plt 5 | import pandas as pd 6 | from matplotlib.dates import (MONDAY, DateFormatter, MonthLocator, 7 | WeekdayLocator, date2num) 8 | 9 | from mpl_finance import plot_day_summary_oclh 10 | 11 | date1 = "2003-11-1" 12 | date2 = "2003-12-1" 13 | 14 | # every monday 15 | mondays = WeekdayLocator(MONDAY) 16 | daysFmt = DateFormatter("%d %b %y") 17 | 18 | 19 | quotes = pd.read_csv('data/yahoofinance-INTC-19950101-20040412.csv', 20 | index_col=0, 21 | parse_dates=True, 22 | infer_datetime_format=True) 23 | 24 | # select desired range of dates 25 | quotes = quotes[(quotes.index >= date1) & (quotes.index <= date2)] 26 | 27 | 28 | fig, ax = plt.subplots() 29 | plot_day_summary_oclh(ax, zip(date2num(quotes.index.to_pydatetime()), 30 | quotes['Open'], quotes['Close'], 31 | quotes['Low'], quotes['High']), 32 | ticksize=3) 33 | ax.xaxis.set_major_locator(mondays) 34 | ax.xaxis.set_major_formatter(daysFmt) 35 | ax.autoscale_view() 36 | ax.xaxis.grid(True, 'major') 37 | ax.grid(True) 38 | 39 | fig.autofmt_xdate() 40 | 41 | plt.show() 42 | -------------------------------------------------------------------------------- /mpl_finance.py: -------------------------------------------------------------------------------- 1 | """ 2 | A collection of functions for analyzing and plotting 3 | financial data. User contributions welcome! 4 | 5 | """ 6 | from __future__ import (absolute_import, division, print_function, 7 | unicode_literals) 8 | 9 | import warnings as __warnings 10 | import sys as __sys 11 | if not __sys.warnoptions: 12 | import os as __os 13 | __warnings.filterwarnings("default",category=DeprecationWarning,module='mpl_finance') # Change the filter in this process 14 | __os.environ["PYTHONWARNINGS"] = "default::DeprecationWarning:mpl_finance" # Also affect subprocesses 15 | 16 | __warnings.warn('\n\n ================================================================='+ 17 | '\n\n WARNING: `mpl_finance` is deprecated:'+ 18 | '\n\n Please use `mplfinance` instead (no hyphen, no underscore).'+ 19 | '\n\n To install: `pip install --upgrade mplfinance` '+ 20 | '\n\n For more information, see: https://pypi.org/project/mplfinance/' 21 | '\n\n =================================================================\n', 22 | category=DeprecationWarning) 23 | 24 | import numpy as np 25 | from matplotlib import colors as mcolors 26 | from matplotlib.collections import LineCollection, PolyCollection 27 | from matplotlib.lines import TICKLEFT, TICKRIGHT, Line2D 28 | from matplotlib.patches import Rectangle 29 | from matplotlib.transforms import Affine2D 30 | 31 | from six.moves import xrange, zip 32 | 33 | 34 | def plot_day_summary_oclh(ax, quotes, ticksize=3, 35 | colorup='k', colordown='r'): 36 | """Plots day summary 37 | 38 | Represent the time, open, close, high, low as a vertical line 39 | ranging from low to high. The left tick is the open and the right 40 | tick is the close. 41 | 42 | 43 | 44 | Parameters 45 | ---------- 46 | ax : `Axes` 47 | an `Axes` instance to plot to 48 | quotes : sequence of (time, open, close, high, low, ...) sequences 49 | data to plot. time must be in float date format - see date2num 50 | ticksize : int 51 | open/close tick marker in points 52 | colorup : color 53 | the color of the lines where close >= open 54 | colordown : color 55 | the color of the lines where close < open 56 | 57 | Returns 58 | ------- 59 | lines : list 60 | list of tuples of the lines added (one tuple per quote) 61 | """ 62 | return _plot_day_summary(ax, quotes, ticksize=ticksize, 63 | colorup=colorup, colordown=colordown, 64 | ochl=True) 65 | 66 | 67 | def plot_day_summary_ohlc(ax, quotes, ticksize=3, 68 | colorup='k', colordown='r'): 69 | """Plots day summary 70 | 71 | Represent the time, open, high, low, close as a vertical line 72 | ranging from low to high. The left tick is the open and the right 73 | tick is the close. 74 | 75 | 76 | 77 | Parameters 78 | ---------- 79 | ax : `Axes` 80 | an `Axes` instance to plot to 81 | quotes : sequence of (time, open, high, low, close, ...) sequences 82 | data to plot. time must be in float date format - see date2num 83 | ticksize : int 84 | open/close tick marker in points 85 | colorup : color 86 | the color of the lines where close >= open 87 | colordown : color 88 | the color of the lines where close < open 89 | 90 | Returns 91 | ------- 92 | lines : list 93 | list of tuples of the lines added (one tuple per quote) 94 | """ 95 | return _plot_day_summary(ax, quotes, ticksize=ticksize, 96 | colorup=colorup, colordown=colordown, 97 | ochl=False) 98 | 99 | 100 | def _plot_day_summary(ax, quotes, ticksize=3, 101 | colorup='k', colordown='r', 102 | ochl=True): 103 | """Plots day summary 104 | 105 | 106 | Represent the time, open, high, low, close as a vertical line 107 | ranging from low to high. The left tick is the open and the right 108 | tick is the close. 109 | 110 | 111 | 112 | Parameters 113 | ---------- 114 | ax : `Axes` 115 | an `Axes` instance to plot to 116 | quotes : sequence of quote sequences 117 | data to plot. time must be in float date format - see date2num 118 | (time, open, high, low, close, ...) vs 119 | (time, open, close, high, low, ...) 120 | set by `ochl` 121 | ticksize : int 122 | open/close tick marker in points 123 | colorup : color 124 | the color of the lines where close >= open 125 | colordown : color 126 | the color of the lines where close < open 127 | ochl: bool 128 | argument to select between ochl and ohlc ordering of quotes 129 | 130 | Returns 131 | ------- 132 | lines : list 133 | list of tuples of the lines added (one tuple per quote) 134 | """ 135 | # unfortunately this has a different return type than plot_day_summary2_* 136 | lines = [] 137 | for q in quotes: 138 | if ochl: 139 | t, open, close, high, low = q[:5] 140 | else: 141 | t, open, high, low, close = q[:5] 142 | 143 | if close >= open: 144 | color = colorup 145 | else: 146 | color = colordown 147 | 148 | vline = Line2D(xdata=(t, t), ydata=(low, high), 149 | color=color, 150 | antialiased=False, # no need to antialias vert lines 151 | ) 152 | 153 | oline = Line2D(xdata=(t, t), ydata=(open, open), 154 | color=color, 155 | antialiased=False, 156 | marker=TICKLEFT, 157 | markersize=ticksize, 158 | ) 159 | 160 | cline = Line2D(xdata=(t, t), ydata=(close, close), 161 | color=color, 162 | antialiased=False, 163 | markersize=ticksize, 164 | marker=TICKRIGHT) 165 | 166 | lines.extend((vline, oline, cline)) 167 | ax.add_line(vline) 168 | ax.add_line(oline) 169 | ax.add_line(cline) 170 | 171 | ax.autoscale_view() 172 | 173 | return lines 174 | 175 | 176 | def candlestick_ochl(ax, quotes, width=0.2, colorup='k', colordown='r', 177 | alpha=1.0): 178 | """ 179 | Plot the time, open, close, high, low as a vertical line ranging 180 | from low to high. Use a rectangular bar to represent the 181 | open-close span. If close >= open, use colorup to color the bar, 182 | otherwise use colordown 183 | 184 | Parameters 185 | ---------- 186 | ax : `Axes` 187 | an Axes instance to plot to 188 | quotes : sequence of (time, open, close, high, low, ...) sequences 189 | As long as the first 5 elements are these values, 190 | the record can be as long as you want (e.g., it may store volume). 191 | 192 | time must be in float days format - see date2num 193 | 194 | width : float 195 | fraction of a day for the rectangle width 196 | colorup : color 197 | the color of the rectangle where close >= open 198 | colordown : color 199 | the color of the rectangle where close < open 200 | alpha : float 201 | the rectangle alpha level 202 | 203 | Returns 204 | ------- 205 | ret : tuple 206 | returns (lines, patches) where lines is a list of lines 207 | added and patches is a list of the rectangle patches added 208 | 209 | """ 210 | return _candlestick(ax, quotes, width=width, colorup=colorup, 211 | colordown=colordown, 212 | alpha=alpha, ochl=True) 213 | 214 | 215 | def candlestick_ohlc(ax, quotes, width=0.2, colorup='k', colordown='r', 216 | alpha=1.0): 217 | """ 218 | Plot the time, open, high, low, close as a vertical line ranging 219 | from low to high. Use a rectangular bar to represent the 220 | open-close span. If close >= open, use colorup to color the bar, 221 | otherwise use colordown 222 | 223 | Parameters 224 | ---------- 225 | ax : `Axes` 226 | an Axes instance to plot to 227 | quotes : sequence of (time, open, high, low, close, ...) sequences 228 | As long as the first 5 elements are these values, 229 | the record can be as long as you want (e.g., it may store volume). 230 | 231 | time must be in float days format - see date2num 232 | 233 | width : float 234 | fraction of a day for the rectangle width 235 | colorup : color 236 | the color of the rectangle where close >= open 237 | colordown : color 238 | the color of the rectangle where close < open 239 | alpha : float 240 | the rectangle alpha level 241 | 242 | Returns 243 | ------- 244 | ret : tuple 245 | returns (lines, patches) where lines is a list of lines 246 | added and patches is a list of the rectangle patches added 247 | 248 | """ 249 | return _candlestick(ax, quotes, width=width, colorup=colorup, 250 | colordown=colordown, 251 | alpha=alpha, ochl=False) 252 | 253 | 254 | def _candlestick(ax, quotes, width=0.2, colorup='k', colordown='r', 255 | alpha=1.0, ochl=True): 256 | """ 257 | Plot the time, open, high, low, close as a vertical line ranging 258 | from low to high. Use a rectangular bar to represent the 259 | open-close span. If close >= open, use colorup to color the bar, 260 | otherwise use colordown 261 | 262 | Parameters 263 | ---------- 264 | ax : `Axes` 265 | an Axes instance to plot to 266 | quotes : sequence of quote sequences 267 | data to plot. time must be in float date format - see date2num 268 | (time, open, high, low, close, ...) vs 269 | (time, open, close, high, low, ...) 270 | set by `ochl` 271 | width : float 272 | fraction of a day for the rectangle width 273 | colorup : color 274 | the color of the rectangle where close >= open 275 | colordown : color 276 | the color of the rectangle where close < open 277 | alpha : float 278 | the rectangle alpha level 279 | ochl: bool 280 | argument to select between ochl and ohlc ordering of quotes 281 | 282 | Returns 283 | ------- 284 | ret : tuple 285 | returns (lines, patches) where lines is a list of lines 286 | added and patches is a list of the rectangle patches added 287 | 288 | """ 289 | 290 | OFFSET = width / 2.0 291 | 292 | lines = [] 293 | patches = [] 294 | for q in quotes: 295 | if ochl: 296 | t, open, close, high, low = q[:5] 297 | else: 298 | t, open, high, low, close = q[:5] 299 | 300 | if close >= open: 301 | color = colorup 302 | lower = open 303 | height = close - open 304 | else: 305 | color = colordown 306 | lower = close 307 | height = open - close 308 | 309 | vline = Line2D( 310 | xdata=(t, t), ydata=(low, high), 311 | color=color, 312 | linewidth=0.5, 313 | antialiased=True, 314 | ) 315 | 316 | rect = Rectangle( 317 | xy=(t - OFFSET, lower), 318 | width=width, 319 | height=height, 320 | facecolor=color, 321 | edgecolor=color, 322 | ) 323 | rect.set_alpha(alpha) 324 | 325 | lines.append(vline) 326 | patches.append(rect) 327 | ax.add_line(vline) 328 | ax.add_patch(rect) 329 | ax.autoscale_view() 330 | 331 | return lines, patches 332 | 333 | 334 | def _check_input(opens, closes, highs, lows, miss=-1): 335 | """Checks that *opens*, *highs*, *lows* and *closes* have the same length. 336 | NOTE: this code assumes if any value open, high, low, close is 337 | missing (*-1*) they all are missing 338 | 339 | Parameters 340 | ---------- 341 | ax : `Axes` 342 | an Axes instance to plot to 343 | opens : sequence 344 | sequence of opening values 345 | highs : sequence 346 | sequence of high values 347 | lows : sequence 348 | sequence of low values 349 | closes : sequence 350 | sequence of closing values 351 | miss : int 352 | identifier of the missing data 353 | 354 | Raises 355 | ------ 356 | ValueError 357 | if the input sequences don't have the same length 358 | """ 359 | 360 | def _missing(sequence, miss=-1): 361 | """Returns the index in *sequence* of the missing data, identified by 362 | *miss* 363 | 364 | Parameters 365 | ---------- 366 | sequence : 367 | sequence to evaluate 368 | miss : 369 | identifier of the missing data 370 | 371 | Returns 372 | ------- 373 | where_miss: numpy.ndarray 374 | indices of the missing data 375 | """ 376 | return np.where(np.array(sequence) == miss)[0] 377 | 378 | same_length = len(opens) == len(highs) == len(lows) == len(closes) 379 | _missopens = _missing(opens) 380 | same_missing = ((_missopens == _missing(highs)).all() and 381 | (_missopens == _missing(lows)).all() and 382 | (_missopens == _missing(closes)).all()) 383 | 384 | if not (same_length and same_missing): 385 | msg = ("*opens*, *highs*, *lows* and *closes* must have the same" 386 | " length. NOTE: this code assumes if any value open, high," 387 | " low, close is missing (*-1*) they all must be missing.") 388 | raise ValueError(msg) 389 | 390 | 391 | def plot_day_summary2_ochl(ax, opens, closes, highs, lows, ticksize=4, 392 | colorup='k', colordown='r'): 393 | """Represent the time, open, close, high, low, as a vertical line 394 | ranging from low to high. The left tick is the open and the right 395 | tick is the close. 396 | 397 | Parameters 398 | ---------- 399 | ax : `Axes` 400 | an Axes instance to plot to 401 | opens : sequence 402 | sequence of opening values 403 | closes : sequence 404 | sequence of closing values 405 | highs : sequence 406 | sequence of high values 407 | lows : sequence 408 | sequence of low values 409 | ticksize : int 410 | size of open and close ticks in points 411 | colorup : color 412 | the color of the lines where close >= open 413 | colordown : color 414 | the color of the lines where close < open 415 | 416 | Returns 417 | ------- 418 | ret : list 419 | a list of lines added to the axes 420 | """ 421 | 422 | return plot_day_summary2_ohlc(ax, opens, highs, lows, closes, ticksize, 423 | colorup, colordown) 424 | 425 | 426 | def plot_day_summary2_ohlc(ax, opens, highs, lows, closes, ticksize=4, 427 | colorup='k', colordown='r'): 428 | """Represent the time, open, high, low, close as a vertical line 429 | ranging from low to high. The left tick is the open and the right 430 | tick is the close. 431 | *opens*, *highs*, *lows* and *closes* must have the same length. 432 | NOTE: this code assumes if any value open, high, low, close is 433 | missing (*-1*) they all are missing 434 | 435 | Parameters 436 | ---------- 437 | ax : `Axes` 438 | an Axes instance to plot to 439 | opens : sequence 440 | sequence of opening values 441 | highs : sequence 442 | sequence of high values 443 | lows : sequence 444 | sequence of low values 445 | closes : sequence 446 | sequence of closing values 447 | ticksize : int 448 | size of open and close ticks in points 449 | colorup : color 450 | the color of the lines where close >= open 451 | colordown : color 452 | the color of the lines where close < open 453 | 454 | Returns 455 | ------- 456 | ret : list 457 | a list of lines added to the axes 458 | """ 459 | 460 | _check_input(opens, highs, lows, closes) 461 | 462 | rangeSegments = [((i, low), (i, high)) for i, low, high in 463 | zip(xrange(len(lows)), lows, highs) if low != -1] 464 | 465 | # the ticks will be from ticksize to 0 in points at the origin and 466 | # we'll translate these to the i, close location 467 | openSegments = [((-ticksize, 0), (0, 0))] 468 | 469 | # the ticks will be from 0 to ticksize in points at the origin and 470 | # we'll translate these to the i, close location 471 | closeSegments = [((0, 0), (ticksize, 0))] 472 | 473 | offsetsOpen = [(i, open) for i, open in 474 | zip(xrange(len(opens)), opens) if open != -1] 475 | 476 | offsetsClose = [(i, close) for i, close in 477 | zip(xrange(len(closes)), closes) if close != -1] 478 | 479 | scale = ax.figure.dpi * (1.0 / 72.0) 480 | 481 | tickTransform = Affine2D().scale(scale, 0.0) 482 | 483 | colorup = mcolors.to_rgba(colorup) 484 | colordown = mcolors.to_rgba(colordown) 485 | colord = {True: colorup, False: colordown} 486 | colors = [colord[open < close] for open, close in 487 | zip(opens, closes) if open != -1 and close != -1] 488 | 489 | useAA = 0, # use tuple here 490 | lw = 1, # and here 491 | rangeCollection = LineCollection(rangeSegments, 492 | colors=colors, 493 | linewidths=lw, 494 | antialiaseds=useAA, 495 | ) 496 | 497 | openCollection = LineCollection(openSegments, 498 | colors=colors, 499 | antialiaseds=useAA, 500 | linewidths=lw, 501 | offsets=offsetsOpen, 502 | transOffset=ax.transData, 503 | ) 504 | openCollection.set_transform(tickTransform) 505 | 506 | closeCollection = LineCollection(closeSegments, 507 | colors=colors, 508 | antialiaseds=useAA, 509 | linewidths=lw, 510 | offsets=offsetsClose, 511 | transOffset=ax.transData, 512 | ) 513 | closeCollection.set_transform(tickTransform) 514 | 515 | minpy, maxx = (0, len(rangeSegments)) 516 | miny = min([low for low in lows if low != -1]) 517 | maxy = max([high for high in highs if high != -1]) 518 | corners = (minpy, miny), (maxx, maxy) 519 | ax.update_datalim(corners) 520 | ax.autoscale_view() 521 | 522 | # add these last 523 | ax.add_collection(rangeCollection) 524 | ax.add_collection(openCollection) 525 | ax.add_collection(closeCollection) 526 | return rangeCollection, openCollection, closeCollection 527 | 528 | 529 | def candlestick2_ochl(ax, opens, closes, highs, lows, width=4, 530 | colorup='k', colordown='r', 531 | alpha=0.75): 532 | """Represent the open, close as a bar line and high low range as a 533 | vertical line. 534 | 535 | Preserves the original argument order. 536 | 537 | 538 | Parameters 539 | ---------- 540 | ax : `Axes` 541 | an Axes instance to plot to 542 | opens : sequence 543 | sequence of opening values 544 | closes : sequence 545 | sequence of closing values 546 | highs : sequence 547 | sequence of high values 548 | lows : sequence 549 | sequence of low values 550 | width : int 551 | size of open and close ticks in points 552 | colorup : color 553 | the color of the lines where close >= open 554 | colordown : color 555 | the color of the lines where close < open 556 | alpha : float 557 | bar transparency 558 | 559 | Returns 560 | ------- 561 | ret : tuple 562 | (lineCollection, barCollection) 563 | """ 564 | 565 | return candlestick2_ohlc(ax, opens, highs, lows, closes, width=width, 566 | colorup=colorup, colordown=colordown, 567 | alpha=alpha) 568 | 569 | 570 | def candlestick2_ohlc(ax, opens, highs, lows, closes, width=4, 571 | colorup='k', colordown='r', 572 | alpha=0.75): 573 | """Represent the open, close as a bar line and high low range as a 574 | vertical line. 575 | 576 | NOTE: this code assumes if any value open, low, high, close is 577 | missing they all are missing 578 | 579 | 580 | Parameters 581 | ---------- 582 | ax : `Axes` 583 | an Axes instance to plot to 584 | opens : sequence 585 | sequence of opening values 586 | highs : sequence 587 | sequence of high values 588 | lows : sequence 589 | sequence of low values 590 | closes : sequence 591 | sequence of closing values 592 | width : int 593 | size of open and close ticks in points 594 | colorup : color 595 | the color of the lines where close >= open 596 | colordown : color 597 | the color of the lines where close < open 598 | alpha : float 599 | bar transparency 600 | 601 | Returns 602 | ------- 603 | ret : tuple 604 | (lineCollection, barCollection) 605 | """ 606 | 607 | _check_input(opens, highs, lows, closes) 608 | 609 | delta = width / 2. 610 | barVerts = [((i - delta, open), 611 | (i - delta, close), 612 | (i + delta, close), 613 | (i + delta, open)) 614 | for i, open, close in zip(xrange(len(opens)), opens, closes) 615 | if open != -1 and close != -1] 616 | 617 | rangeSegments = [((i, low), (i, high)) 618 | for i, low, high in zip(xrange(len(lows)), lows, highs) 619 | if low != -1] 620 | 621 | colorup = mcolors.to_rgba(colorup, alpha) 622 | colordown = mcolors.to_rgba(colordown, alpha) 623 | colord = {True: colorup, False: colordown} 624 | colors = [colord[open < close] 625 | for open, close in zip(opens, closes) 626 | if open != -1 and close != -1] 627 | 628 | useAA = 0, # use tuple here 629 | lw = 0.5, # and here 630 | rangeCollection = LineCollection(rangeSegments, 631 | colors=colors, 632 | linewidths=lw, 633 | antialiaseds=useAA, 634 | ) 635 | 636 | barCollection = PolyCollection(barVerts, 637 | facecolors=colors, 638 | edgecolors=colors, 639 | antialiaseds=useAA, 640 | linewidths=lw, 641 | ) 642 | 643 | minx, maxx = 0, len(rangeSegments) 644 | miny = min([low for low in lows if low != -1]) 645 | maxy = max([high for high in highs if high != -1]) 646 | 647 | corners = (minx, miny), (maxx, maxy) 648 | ax.update_datalim(corners) 649 | ax.autoscale_view() 650 | 651 | # add these last 652 | ax.add_collection(rangeCollection) 653 | ax.add_collection(barCollection) 654 | return rangeCollection, barCollection 655 | 656 | 657 | def volume_overlay(ax, opens, closes, volumes, 658 | colorup='k', colordown='r', 659 | width=4, alpha=1.0): 660 | """Add a volume overlay to the current axes. The opens and closes 661 | are used to determine the color of the bar. -1 is missing. If a 662 | value is missing on one it must be missing on all 663 | 664 | Parameters 665 | ---------- 666 | ax : `Axes` 667 | an Axes instance to plot to 668 | opens : sequence 669 | a sequence of opens 670 | closes : sequence 671 | a sequence of closes 672 | volumes : sequence 673 | a sequence of volumes 674 | width : int 675 | the bar width in points 676 | colorup : color 677 | the color of the lines where close >= open 678 | colordown : color 679 | the color of the lines where close < open 680 | alpha : float 681 | bar transparency 682 | 683 | Returns 684 | ------- 685 | ret : `barCollection` 686 | The `barrCollection` added to the axes 687 | 688 | """ 689 | 690 | colorup = mcolors.to_rgba(colorup, alpha) 691 | colordown = mcolors.to_rgba(colordown, alpha) 692 | colord = {True: colorup, False: colordown} 693 | colors = [colord[open < close] 694 | for open, close in zip(opens, closes) 695 | if open != -1 and close != -1] 696 | 697 | delta = width / 2. 698 | bars = [((i - delta, 0), (i - delta, v), (i + delta, v), (i + delta, 0)) 699 | for i, v in enumerate(volumes) 700 | if v != -1] 701 | 702 | barCollection = PolyCollection(bars, 703 | facecolors=colors, 704 | edgecolors=((0, 0, 0, 1), ), 705 | antialiaseds=(0,), 706 | linewidths=(0.5,), 707 | ) 708 | 709 | ax.add_collection(barCollection) 710 | corners = (0, 0), (len(bars), max(volumes)) 711 | ax.update_datalim(corners) 712 | ax.autoscale_view() 713 | 714 | # add these last 715 | return barCollection 716 | 717 | 718 | def volume_overlay2(ax, closes, volumes, 719 | colorup='k', colordown='r', 720 | width=4, alpha=1.0): 721 | """ 722 | Add a volume overlay to the current axes. The closes are used to 723 | determine the color of the bar. -1 is missing. If a value is 724 | missing on one it must be missing on all 725 | 726 | nb: first point is not displayed - it is used only for choosing the 727 | right color 728 | 729 | 730 | Parameters 731 | ---------- 732 | ax : `Axes` 733 | an Axes instance to plot to 734 | closes : sequence 735 | a sequence of closes 736 | volumes : sequence 737 | a sequence of volumes 738 | width : int 739 | the bar width in points 740 | colorup : color 741 | the color of the lines where close >= open 742 | colordown : color 743 | the color of the lines where close < open 744 | alpha : float 745 | bar transparency 746 | 747 | Returns 748 | ------- 749 | ret : `barCollection` 750 | The `barrCollection` added to the axes 751 | 752 | """ 753 | 754 | return volume_overlay(ax, closes[:-1], closes[1:], volumes[1:], 755 | colorup, colordown, width, alpha) 756 | 757 | 758 | def volume_overlay3(ax, quotes, 759 | colorup='k', colordown='r', 760 | width=4, alpha=1.0): 761 | """Add a volume overlay to the current axes. quotes is a list of (d, 762 | open, high, low, close, volume) and close-open is used to 763 | determine the color of the bar 764 | 765 | Parameters 766 | ---------- 767 | ax : `Axes` 768 | an Axes instance to plot to 769 | quotes : sequence of (time, open, high, low, close, ...) sequences 770 | data to plot. time must be in float date format - see date2num 771 | width : int 772 | the bar width in points 773 | colorup : color 774 | the color of the lines where close1 >= close0 775 | colordown : color 776 | the color of the lines where close1 < close0 777 | alpha : float 778 | bar transparency 779 | 780 | Returns 781 | ------- 782 | ret : `barCollection` 783 | The `barrCollection` added to the axes 784 | 785 | 786 | """ 787 | 788 | colorup = mcolors.to_rgba(colorup, alpha) 789 | colordown = mcolors.to_rgba(colordown, alpha) 790 | colord = {True: colorup, False: colordown} 791 | 792 | dates, opens, highs, lows, closes, volumes = list(zip(*quotes)) 793 | colors = [colord[close1 >= close0] 794 | for close0, close1 in zip(closes[:-1], closes[1:]) 795 | if close0 != -1 and close1 != -1] 796 | colors.insert(0, colord[closes[0] >= opens[0]]) 797 | 798 | right = width / 2.0 799 | left = -width / 2.0 800 | 801 | bars = [((left, 0), (left, volume), (right, volume), (right, 0)) 802 | for d, open, high, low, close, volume in quotes] 803 | 804 | sx = ax.figure.dpi * (1.0 / 72.0) # scale for points 805 | sy = ax.bbox.height / ax.viewLim.height 806 | 807 | barTransform = Affine2D().scale(sx, sy) 808 | 809 | dates = [d for d, open, high, low, close, volume in quotes] 810 | offsetsBars = [(d, 0) for d in dates] 811 | 812 | useAA = 0, # use tuple here 813 | lw = 0.5, # and here 814 | barCollection = PolyCollection(bars, 815 | facecolors=colors, 816 | edgecolors=((0, 0, 0, 1),), 817 | antialiaseds=useAA, 818 | linewidths=lw, 819 | offsets=offsetsBars, 820 | transOffset=ax.transData, 821 | ) 822 | barCollection.set_transform(barTransform) 823 | 824 | minpy, maxx = (min(dates), max(dates)) 825 | miny = 0 826 | maxy = max([volume for d, open, high, low, close, volume in quotes]) 827 | corners = (minpy, miny), (maxx, maxy) 828 | ax.update_datalim(corners) 829 | # print 'datalim', ax.dataLim.bounds 830 | # print 'viewlim', ax.viewLim.bounds 831 | 832 | ax.add_collection(barCollection) 833 | ax.autoscale_view() 834 | 835 | return barCollection 836 | 837 | 838 | def index_bar(ax, vals, 839 | facecolor='b', edgecolor='l', 840 | width=4, alpha=1.0, ): 841 | """Add a bar collection graph with height vals (-1 is missing). 842 | 843 | Parameters 844 | ---------- 845 | ax : `Axes` 846 | an Axes instance to plot to 847 | vals : sequence 848 | a sequence of values 849 | facecolor : color 850 | the color of the bar face 851 | edgecolor : color 852 | the color of the bar edges 853 | width : int 854 | the bar width in points 855 | alpha : float 856 | bar transparency 857 | 858 | Returns 859 | ------- 860 | ret : `barCollection` 861 | The `barrCollection` added to the axes 862 | 863 | """ 864 | 865 | facecolors = (mcolors.to_rgba(facecolor, alpha),) 866 | edgecolors = (mcolors.to_rgba(edgecolor, alpha),) 867 | 868 | right = width / 2.0 869 | left = -width / 2.0 870 | 871 | bars = [((left, 0), (left, v), (right, v), (right, 0)) 872 | for v in vals if v != -1] 873 | 874 | sx = ax.figure.dpi * (1.0 / 72.0) # scale for points 875 | sy = ax.bbox.height / ax.viewLim.height 876 | 877 | barTransform = Affine2D().scale(sx, sy) 878 | 879 | offsetsBars = [(i, 0) for i, v in enumerate(vals) if v != -1] 880 | 881 | barCollection = PolyCollection(bars, 882 | facecolors=facecolors, 883 | edgecolors=edgecolors, 884 | antialiaseds=(0,), 885 | linewidths=(0.5,), 886 | offsets=offsetsBars, 887 | transOffset=ax.transData, 888 | ) 889 | barCollection.set_transform(barTransform) 890 | 891 | minpy, maxx = (0, len(offsetsBars)) 892 | miny = 0 893 | maxy = max([v for v in vals if v != -1]) 894 | corners = (minpy, miny), (maxx, maxy) 895 | ax.update_datalim(corners) 896 | ax.autoscale_view() 897 | 898 | # add these last 899 | ax.add_collection(barCollection) 900 | return barCollection 901 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | with open('README.md') as f: 4 | long_description = f.read() 5 | 6 | setup(name='mpl_finance', 7 | version='0.10.1', 8 | author='MPL Developers', 9 | author_email='matplotlib-users@python.org', 10 | py_modules=['mpl_finance'], 11 | description='Finance plots using matplotlib', 12 | long_description=long_description, 13 | long_description_content_type='text/markdown; charset=UTF-8', 14 | url='http://github.com/matplotlib/mpl-finance', 15 | platforms='Cross platform (Linux, Mac OSX, Windows)', 16 | install_requires=['matplotlib'], 17 | license="BSD-style", 18 | classifiers=['Development Status :: 7 - Inactive', 19 | 'Programming Language :: Python :: 2', 20 | 'Programming Language :: Python :: 2.7', 21 | 'Programming Language :: Python :: 3', 22 | 'Programming Language :: Python :: 3.3', 23 | 'Programming Language :: Python :: 3.4', 24 | 'Programming Language :: Python :: 3.5', 25 | 'Programming Language :: Python :: 3.6', 26 | ], 27 | keywords='finance', 28 | ) 29 | -------------------------------------------------------------------------------- /tests.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import os 3 | import subprocess 4 | 5 | 6 | def test_e2e_examples(): 7 | """Run e2e tests over examples folder""" 8 | os.chdir("examples") 9 | exs = glob.glob('*.py') 10 | for ex in exs: 11 | subprocess.check_call(["python", ex]) 12 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # Tox (http://tox.testrun.org/) is a tool for running tests 2 | # in multiple virtualenvs. This configuration file will run the 3 | # test suite on all supported python versions. To use it, "pip install tox" 4 | # and then run "tox" from this directory. 5 | 6 | [tox] 7 | envlist = py36, py37, py38 8 | [pytest] 9 | python_files = 'tests.py' 10 | 11 | [testenv] 12 | deps = 13 | matplotlib 14 | numpy 15 | pandas 16 | pytest 17 | setenv = 18 | # don't use interactive backend for matplotlib in e2e tests 19 | MPLBACKEND = agg 20 | commands = 21 | pytest 22 | --------------------------------------------------------------------------------