├── .gitignore ├── .gitlab-ci.yml ├── .openapi-generator-ignore ├── .openapi-generator └── VERSION ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── examples.py ├── finnhub ├── __init__.py ├── client.py └── exceptions.py ├── git_push.sh ├── release.sh ├── requirements.txt ├── setup.cfg ├── setup.py ├── test-requirements.txt └── tox.ini /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | .idea/ 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | env/ 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *,cover 47 | .hypothesis/ 48 | venv/ 49 | .venv/ 50 | .python-version 51 | .pytest_cache 52 | 53 | # Translations 54 | *.mo 55 | *.pot 56 | 57 | # Django stuff: 58 | *.log 59 | 60 | # Sphinx documentation 61 | docs/_build/ 62 | 63 | # PyBuilder 64 | target/ 65 | 66 | #Ipython Notebook 67 | .ipynb_checkpoints 68 | .DS_Store -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # ref: https://docs.gitlab.com/ee/ci/README.html 2 | 3 | stages: 4 | - test 5 | 6 | .nosetest: 7 | stage: test 8 | script: 9 | - pip install -r requirements.txt 10 | - pip install -r test-requirements.txt 11 | - pytest --cov=finnhub 12 | 13 | nosetest-2.7: 14 | extends: .nosetest 15 | image: python:2.7-alpine 16 | nosetest-3.3: 17 | extends: .nosetest 18 | image: python:3.3-alpine 19 | nosetest-3.4: 20 | extends: .nosetest 21 | image: python:3.4-alpine 22 | nosetest-3.5: 23 | extends: .nosetest 24 | image: python:3.5-alpine 25 | nosetest-3.6: 26 | extends: .nosetest 27 | image: python:3.6-alpine 28 | nosetest-3.7: 29 | extends: .nosetest 30 | image: python:3.7-alpine 31 | nosetest-3.8: 32 | extends: .nosetest 33 | image: python:3.8-alpine 34 | -------------------------------------------------------------------------------- /.openapi-generator-ignore: -------------------------------------------------------------------------------- 1 | # OpenAPI Generator Ignore 2 | # Generated by openapi-generator https://github.com/openapitools/openapi-generator 3 | 4 | # Use this file to prevent files from being overwritten by the generator. 5 | # The patterns follow closely to .gitignore or .dockerignore. 6 | 7 | # As an example, the C# client generator defines ApiClient.cs. 8 | # You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: 9 | #ApiClient.cs 10 | 11 | # You can match any string of characters against a directory, file or extension with a single asterisk (*): 12 | #foo/*/qux 13 | # The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux 14 | 15 | # You can recursively match patterns against a directory, file or extension with a double asterisk (**): 16 | #foo/**/qux 17 | # This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux 18 | 19 | # You can also negate patterns with an exclamation (!). 20 | # For example, you can ignore all files in a docs folder with the file extension .md: 21 | #docs/*.md 22 | # Then explicitly reverse the ignore rule for a single file: 23 | #!docs/README.md 24 | -------------------------------------------------------------------------------- /.openapi-generator/VERSION: -------------------------------------------------------------------------------- 1 | 4.3.1 -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # ref: https://docs.travis-ci.com/user/languages/python 2 | language: python 3 | python: 4 | - "2.7" 5 | - "3.2" 6 | - "3.3" 7 | - "3.4" 8 | - "3.5" 9 | - "3.6" 10 | - "3.7" 11 | - "3.8" 12 | # command to install dependencies 13 | install: 14 | - "pip install -r requirements.txt" 15 | - "pip install -r test-requirements.txt" 16 | # command to run tests 17 | script: pytest --cov=finnhub 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.0.0(2020-07-20) 2 | 3 | This version simplify the usage of the library. It also makes the return data more friendly to use with other libraries like pandas 4 | 5 | ### Breaking Changes 6 | 7 | The usage has simplify to 8 | 9 | ```python 10 | import finnhub 11 | 12 | # Setup client 13 | finnhub_client = finnhub.Client(api_key="YOUR API KEY") 14 | 15 | # Stock candles 16 | print(finnhub_client.stock_candles('AAPL', 'D', 1590988249, 1591852249)) 17 | ``` 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # finnhub-python 2 | 3 | - API documentation: https://finnhub.io/docs/api 4 | - API version: 1.0.0 5 | - Package version: 2.4.23 6 | 7 | ## Installation 8 | 9 | Install package 10 | 11 | ```sh 12 | pip install finnhub-python 13 | ``` 14 | 15 | ## Getting Started 16 | 17 | Refer to [CHANGELOG](https://github.com/Finnhub-Stock-API/finnhub-python/blob/master/CHANGELOG.md) If you are coming from version 1 18 | 19 | ```python 20 | import finnhub 21 | 22 | # Setup client 23 | finnhub_client = finnhub.Client(api_key="YOUR API KEY") 24 | 25 | # Stock candles 26 | res = finnhub_client.stock_candles('AAPL', 'D', 1590988249, 1591852249) 27 | print(res) 28 | 29 | #Convert to Pandas Dataframe 30 | import pandas as pd 31 | print(pd.DataFrame(res)) 32 | 33 | # Aggregate Indicators 34 | print(finnhub_client.aggregate_indicator('AAPL', 'D')) 35 | 36 | # Basic financials 37 | print(finnhub_client.company_basic_financials('AAPL', 'all')) 38 | 39 | # Earnings surprises 40 | print(finnhub_client.company_earnings('TSLA', limit=5)) 41 | 42 | # EPS estimates 43 | print(finnhub_client.company_eps_estimates('AMZN', freq='quarterly')) 44 | 45 | # Company Executives 46 | print(finnhub_client.company_executive('AAPL')) 47 | 48 | # Company News 49 | # Need to use _from instead of from to avoid conflict 50 | print(finnhub_client.company_news('AAPL', _from="2020-06-01", to="2020-06-10")) 51 | 52 | # Company Peers 53 | print(finnhub_client.company_peers('AAPL')) 54 | 55 | # Company Profile 56 | print(finnhub_client.company_profile(symbol='AAPL')) 57 | print(finnhub_client.company_profile(isin='US0378331005')) 58 | print(finnhub_client.company_profile(cusip='037833100')) 59 | 60 | # Company Profile 2 61 | print(finnhub_client.company_profile2(symbol='AAPL')) 62 | 63 | # Revenue Estimates 64 | print(finnhub_client.company_revenue_estimates('TSLA', freq='quarterly')) 65 | 66 | # List country 67 | print(finnhub_client.country()) 68 | 69 | # Crypto Exchange 70 | print(finnhub_client.crypto_exchanges()) 71 | 72 | # Crypto symbols 73 | print(finnhub_client.crypto_symbols('BINANCE')) 74 | 75 | # Economic data 76 | print(finnhub_client.economic_data('MA-USA-656880')) 77 | 78 | # Filings 79 | print(finnhub_client.filings(symbol='AAPL', _from="2020-01-01", to="2020-06-11")) 80 | 81 | # Financials 82 | print(finnhub_client.financials('AAPL', 'bs', 'annual')) 83 | 84 | # Financials as reported 85 | print(finnhub_client.financials_reported(symbol='AAPL', freq='annual')) 86 | 87 | # Forex exchanges 88 | print(finnhub_client.forex_exchanges()) 89 | 90 | # Forex all pairs 91 | print(finnhub_client.forex_rates(base='USD')) 92 | 93 | # Forex symbols 94 | print(finnhub_client.forex_symbols('OANDA')) 95 | 96 | # Fund Ownership 97 | print(finnhub_client.fund_ownership('AMZN', limit=5)) 98 | 99 | # General news 100 | print(finnhub_client.general_news('forex', min_id=0)) 101 | 102 | # Investors ownership 103 | print(finnhub_client.ownership('AAPL', limit=5)) 104 | 105 | # IPO calendar 106 | print(finnhub_client.ipo_calendar(_from="2020-05-01", to="2020-06-01")) 107 | 108 | # Major developments 109 | print(finnhub_client.press_releases('AAPL', _from="2020-01-01", to="2020-12-31")) 110 | 111 | # News sentiment 112 | print(finnhub_client.news_sentiment('AAPL')) 113 | 114 | # Pattern recognition 115 | print(finnhub_client.pattern_recognition('AAPL', 'D')) 116 | 117 | # Price target 118 | print(finnhub_client.price_target('AAPL')) 119 | 120 | # Quote 121 | print(finnhub_client.quote('AAPL')) 122 | 123 | # Recommendation trends 124 | print(finnhub_client.recommendation_trends('AAPL')) 125 | 126 | # Stock dividends 127 | print(finnhub_client.stock_dividends('KO', _from='2019-01-01', to='2020-01-01')) 128 | 129 | # Stock dividends 2 130 | print(finnhub_client.stock_basic_dividends("KO")) 131 | 132 | # Stock symbols 133 | print(finnhub_client.stock_symbols('US')[0:5]) 134 | 135 | # Transcripts 136 | print(finnhub_client.transcripts('AAPL_162777')) 137 | 138 | # Transcripts list 139 | print(finnhub_client.transcripts_list('AAPL')) 140 | 141 | # Earnings Calendar 142 | print(finnhub_client.earnings_calendar(_from="2020-06-10", to="2020-06-30", symbol="", international=False)) 143 | 144 | # Covid-19 145 | print(finnhub_client.covid19()) 146 | 147 | # Upgrade downgrade 148 | print(finnhub_client.upgrade_downgrade(symbol='AAPL', _from='2020-01-01', to='2020-06-30')) 149 | 150 | # Economic code 151 | print(finnhub_client.economic_code()[0:5]) 152 | 153 | # Economic calendar 154 | print(finnhub_client.calendar_economic('2021-01-01', '2021-01-07')) 155 | 156 | # Support resistance 157 | print(finnhub_client.support_resistance('AAPL', 'D')) 158 | 159 | # Technical Indicator 160 | print(finnhub_client.technical_indicator(symbol="AAPL", resolution='D', _from=1583098857, to=1584308457, indicator='rsi', indicator_fields={"timeperiod": 3})) 161 | 162 | # Stock splits 163 | print(finnhub_client.stock_splits('AAPL', _from='2000-01-01', to='2020-01-01')) 164 | 165 | # Forex candles 166 | print(finnhub_client.forex_candles('OANDA:EUR_USD', 'D', 1590988249, 1591852249)) 167 | 168 | # Crypto Candles 169 | print(finnhub_client.crypto_candles('BINANCE:BTCUSDT', 'D', 1590988249, 1591852249)) 170 | 171 | # Tick Data 172 | print(finnhub_client.stock_tick('AAPL', '2020-03-25', 500, 0)) 173 | 174 | # BBO Data 175 | print(finnhub_client.stock_nbbo("AAPL", "2020-03-25", 500, 0)) 176 | 177 | # Indices Constituents 178 | print(finnhub_client.indices_const(symbol = "^GSPC")) 179 | 180 | # Indices Historical Constituents 181 | print(finnhub_client.indices_hist_const(symbol = "^GSPC")) 182 | 183 | # ETFs Profile 184 | print(finnhub_client.etfs_profile('SPY')) 185 | print(finnhub_client.etfs_profile(isin="US78462F1030")) 186 | 187 | # ETFs Holdings 188 | print(finnhub_client.etfs_holdings('SPY')) 189 | print(finnhub_client.etfs_holdings(isin="US00214Q1040", skip=2)) 190 | print(finnhub_client.etfs_holdings("IPO", date='2022-03-10')) 191 | 192 | # ETFs Sector Exposure 193 | print(finnhub_client.etfs_sector_exp('SPY')) 194 | 195 | # ETFs Country Exposure 196 | print(finnhub_client.etfs_country_exp('SPY')) 197 | 198 | # International Filings 199 | print(finnhub_client.international_filings('RY.TO')) 200 | print(finnhub_client.international_filings(country='GB')) 201 | 202 | # SEC Sentiment Analysis 203 | print(finnhub_client.sec_sentiment_analysis('0000320193-20-000052')) 204 | 205 | # SEC similarity index 206 | print(finnhub_client.sec_similarity_index('AAPL')) 207 | 208 | # Bid Ask 209 | print(finnhub_client.last_bid_ask('AAPL')) 210 | 211 | # FDA Calendar 212 | print(finnhub_client.fda_calendar()) 213 | 214 | # Symbol lookup 215 | print(finnhub_client.symbol_lookup('apple')) 216 | 217 | # Insider transactions 218 | print(finnhub_client.stock_insider_transactions('AAPL', '2021-01-01', '2021-03-01')) 219 | 220 | # Mutual Funds Profile 221 | print(finnhub_client.mutual_fund_profile("VTSAX")) 222 | print(finnhub_client.mutual_fund_profile(isin="US9229087286")) 223 | 224 | # Mutual Funds Holdings 225 | print(finnhub_client.mutual_fund_holdings("VTSAX")) 226 | print(finnhub_client.mutual_fund_holdings(isin="US9229087286", skip=2)) 227 | 228 | # Mutual Funds Sector Exposure 229 | print(finnhub_client.mutual_fund_sector_exp("VTSAX")) 230 | 231 | # Mutual Funds Country Exposure 232 | print(finnhub_client.mutual_fund_country_exp("VTSAX")) 233 | 234 | # Revenue breakdown 235 | print(finnhub_client.stock_revenue_breakdown('AAPL')) 236 | 237 | # Social sentiment 238 | print(finnhub_client.stock_social_sentiment('GME')) 239 | 240 | # Investment Themes 241 | print(finnhub_client.stock_investment_theme('financialExchangesData')) 242 | 243 | # Supply chain 244 | print(finnhub_client.stock_supply_chain('AAPL')) 245 | 246 | # Company ESG 247 | print(finnhub_client.company_esg_score("AAPL")) 248 | 249 | # Earnings Quality Score 250 | print(finnhub_client.company_earnings_quality_score('AAPL', 'quarterly')) 251 | 252 | # Crypto Profile 253 | print(finnhub_client.crypto_profile('BTC')) 254 | 255 | # EBITDA Estimates 256 | print(finnhub_client.company_ebitda_estimates("TSLA", freq="quarterly")) 257 | 258 | # EBIT Estimates 259 | print(finnhub_client.company_ebit_estimates("TSLA", freq="quarterly")) 260 | 261 | # USPTO Patent 262 | print(finnhub_client.stock_uspto_patent("AAPL", "2021-01-01", "2021-12-31")) 263 | 264 | # Visa application 265 | print(finnhub_client.stock_visa_application("AAPL", "2021-01-01", "2022-06-15")) 266 | 267 | # Insider sentiment 268 | print(finnhub_client.stock_insider_sentiment('AAPL', '2021-01-01', '2022-03-01')) 269 | 270 | # Bond Profile 271 | print(finnhub_client.bond_profile(isin='US912810TD00')) 272 | 273 | # Bond price 274 | print(finnhub_client.bond_price('US912810TD00', 1590988249, 1649099548)) 275 | 276 | # Lobbying 277 | print(finnhub_client.stock_lobbying("AAPL", "2021-01-01", "2022-06-15")) 278 | 279 | # USA Spending 280 | print(finnhub_client.stock_usa_spending("LMT", "2021-01-01", "2022-06-15")) 281 | 282 | # Sector metrics 283 | print(finnhub_client.sector_metric('NA')) 284 | 285 | ## Fund's EET data 286 | print(finnhub_client.mutual_fund_eet('LU2036931686')) 287 | print(finnhub_client.mutual_fund_eet_pai('LU2036931686')) 288 | 289 | # Symbol & ISIN change 290 | print(finnhub_client.isin_change(_from='2022-10-01', to='2022-10-07')) 291 | print(finnhub_client.symbol_change(_from='2022-10-01', to='2022-10-07')) 292 | 293 | # 13-F data 294 | print(finnhub_client.institutional_profile()) 295 | print(finnhub_client.institutional_portfolio(cik='1000097', _from='2022-01-01', to='2022-10-07')) 296 | print(finnhub_client.institutional_ownership('TSLA', '', _from='2022-01-01', to='2022-10-07')) 297 | 298 | # Bond yield and FINRA Trace tick 299 | print(finnhub_client.bond_yield_curve('10y')) 300 | print(finnhub_client.bond_tick('US693475BF18', '2022-08-19', 500, 0, 'trace')) 301 | 302 | # Congressional Trading 303 | print(finnhub_client.congressional_trading('AAPL', '2020-01-01', '2023-03-31')) 304 | 305 | # Price metrics with historical data 306 | print(finnhub_client.price_metrics(symbol="AAPL", date="2022-01-01")) 307 | 308 | ## Market Holday / Status 309 | print(finnhub_client.market_holiday(exchange='US')) 310 | print(finnhub_client.market_status(exchange='US')) 311 | 312 | ``` 313 | 314 | ## License 315 | 316 | Apache License 317 | -------------------------------------------------------------------------------- /examples.py: -------------------------------------------------------------------------------- 1 | import finnhub 2 | import os 3 | 4 | # Setup client 5 | finnhub_client = finnhub.Client(api_key=os.environ["FINNHUB_API_KEY"]) 6 | print(finnhub_client.stock_presentation('AAPL')) 7 | print(finnhub_client.stock_revenue_breakdown2('AAPL')) 8 | 9 | print(finnhub_client.earnings_call_live('2024-11-01', '2024-11-24', 'NVDA')) 10 | print(finnhub_client.historical_employee_count('AAPL', '2020-01-01', '2024-01-01')) 11 | print(finnhub_client.airline_price_index('united', '2022-01-01', '2025-01-01')) 12 | 13 | print(finnhub_client.historical_market_cap('AAPL', '2022-01-01', '2024-01-01')) 14 | print(finnhub_client.company_historical_esg_score('AAPL')) 15 | 16 | print(finnhub_client.market_holiday(exchange='US')) 17 | print(finnhub_client.market_status(exchange='US')) 18 | 19 | print(finnhub_client.bond_yield_curve('10y')) 20 | print(finnhub_client.bond_tick('US693475BF18', '2022-08-19', 500, 0, 'trace')) 21 | 22 | print(finnhub_client.congressional_trading('AAPL', '2020-01-01', '2023-03-31')) 23 | print(finnhub_client.price_metrics(symbol="AAPL", date="2022-01-01")) 24 | 25 | # Filings 26 | print(finnhub_client.filings(symbol="AAPL", _from="2023-01-01", to="2023-01-15")) 27 | 28 | print(finnhub_client.mutual_fund_eet('LU2036931686')) 29 | print(finnhub_client.mutual_fund_eet_pai('LU2036931686')) 30 | 31 | print(finnhub_client.isin_change(_from='2022-10-01', to='2022-10-07')) 32 | print(finnhub_client.symbol_change(_from='2022-10-01', to='2022-10-07')) 33 | print(finnhub_client.institutional_profile()) 34 | print(finnhub_client.institutional_portfolio(cik='1000097', _from='2022-01-01', to='2022-10-07')) 35 | print(finnhub_client.institutional_ownership('TSLA', '', _from='2022-01-01', to='2022-10-07')) 36 | 37 | # USA Spending 38 | print(finnhub_client.stock_usa_spending("LMT", "2021-01-01", "2022-06-15")) 39 | 40 | print(finnhub_client.bond_profile(isin='US912810TD00')) 41 | print(finnhub_client.bond_price('US912810TD00', 1590988249, 1649099548)) 42 | print(finnhub_client.stock_lobbying("AAPL", "2021-01-01", "2022-06-15")) 43 | 44 | # Insider sentiment 45 | print(finnhub_client.stock_insider_sentiment('AAPL', '2021-01-01', '2022-03-01')) 46 | 47 | # Stock candles 48 | print(finnhub_client.stock_candles("AAPL", "D", 1590988249, 1591852249)) 49 | 50 | # Aggregate Indicators 51 | print(finnhub_client.aggregate_indicator("AAPL", "D")) 52 | 53 | # Basic financials 54 | print(finnhub_client.company_basic_financials("AAPL", "all")) 55 | 56 | # Earnings surprises 57 | print(finnhub_client.company_earnings("TSLA", limit=5)) 58 | 59 | # EPS estimates 60 | print(finnhub_client.company_eps_estimates("AMZN", freq="quarterly")) 61 | 62 | # Company Executives 63 | print(finnhub_client.company_executive("AAPL")) 64 | 65 | # Company News 66 | # Need to use _from instead of from to avoid conflict 67 | print(finnhub_client.company_news("AAPL", _from="2020-06-01", to="2020-06-10")) 68 | 69 | # Company Peers 70 | print(finnhub_client.company_peers("AAPL")) 71 | 72 | # Company Profile 73 | print(finnhub_client.company_profile(symbol="AAPL")) 74 | print(finnhub_client.company_profile(isin="US0378331005")) 75 | print(finnhub_client.company_profile(cusip="037833100")) 76 | 77 | # Company Profile 2 78 | print(finnhub_client.company_profile2(symbol="AAPL")) 79 | 80 | # Revenue Estimates 81 | print(finnhub_client.company_revenue_estimates("TSLA", freq="quarterly")) 82 | 83 | # List country 84 | print(finnhub_client.country()) 85 | 86 | # Crypto Exchange 87 | print(finnhub_client.crypto_exchanges()) 88 | 89 | # Crypto symbols 90 | print(finnhub_client.crypto_symbols("BINANCE")) 91 | 92 | # Economic code 93 | print(finnhub_client.economic_code()[0:5]) 94 | 95 | # Economic data 96 | print(finnhub_client.economic_data("MA-USA-656880")) 97 | 98 | # Economic calendar 99 | print(finnhub_client.calendar_economic('2021-01-01', '2021-01-07')) 100 | 101 | # Financials 102 | print(finnhub_client.financials("AAPL", "bs", "annual")) 103 | 104 | # Financials as reported 105 | print(finnhub_client.financials_reported(symbol="AAPL", freq="annual")) 106 | 107 | # Forex exchanges 108 | print(finnhub_client.forex_exchanges()) 109 | 110 | # Forex all pairs 111 | print(finnhub_client.forex_rates(base="USD")) 112 | 113 | # Forex symbols 114 | print(finnhub_client.forex_symbols("OANDA")) 115 | 116 | # Fund Ownership 117 | print(finnhub_client.fund_ownership("AMZN", limit=5)) 118 | 119 | # General news 120 | print(finnhub_client.general_news("forex", min_id=0)) 121 | 122 | # Investors ownership 123 | print(finnhub_client.ownership("AAPL", limit=5)) 124 | 125 | # IPO calendar 126 | print(finnhub_client.ipo_calendar(_from="2020-05-01", to="2020-06-01")) 127 | 128 | # Major developments 129 | print(finnhub_client.press_releases("AAPL", _from="2020-01-01", to="2020-12-31")) 130 | 131 | # News sentiment 132 | print(finnhub_client.news_sentiment("AAPL")) 133 | 134 | # Pattern recognition 135 | print(finnhub_client.pattern_recognition("AAPL", "D")) 136 | 137 | # Price target 138 | print(finnhub_client.price_target("AAPL")) 139 | 140 | # Quote 141 | print(finnhub_client.quote("AAPL")) 142 | 143 | # Recommendation trends 144 | print(finnhub_client.recommendation_trends("AAPL")) 145 | 146 | # Similarity index 147 | print(finnhub_client.sim_index(symbol="AAPL", freq="annual")) 148 | 149 | # Stock dividends 150 | print(finnhub_client.stock_dividends("KO", _from="2019-01-01", to="2020-01-01")) 151 | 152 | # Stock dividends 2 153 | print(finnhub_client.stock_basic_dividends("KO")) 154 | 155 | # Stock symbols 156 | print(finnhub_client.stock_symbols("US")[0:5]) 157 | 158 | # Transcripts 159 | print(finnhub_client.transcripts("AAPL_162777")) 160 | 161 | # Transcripts list 162 | print(finnhub_client.transcripts_list("AAPL")) 163 | 164 | # Earnings Calendar 165 | print(finnhub_client.earnings_calendar(_from="2020-06-10", to="2020-06-30", symbol="", 166 | international=False)) 167 | 168 | # Covid-19 169 | print(finnhub_client.covid19()) 170 | 171 | # Upgrade downgrade 172 | print(finnhub_client.upgrade_downgrade(symbol="AAPL", _from="2020-01-01", to="2020-06-30")) 173 | 174 | # Support resistance 175 | print(finnhub_client.support_resistance("AAPL", "D")) 176 | 177 | # # Technical Indicator 178 | print( 179 | finnhub_client.technical_indicator( 180 | symbol="AAPL", 181 | resolution="D", 182 | _from=1583098857, 183 | to=1584308457, 184 | indicator="rsi", 185 | indicator_fields={"timeperiod": 3}, 186 | ) 187 | ) 188 | 189 | # Stock splits 190 | print(finnhub_client.stock_splits("AAPL", _from="2000-01-01", to="2020-01-01")) 191 | 192 | # Forex candles 193 | print(finnhub_client.forex_candles("OANDA:EUR_USD", "D", 1590988249, 1591852249)) 194 | 195 | # Crypto Candles 196 | print(finnhub_client.crypto_candles("BINANCE:BTCUSDT", "D", 1590988249, 1591852249)) 197 | 198 | # Tick Data 199 | print(finnhub_client.stock_tick("AAPL", "2020-03-25", 500, 0)) 200 | 201 | # BBO Data 202 | print(finnhub_client.stock_nbbo("AAPL", "2020-03-25", 500, 0)) 203 | 204 | # Indices Constituents 205 | print(finnhub_client.indices_const(symbol="^GSPC")) 206 | 207 | # Indices Historical Constituents 208 | print(finnhub_client.indices_hist_const(symbol="^GSPC")) 209 | 210 | # ETFs Profile 211 | print(finnhub_client.etfs_profile("SPY")) 212 | print(finnhub_client.etfs_profile(isin="US78462F1030")) 213 | 214 | # ETFs Holdings 215 | print(finnhub_client.etfs_holdings("SPY")) 216 | print(finnhub_client.etfs_holdings(isin="US00214Q1040", skip=2)) 217 | 218 | # ETFs Industry Exposure 219 | print(finnhub_client.etfs_sector_exp("SPY")) 220 | 221 | # ETFs Country Exposure 222 | print(finnhub_client.etfs_country_exp("SPY")) 223 | 224 | # International Filings 225 | print(finnhub_client.international_filings('RY.TO')) 226 | print(finnhub_client.international_filings(country='GB')) 227 | 228 | # SEC Sentiment Analysis 229 | print(finnhub_client.sec_sentiment_analysis('0000320193-20-000052')) 230 | 231 | # SEC similarity index 232 | print(finnhub_client.sec_similarity_index('AAPL')) 233 | 234 | # Bid Ask 235 | print(finnhub_client.last_bid_ask('AAPL')) 236 | 237 | # FDA Calendar 238 | print(finnhub_client.fda_calendar()) 239 | 240 | # Symbol lookup 241 | print(finnhub_client.symbol_lookup('apple')) 242 | 243 | # Insider transactions 244 | print(finnhub_client.stock_insider_transactions('AAPL', '2021-01-01', '2021-03-01')) 245 | 246 | # Mutual Funds Profile 247 | print(finnhub_client.mutual_fund_profile("VTSAX")) 248 | print(finnhub_client.mutual_fund_profile(isin="US9229087286")) 249 | 250 | # Mutual Funds Holdings 251 | print(finnhub_client.mutual_fund_holdings("VTSAX")) 252 | print(finnhub_client.mutual_fund_holdings(isin="US9229087286", skip=2)) 253 | 254 | # Mutual Funds Industry Exposure 255 | print(finnhub_client.mutual_fund_sector_exp("VTSAX")) 256 | 257 | # Mutual Funds Country Exposure 258 | print(finnhub_client.mutual_fund_country_exp("VTSAX")) 259 | 260 | # Revenue breakdown 261 | print(finnhub_client.stock_revenue_breakdown('AAPL')) 262 | 263 | # Social sentiment 264 | print(finnhub_client.stock_social_sentiment('GME')) 265 | 266 | # Investment Themes 267 | print(finnhub_client.stock_investment_theme('financialExchangesData')) 268 | 269 | # Supply chain 270 | print(finnhub_client.stock_supply_chain('AAPL')) 271 | 272 | # Company ESG 273 | print(finnhub_client.company_esg_score("AAPL")) 274 | 275 | # Earnings Quality Score 276 | print(finnhub_client.company_earnings_quality_score('AAPL', 'quarterly')) 277 | 278 | # Crypto Profile 279 | print(finnhub_client.crypto_profile('BTC')) 280 | 281 | # EBITDA Estimates 282 | print(finnhub_client.company_ebitda_estimates("TSLA", freq="quarterly")) 283 | 284 | # EBIT Estimates 285 | print(finnhub_client.company_ebit_estimates("TSLA", freq="quarterly")) 286 | 287 | # USPTO Patent 288 | print(finnhub_client.stock_uspto_patent("AAPL", "2021-01-01", "2021-12-31")) 289 | 290 | # Visa application 291 | print(finnhub_client.stock_visa_application("AAPL", "2021-01-01", "2022-06-15")) 292 | 293 | # Sector metrics 294 | print(finnhub_client.sector_metric('NA')) 295 | -------------------------------------------------------------------------------- /finnhub/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from finnhub.client import Client 4 | from finnhub.exceptions import FinnhubAPIException, FinnhubRequestException 5 | -------------------------------------------------------------------------------- /finnhub/client.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | 4 | from finnhub.exceptions import FinnhubAPIException 5 | from finnhub.exceptions import FinnhubRequestException 6 | 7 | 8 | class Client: 9 | API_URL = "https://api.finnhub.io/api/v1" 10 | DEFAULT_TIMEOUT = 10 11 | 12 | def __init__(self, api_key, proxies=None): 13 | self._session = self._init_session(api_key, proxies) 14 | 15 | @staticmethod 16 | def _init_session(api_key, proxies): 17 | session = requests.session() 18 | session.headers.update({"Accept": "application/json", 19 | "User-Agent": "finnhub/python"}) 20 | session.params["token"] = api_key 21 | if proxies is not None: 22 | session.proxies.update(proxies) 23 | 24 | return session 25 | 26 | def close(self): 27 | self._session.close() 28 | 29 | def __enter__(self): 30 | return self 31 | 32 | def __exit__(self, *exc): 33 | self.close() 34 | 35 | def _request(self, method, path, **kwargs): 36 | uri = "{}/{}".format(self.API_URL, path) 37 | kwargs["timeout"] = kwargs.get("timeout", self.DEFAULT_TIMEOUT) 38 | kwargs["params"] = self._format_params(kwargs.get("params", {})) 39 | 40 | response = getattr(self._session, method)(uri, **kwargs) 41 | return self._handle_response(response) 42 | 43 | @staticmethod 44 | def _handle_response(response): 45 | if not response.ok: 46 | raise FinnhubAPIException(response) 47 | 48 | try: 49 | content_type = response.headers.get('Content-Type', '') 50 | if 'application/json' in content_type: 51 | return response.json() 52 | if 'text/csv' in content_type: 53 | return response.text 54 | if 'text/plain' in content_type: 55 | return response.text 56 | raise FinnhubRequestException("Invalid Response: {}".format(response.text)) 57 | except ValueError: 58 | raise FinnhubRequestException("Invalid Response: {}".format(response.text)) 59 | 60 | @staticmethod 61 | def _merge_two_dicts(first, second): 62 | result = first.copy() 63 | result.update(second) 64 | return result 65 | 66 | @staticmethod 67 | def _format_params(params): 68 | return {k: json.dumps(v) if isinstance(v, bool) else v for k, v in params.items()} 69 | 70 | def _get(self, path, **kwargs): 71 | return self._request("get", path, **kwargs) 72 | 73 | @property 74 | def api_key(self): 75 | return self._session.params.get("token") 76 | 77 | @api_key.setter 78 | def api_key(self, token): 79 | self._session.params["token"] = token 80 | 81 | def covid19(self): 82 | return self._get("/covid19/us") 83 | 84 | def company_profile(self, **params): 85 | return self._get("/stock/profile", params=params) 86 | 87 | def company_profile2(self, **params): 88 | return self._get("/stock/profile2", params=params) 89 | 90 | def aggregate_indicator(self, symbol, resolution): 91 | return self._get("/scan/technical-indicator", params={ 92 | "symbol": symbol, 93 | "resolution": resolution, 94 | }) 95 | 96 | def crypto_exchanges(self): 97 | return self._get("/crypto/exchange") 98 | 99 | def forex_exchanges(self): 100 | return self._get("/forex/exchange") 101 | 102 | def press_releases(self, symbol, _from=None, to=None): 103 | return self._get("/press-releases", params={ 104 | "symbol": symbol, 105 | "from": _from, 106 | "to": to 107 | }) 108 | 109 | def company_executive(self, symbol): 110 | return self._get("/stock/executive", params={"symbol": symbol}) 111 | 112 | def stock_dividends(self, symbol, _from=None, to=None): 113 | return self._get("/stock/dividend", params={ 114 | "symbol": symbol, 115 | "from": _from, 116 | "to": to 117 | }) 118 | 119 | def stock_basic_dividends(self, symbol): 120 | return self._get("/stock/dividend2", params={"symbol": symbol}) 121 | 122 | def stock_symbols(self, exchange, mic=None, security_type=None, currency=None): 123 | return self._get("/stock/symbol", 124 | params={"exchange": exchange, 'mic': mic, 'securityType': security_type, 'currency': currency}) 125 | 126 | def recommendation_trends(self, symbol): 127 | return self._get("/stock/recommendation", params={"symbol": symbol}) 128 | 129 | def price_target(self, symbol): 130 | return self._get("/stock/price-target", params={"symbol": symbol}) 131 | 132 | def upgrade_downgrade(self, symbol=None, _from=None, to=None): 133 | return self._get("/stock/upgrade-downgrade", params={'symbol': symbol, 'from': _from, 'to': to}) 134 | 135 | def option_chain(self, **params): 136 | return self._get("/stock/option-chain", params=params) 137 | 138 | def company_peers(self, symbol): 139 | return self._get("/stock/peers", params={"symbol": symbol}) 140 | 141 | def company_basic_financials(self, symbol, metric): 142 | return self._get("/stock/metric", params={ 143 | "symbol": symbol, 144 | "metric": metric 145 | }) 146 | 147 | def financials(self, symbol, statement, freq): 148 | return self._get("/stock/financials", params={ 149 | "symbol": symbol, 150 | "statement": statement, 151 | "freq": freq 152 | }) 153 | 154 | def financials_reported(self, **params): 155 | return self._get("/stock/financials-reported", params=params) 156 | 157 | def fund_ownership(self, symbol, limit=None): 158 | return self._get("/stock/fund-ownership", params={ 159 | "symbol": symbol, 160 | "limit": limit 161 | }) 162 | 163 | def company_earnings(self, symbol, limit=None): 164 | return self._get("/stock/earnings", params={ 165 | "symbol": symbol, 166 | "limit": limit 167 | }) 168 | 169 | def company_revenue_estimates(self, symbol, freq=None): 170 | return self._get("/stock/revenue-estimate", params={ 171 | "symbol": symbol, 172 | "freq": freq 173 | }) 174 | 175 | def company_ebitda_estimates(self, symbol, freq=None): 176 | return self._get("/stock/ebitda-estimate", params={ 177 | "symbol": symbol, 178 | "freq": freq 179 | }) 180 | 181 | def company_ebit_estimates(self, symbol, freq=None): 182 | return self._get("/stock/ebit-estimate", params={ 183 | "symbol": symbol, 184 | "freq": freq 185 | }) 186 | 187 | def company_eps_estimates(self, symbol, freq=None): 188 | return self._get("/stock/eps-estimate", params={ 189 | "symbol": symbol, 190 | "freq": freq 191 | }) 192 | 193 | def exchange(self): 194 | return self._get("/stock/exchange") 195 | 196 | def filings(self, symbol='', cik='', access_number='', form='', _from='', to=''): 197 | return self._get("/stock/filings", 198 | params={"symbol": symbol, "cik": cik, "accessNumber": access_number, "form": form, 199 | "from": _from, "to": to}) 200 | 201 | def stock_symbol(self, **params): 202 | return self._get("/stock/symbol", params=params) 203 | 204 | def quote(self, symbol): 205 | return self._get("/quote", params={ 206 | "symbol": symbol 207 | }) 208 | 209 | def transcripts(self, _id): 210 | return self._get("/stock/transcripts", params={"id": _id}) 211 | 212 | def transcripts_list(self, symbol): 213 | return self._get("/stock/transcripts/list", params={"symbol": symbol}) 214 | 215 | def sim_index(self, **params): 216 | return self._get("/stock/similarity-index", params=params) 217 | 218 | def stock_candles(self, symbol, resolution, _from, to, **kwargs): 219 | params = self._merge_two_dicts({ 220 | "symbol": symbol, 221 | "resolution": resolution, 222 | "from": _from, 223 | "to": to 224 | }, kwargs) 225 | 226 | return self._get("/stock/candle", params=params) 227 | 228 | def stock_tick(self, symbol, date, limit, skip, _format='json', **kwargs): 229 | params = self._merge_two_dicts({ 230 | "symbol": symbol, 231 | "date": date, 232 | "limit": limit, 233 | "skip": skip, 234 | "format": _format 235 | }, kwargs) 236 | 237 | return self._get("/stock/tick", params=params) 238 | 239 | def stock_nbbo(self, symbol, date, limit, skip, _format='json', **kwargs): 240 | params = self._merge_two_dicts({ 241 | "symbol": symbol, 242 | "date": date, 243 | "limit": limit, 244 | "skip": skip, 245 | "format": _format 246 | }, kwargs) 247 | 248 | return self._get("/stock/bbo", params=params) 249 | 250 | def forex_rates(self, **params): 251 | return self._get("/forex/rates", params=params) 252 | 253 | def forex_symbols(self, exchange): 254 | return self._get("/forex/symbol", params={ 255 | "exchange": exchange 256 | }) 257 | 258 | def forex_candles(self, symbol, resolution, _from, to, _format='json'): 259 | return self._get("/forex/candle", params={ 260 | "symbol": symbol, 261 | "resolution": resolution, 262 | "from": _from, 263 | "to": to, 264 | "format": _format 265 | }) 266 | 267 | def crypto_symbols(self, exchange): 268 | return self._get("/crypto/symbol", params={"exchange": exchange}) 269 | 270 | def crypto_candles(self, symbol, resolution, _from, to, _format='json'): 271 | return self._get("/crypto/candle", params={ 272 | "symbol": symbol, 273 | "resolution": resolution, 274 | "from": _from, 275 | "to": to, 276 | "format": _format 277 | }) 278 | 279 | def pattern_recognition(self, symbol, resolution): 280 | return self._get("/scan/pattern", params={ 281 | "symbol": symbol, 282 | "resolution": resolution 283 | }) 284 | 285 | def support_resistance(self, symbol, resolution): 286 | return self._get("/scan/support-resistance", params={ 287 | "symbol": symbol, 288 | "resolution": resolution 289 | }) 290 | 291 | def technical_indicator(self, symbol, resolution, _from, to, indicator, indicator_fields=None): 292 | indicator_fields = indicator_fields or {} 293 | params = self._merge_two_dicts({ 294 | "symbol": symbol, 295 | "resolution": resolution, 296 | "from": _from, 297 | "to": to, 298 | "indicator": indicator 299 | }, indicator_fields) 300 | 301 | return self._get("/indicator", params=params) 302 | 303 | def stock_splits(self, symbol, _from, to): 304 | return self._get("/stock/split", params={ 305 | "symbol": symbol, 306 | "from": _from, 307 | "to": to 308 | }) 309 | 310 | def general_news(self, category, min_id=0): 311 | return self._get("/news", params={ 312 | "category": category, 313 | "minId": min_id 314 | }) 315 | 316 | def company_news(self, symbol, _from, to): 317 | return self._get("/company-news", params={ 318 | "symbol": symbol, 319 | "from": _from, 320 | "to": to 321 | }) 322 | 323 | def news_sentiment(self, symbol): 324 | return self._get("/news-sentiment", params={ 325 | "symbol": symbol 326 | }) 327 | 328 | def ownership(self, symbol, limit=None): 329 | return self._get("/stock/ownership", params={ 330 | "symbol": symbol, 331 | "limit": limit 332 | }) 333 | 334 | def country(self): 335 | return self._get("/country") 336 | 337 | def economic_code(self): 338 | return self._get("/economic/code") 339 | 340 | def economic_data(self, code): 341 | return self._get("/economic", params={"code": code}) 342 | 343 | def calendar_economic(self, _from=None, to=None): 344 | return self._get("/calendar/economic", params={ 345 | "from": _from, 346 | "to": to 347 | }) 348 | 349 | def earnings_calendar(self, _from, to, symbol, international=False): 350 | return self._get("/calendar/earnings", params={ 351 | "from": _from, 352 | "to": to, 353 | "symbol": symbol, 354 | "international": international 355 | }) 356 | 357 | def ipo_calendar(self, _from, to): 358 | return self._get("/calendar/ipo", params={ 359 | "from": _from, 360 | "to": to 361 | }) 362 | 363 | def indices_const(self, **params): 364 | return self._get("/index/constituents", params=params) 365 | 366 | def indices_hist_const(self, **params): 367 | return self._get("/index/historical-constituents", params=params) 368 | 369 | def etfs_profile(self, symbol=None, isin=None): 370 | return self._get("/etf/profile", params={"symbol": symbol, "isin": isin}) 371 | 372 | def etfs_holdings(self, symbol=None, isin=None, skip=None, date=None): 373 | return self._get("/etf/holdings", params={"symbol": symbol, "isin": isin, "skip": skip, "date": date}) 374 | 375 | def etfs_sector_exp(self, symbol): 376 | return self._get("/etf/sector", params={"symbol": symbol}) 377 | 378 | def etfs_country_exp(self, symbol): 379 | return self._get("/etf/country", params={"symbol": symbol}) 380 | 381 | def international_filings(self, symbol="", country=""): 382 | return self._get("/stock/international-filings", params={"symbol": symbol, "country": country}) 383 | 384 | def sec_sentiment_analysis(self, access_number): 385 | return self._get("/stock/filings-sentiment", params={"accessNumber": access_number}) 386 | 387 | def sec_similarity_index(self, symbol="", cik="", freq="annual"): 388 | return self._get("/stock/similarity-index", params={"symbol": symbol, "cik": cik, "freq": freq}) 389 | 390 | def last_bid_ask(self, symbol): 391 | return self._get("/stock/bidask", params={"symbol": symbol}) 392 | 393 | def fda_calendar(self): 394 | return self._get("/fda-advisory-committee-calendar") 395 | 396 | def symbol_lookup(self, query): 397 | return self._get("/search", params={"q": query}) 398 | 399 | def stock_insider_transactions(self, symbol, _from=None, to=None): 400 | return self._get("/stock/insider-transactions", params={"symbol": symbol, "from": _from, "to": to}) 401 | 402 | def mutual_fund_profile(self, symbol=None, isin=None): 403 | return self._get("/mutual-fund/profile", params={"symbol": symbol, "isin": isin}) 404 | 405 | def mutual_fund_holdings(self, symbol=None, isin=None, skip=None): 406 | return self._get("/mutual-fund/holdings", params={"symbol": symbol, "isin": isin, "skip": skip}) 407 | 408 | def mutual_fund_sector_exp(self, symbol): 409 | return self._get("/mutual-fund/sector", params={"symbol": symbol}) 410 | 411 | def mutual_fund_country_exp(self, symbol): 412 | return self._get("/mutual-fund/country", params={"symbol": symbol}) 413 | 414 | def mutual_fund_eet(self, isin): 415 | return self._get("/mutual-fund/eet", params={"isin": isin}) 416 | 417 | def mutual_fund_eet_pai(self, isin): 418 | return self._get("/mutual-fund/eet-pai", params={"isin": isin}) 419 | 420 | def stock_revenue_breakdown(self, symbol, cik=""): 421 | return self._get("/stock/revenue-breakdown", params={"symbol": symbol, "cik": cik}) 422 | 423 | def stock_social_sentiment(self, symbol, _from=None, to=None): 424 | return self._get("/stock/social-sentiment", params={"symbol": symbol, "from": _from, "to": to}) 425 | 426 | def stock_investment_theme(self, theme): 427 | return self._get("/stock/investment-theme", params={"theme": theme}) 428 | 429 | def stock_supply_chain(self, symbol): 430 | return self._get("/stock/supply-chain", params={"symbol": symbol}) 431 | 432 | def company_esg_score(self, symbol): 433 | return self._get("/stock/esg", params={"symbol": symbol}) 434 | 435 | def company_historical_esg_score(self, symbol): 436 | return self._get("/stock/historical-esg", params={"symbol": symbol}) 437 | 438 | def historical_market_cap(self, symbol, _from=None, to=None): 439 | return self._get("/stock/historical-market-cap", params={"symbol": symbol, "from": _from, "to": to}) 440 | 441 | def company_earnings_quality_score(self, symbol, freq): 442 | return self._get("/stock/earnings-quality-score", params={"symbol": symbol, 'freq': freq}) 443 | 444 | def crypto_profile(self, symbol): 445 | return self._get("/crypto/profile", params={"symbol": symbol}) 446 | 447 | def stock_uspto_patent(self, symbol, _from=None, to=None): 448 | return self._get("/stock/uspto-patent", params={"symbol": symbol, "from": _from, "to": to}) 449 | 450 | def stock_visa_application(self, symbol, _from=None, to=None): 451 | return self._get("/stock/visa-application", params={"symbol": symbol, "from": _from, "to": to}) 452 | 453 | def stock_insider_sentiment(self, symbol, _from, to): 454 | return self._get("/stock/insider-sentiment", params={"symbol": symbol, "from": _from, "to": to}) 455 | 456 | def stock_lobbying(self, symbol, _from, to): 457 | return self._get("/stock/lobbying", params={"symbol": symbol, "from": _from, "to": to}) 458 | 459 | def bond_profile(self, **params): 460 | return self._get("/bond/profile", params=params) 461 | 462 | def bond_price(self, isin, _from, to): 463 | return self._get("/bond/price", params={"isin": isin, "from": _from, "to": to}) 464 | 465 | def stock_usa_spending(self, symbol, _from, to): 466 | return self._get("/stock/usa-spending", params={"symbol": symbol, "from": _from, "to": to}) 467 | 468 | def sector_metric(self, region): 469 | return self._get("/sector/metrics", params={"region": region}) 470 | 471 | def price_metrics(self, symbol, date=''): 472 | return self._get("/stock/price-metric", params={"symbol": symbol, "date": date}) 473 | 474 | def symbol_change(self, _from, to): 475 | return self._get("/ca/symbol-change", params={"from": _from, "to": to}) 476 | 477 | def isin_change(self, _from, to): 478 | return self._get("/ca/isin-change", params={"from": _from, "to": to}) 479 | 480 | def institutional_profile(self, cik=''): 481 | return self._get("/institutional/profile", params={"cik": cik}) 482 | 483 | def institutional_portfolio(self, cik, _from, to): 484 | return self._get("/institutional/portfolio", params={"cik": cik, "from": _from, "to": to}) 485 | 486 | def institutional_ownership(self, symbol, cusip, _from, to): 487 | return self._get("/institutional/ownership", params={"symbol": symbol, "cusip": cusip, "from": _from, "to": to}) 488 | 489 | def congressional_trading(self, symbol, _from, to): 490 | return self._get("/stock/congressional-trading", params={"symbol": symbol, "from": _from, "to": to}) 491 | 492 | def bond_tick(self, isin, date, limit, skip, exchange='trace', _format='json', **kwargs): 493 | params = self._merge_two_dicts({ 494 | "isin": isin, 495 | "date": date, 496 | "limit": limit, 497 | "skip": skip, 498 | "exchange": exchange, 499 | "format": _format 500 | }, kwargs) 501 | 502 | return self._get("/bond/tick", params=params) 503 | 504 | def bond_yield_curve(self, code): 505 | return self._get("/bond/yield-curve", params={'code': code}) 506 | 507 | def market_status(self, exchange): 508 | return self._get("/stock/market-status", params={'exchange': exchange}) 509 | 510 | def market_holiday(self, exchange): 511 | return self._get("/stock/market-holiday", params={'exchange': exchange}) 512 | 513 | def historical_employee_count(self, symbol, _from, to): 514 | return self._get("/stock/historical-employee-count", params={"symbol": symbol, "from": _from, "to": to}) 515 | 516 | def airline_price_index(self, airline, _from, to): 517 | return self._get("/airline/price-index", params={"airline": airline, "from": _from, "to": to}) 518 | 519 | def earnings_call_live(self, _from, to, symbol=""): 520 | return self._get("/stock/earnings-call-live", params={"symbol": symbol, "from": _from, "to": to}) 521 | 522 | def stock_presentation(self, symbol): 523 | return self._get("/stock/presentation", params={"symbol": symbol}) 524 | 525 | def stock_revenue_breakdown2(self, symbol): 526 | return self._get("/stock/revenue-breakdown2", params={"symbol": symbol}) 527 | -------------------------------------------------------------------------------- /finnhub/exceptions.py: -------------------------------------------------------------------------------- 1 | class FinnhubAPIException(Exception): 2 | def __init__(self, response): 3 | super(FinnhubAPIException, self).__init__() 4 | 5 | self.code = 0 6 | 7 | try: 8 | json_response = response.json() 9 | except ValueError: 10 | self.message = "JSON error message from Finnhub: {}".format(response.text) 11 | else: 12 | if "error" not in json_response: 13 | self.message = "Wrong json format from FinnhubAPI" 14 | else: 15 | self.message = json_response["error"] 16 | 17 | self.status_code = response.status_code 18 | self.response = response 19 | 20 | def __str__(self): 21 | return "FinnhubAPIException(status_code: {}): {}".format(self.status_code, self.message) 22 | 23 | 24 | class FinnhubRequestException(Exception): 25 | def __init__(self, message): 26 | super(FinnhubRequestException, self).__init__() 27 | self.message = message 28 | 29 | def __str__(self): 30 | return "FinnhubRequestException: {}".format(self.message) 31 | -------------------------------------------------------------------------------- /git_push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ 3 | # 4 | # Usage example: /bin/sh ./git_push.sh wing328 openapi-pestore-perl "minor update" "gitlab.com" 5 | 6 | git_user_id=$1 7 | git_repo_id=$2 8 | release_note=$3 9 | git_host=$4 10 | 11 | if [ "$git_host" = "" ]; then 12 | git_host="github.com" 13 | echo "[INFO] No command line input provided. Set \$git_host to $git_host" 14 | fi 15 | 16 | if [ "$git_user_id" = "" ]; then 17 | git_user_id="GIT_USER_ID" 18 | echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" 19 | fi 20 | 21 | if [ "$git_repo_id" = "" ]; then 22 | git_repo_id="GIT_REPO_ID" 23 | echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" 24 | fi 25 | 26 | if [ "$release_note" = "" ]; then 27 | release_note="Minor update" 28 | echo "[INFO] No command line input provided. Set \$release_note to $release_note" 29 | fi 30 | 31 | # Initialize the local directory as a Git repository 32 | git init 33 | 34 | # Adds the files in the local repository and stages them for commit. 35 | git add . 36 | 37 | # Commits the tracked changes and prepares them to be pushed to a remote repository. 38 | git commit -m "$release_note" 39 | 40 | # Sets the new remote 41 | git_remote=`git remote` 42 | if [ "$git_remote" = "" ]; then # git remote not defined 43 | 44 | if [ "$GIT_TOKEN" = "" ]; then 45 | echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." 46 | git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git 47 | else 48 | git remote add origin https://${git_user_id}:${GIT_TOKEN}@${git_host}/${git_user_id}/${git_repo_id}.git 49 | fi 50 | 51 | fi 52 | 53 | git pull origin master 54 | 55 | # Pushes (Forces) the changes in the local repository up to the remote repository 56 | echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git" 57 | git push origin master 2>&1 | grep -v 'To https' 58 | 59 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | rm -rf build && rm -rf dist 2 | python3 setup.py sdist bdist_wheel 3 | python3 -m twine upload dist/* --verbose 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests >= 2.22.0 2 | future; python_version<="2.7" 3 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length=99 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | from setuptools import setup, find_packages # noqa: H301 4 | 5 | NAME = "finnhub-python" 6 | VERSION = "2.4.23" 7 | REQUIRES = ["requests >= 2.22.0"] 8 | 9 | with open("README.md", "r") as fh: 10 | long_description = fh.read() 11 | 12 | setup( 13 | name=NAME, 14 | version=VERSION, 15 | description="Finnhub API", 16 | author="Finnhub", 17 | author_email="support@finnhub.io", 18 | url="https://finnhub.io/docs/api", 19 | keywords=["finnhub", "Finnhub API", "api"], 20 | install_requires=REQUIRES, 21 | packages=find_packages(exclude=["test", "tests"]), 22 | include_package_data=True, 23 | license="Apache-2.0", 24 | long_description=long_description, 25 | long_description_content_type="text/markdown" 26 | ) 27 | -------------------------------------------------------------------------------- /test-requirements.txt: -------------------------------------------------------------------------------- 1 | pytest~=4.6.7 # needed for python 2.7+3.4 2 | pytest-cov>=2.8.1 3 | pytest-randomly==1.2.3 # needed for python 2.7+3.4 4 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py27, py3 3 | 4 | [testenv] 5 | deps=-r{toxinidir}/requirements.txt 6 | -r{toxinidir}/test-requirements.txt 7 | 8 | commands= 9 | pytest --cov=finnhub 10 | --------------------------------------------------------------------------------