FinanceToolkit

JerBoumaMIT活跃维护

一套透明高效的 Python 金融分析工具包,可拉取市场与财报数据,计算基本面、因子和绩效指标,并支持 MCP 接入 Agent 工作流。

Transparent and Efficient Financial Analysis

v2.3.3发布于 2026-11-09 13:13 UTC5,515star +7 / 7 天648fork同步于 2026-11-10 17:36 UTC

怎么上手

由 README 提炼,执行前请确认
pip install financetoolkit -U
from financetoolkit import Toolkit
companies = Toolkit(tickers=['AAPL', 'MSFT'], api_key="FINANCIAL_MODELING_PREP_KEY")
硬件要求按 README 说明

README 未说明

下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

开源财务分析工具库,用透明公式统一计算 500+ 财务指标,避免不同数据源口径不一致

一套透明高效的 Python 金融分析工具包,可拉取市场与财报数据,计算基本面、因子和绩效指标,并支持 MCP 接入 Agent 工作流。

核心能力

  • 内置 500+ 财务方法,计算逻辑全部开源可查
  • 覆盖股票、期权、外汇、加密货币、ETF、指数等资产
  • 提供 Discovery 模块,按行业、市值等条件筛选公司
  • 支持获取 30+ 年年度与季度财务报表数据
  • FMP 取数失败时自动回退到 Yahoo Finance

容易踩的坑

需要自行到 FinancialModelingPrep 申请 API Key 才能取数;免费版每天限 250 次请求、仅 5 年数据且只支持美股;默认优先用 FMP,失败才回退 Yahoo Finance,可用 enforce_source 强制指定数据源

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v2.3.3
  1. v2.3.3FinanceToolkit v2.3.3最新正式版2026-11-09 · 2026-11-09 13:13 UTC

    A release on correctness, robustness and security, with bonds as a new asset class. Each ticker is now measured on its own trading days and calculated on unrounded data, so the Python package and the MCP server give the same figures. Controller methods work without arguments, bond calculators work on real bonds and market curves, the portfolio optimizers gain new objectives, constraints and a walk-forward backtest, and the MCP server, the cache, data retrieval and the release pipeline are hardened.

    Package

    Defaults from the data

    • Controller methods work without arguments: the valuation models default to each company's cost of equity (CAPM with its country's equity risk premium) or WACC, the dividend CAGR or the reinvestment growth, with the stable growth kept within 0% and 2.5%, all measured without look-ahead. Rates also take a list or a dict per ticker (#359).
    • With trailing set, the beta of the WACC and residual income covers the trailing periods, so quarterly defaults agree with annual ones (#359).
    • Defaults for get_tail_dependence_coefficient and get_covar (against the benchmark), get_style_analysis (Sharpe's asset classes as ETFs), get_commodity_forward_curve (all eight commodities), get_return_excluding (the largest holding), get_strategy_payoff (an at-the-money straddle) and the Discovery news searches (#359).

    Bonds and rates

    • get_treasury_securities lists every marketable US Treasury with price, yield and duration from FedInvest, without an API key. get_bond_universe lists about 9,000 US corporate bonds from bond ETF holdings, with the G-Spread over the Treasury par curve (#356).
    • The bond calculators (collect_bond_statistics, get_present_value, get_duration, get_yield_to_maturity, get_z_spread, get_key_rate_duration, get_taylor_price_change) run on real bonds: by default the benchmark Treasuries, or bonds chosen with bonds=, issuer=, etfs= and a maturity range. The rate calculators read a country's government bond curves on a day (#358).
    • get_implied_default_probability takes ratings= and uses the latest ICE BofA spread per rating (#358).
    • Removed: get_option_adjusted_spread, get_derivative_price and the parameters for typing in a bond's terms by hand (#358).

    Economic data without a FRED key

    • Initial jobless claims, retail sales, housing starts, real personal income, nonfarm payrolls and the HQM corporate bond curve and spread come straight from the Department of Labor, Census Bureau, BEA, BLS and Treasury when no FRED key is set, identical to FRED over their full history (#357).

    Portfolio optimization

    • get_maximum_diversification_weights, get_minimum_tracking_error_weights (with objective="information_ratio") and get_growth_optimal_weights (Kelly, with fraction=), and covariance="denoised" (López de Prado) in every optimizer and in get_risk_contributions, (#362).
    • Per-asset weight bounds (one number or a dict per ticker), sector_bounds= and country_bounds= from the company profiles, and net_exposure and gross_exposure for long-short portfolios in every optimizer; risk parity takes weight, sector and country bounds (constrained risk budgeting) and HRP weight bounds. Infeasible constraints are refused with the reason (#378).
    • get_hierarchical_equal_risk_contribution_weights (HERC, Raffinot), get_nested_clustered_optimization_weights (NCO, López de Prado), get_minimum_drawdown_weights (CDaR, maximum or average drawdown), get_maximum_omega_weights and get_maximum_cvar_ratio_weights (#385, merged through #386).
    • get_optimization_backtest: a walk-forward backtest that re-optimizes on each monthly, quarterly or yearly date from the trailing returns, without look-ahead, against equal weights and the benchmark, with turnover and transaction costs (#386, #391).
    • current_weights= with maximum_turnover= and transaction_cost= in the optimizers, and expected_returns= ('mean', 'exponential', 'capm' or Jorion
  2. v2.3.2FinanceToolkit v2.3.22026-11-06 · 2026-11-06 19:43 UTC
    查看更新说明

    A large release with new analytics throughout the package: factor analysis (predictive power) in every module, return decomposition, earnings surprises, ETF contributions, alternative betas, Morningstar's risk-adjusted return, drawdown tables, candlestick patterns and indicator summaries. New data comes from analyst targets, 13F ownership, FINRA short volume, historical index constituents, the NY Fed, the BIS and Damodaran. The MCP setup wizard now writes to the right places for Claude Desktop on Linux, Devin Desktop and VS Code.

    Package

    New analytics

    • Factor analysis (predictive power): get_factor_analysis in ratios, technicals, models, risk and performance tests any metric, a list of them or a collection (e.g. ratios="valuation") as a cross-sectional signal: information coefficient (mean, IR, t-stat), quantile returns, top-minus-bottom spread, turnover and rank autocorrelation, without look-ahead. performance.get_factor_analysis also takes your own signal as a DataFrame (#335).
    • Returns explained: models.get_return_decomposition splits a price return into EPS growth × P/E change, plus dividends (#320). performance.get_beta_implied_return gives the beta-implied return, the actual return and the residual per period (#344). risk.get_move_significance shows how unusual a move is: volatility multiple, percentile and "largest since" date (#324).
    • Earnings: get_earnings_surprise gives EPS and revenue surprises, SUE, and the share's reaction against the benchmark per announcement (#321).
    • ETFs: etf.get_contribution gives each holding's or sector's contribution to the return (also in index points), and etf.get_return_excluding the return without chosen holdings or sectors (#322). etf.get_active_share (#339).
    • Performance: alternative betas via get_beta(method=...): Blume, Vasicek, Dimson, Scholes-Williams, upside and downside (#325). get_kelly_criterion and get_return_statistics (profit factor, payoff ratio, expectancy, streaks, recovery factor) (#336). Morningstar Risk-Adjusted Return and Morningstar Risk, checked against Morningstar's April 2023 methodology (#339).
    • Risk: get_drawdown_series and get_drawdown_table (#323), with the gain needed to recover: get_drawdown_series(recovery=True) and a Recovery Needed column (#350). get_move_significance also gives the VaR Multiple, a move divided by its trailing VaR (#350).
    • Portfolio: covariance= on every optimiser: sample, Ledoit-Wolf, OAS, semicovariance or exponential. Matches scikit-learn and PyPortfolioOpt (#326).
    • Models: H-model, three-stage DDM (transition_periods=), justified P/E and P/B, and get_intrinsic_valuation(historical=True) (#341). get_quality_score, a Quality Minus Junk composite (#343).
    • Growth: compound=True with growth=True, lag=n gives the n-period CAGR of statements, estimates and every ratio (#329).
    • Technicals: get_candlestick_patterns, 15 patterns identical to TA-Lib, and get_signals (crossovers, RSI zones, band breaks, new highs/lows) (#338). get_indicator_summary gives an indicator's latest value, its percentile and rank in its own history, its extremes with dates, threshold crossings and the average returns after them (#348).

    New data

    • Analyst price targets, target history and monthly recommendations (#328). Institutional ownership from 13F filings (#333). FINRA daily short sale volume (#337).
    • Index constituents on a past date, plus the dated changes (#330).
    • NY Fed ACM Treasury term premium and Global Supply Chain Pressure Index (#331). BIS credit-to-GDP gap, debt service ratios and credit to GDP by sector (#332). Damodaran industry averages (#334).

    Fixes

    • A ticker without data no longer adds calendar days to the other tickers (#318).
    • Yahoo Finance prices are taken unrepaired when yfinance's repair extra (scikit-learn) is missing, instead of failing (#327).
    • A daily bar fetched before its session closed is asked for again after
  3. v2.3.1FinanceToolkit v2.3.12026-11-03 · 2026-11-03 11:03 UTC
    查看更新说明

    Some minor new functionalities that resolve edge cases and potential security flaws. Also introduced point-in-time mode as suggested by #298.

    Package

    New

    • Point-in-time mode (Toolkit(..., point_in_time=True), #301, closes #298).
      • Statements, ratios and models use each period's figures only from the day they were filed (FMP's accepted and filing dates, otherwise the reporting deadline).
      • end_date works as an "as of" date.
      • The statistics statement now holds the Filing Date and Fiscal Year.
    • Country equity risk premium in the Cost of Equity (#307).
      • CAPM, WACC, EVA, residual income and PVGO use the Damodaran premium of each company's country instead of the benchmark's historical excess return.
      • An explicit market_risk_premium still wins.
      • AAPL's 2024 WACC goes from 0.1947 to 0.0823.
    • Portfolio performance on the MCP server. The new tool portfolio_performance takes a portfolio as transactions, holdings, weights or a preset. It returns the overview, performance, positions, transactions and the money-weighted return.

    Improved

    • Toolkit core (#300, #305):
      • Quarterly data looks back far enough for the trailing year and its growth in the first periods.
      • Supplied statements are never downloaded again and detect their own date order.
      • Statement periods after end_date are left out.
      • Exchange rates older than a month aren't used.
      • Inputs are validated (tickers, benchmark, lag, dates).
    • Data layer (#304):
      • The price cache refetches when a dividend or split rescales the adjusted history.
      • Prices with a failed dividend or adjusted-close request aren't cached.
      • API keys are removed from logged errors.
      • Discovery queries are URL-encoded ("AT&T", "Aerospace & Defense").
      • Certificate errors fail at once instead of retrying for minutes.
      • On the Free plan, dividends before the latest five come from Yahoo Finance.
    • Portfolio (#311):
      • Transactions in several currencies are converted to one reporting currency at each day's rate; pence and pounds are unified.
      • Purchases come before sales within a day.
      • Decimal commas are read per column.
      • The stored data is not rounded.
    • Utilities and cache (#311):
      • Growth is NaN around a gap.
      • standardize covers the shown window.
      • Cache entries are evicted daily, and the coverage of a cached range never extends past today.
    • Heavy calculations are bounded (#306): option, bond, Monte Carlo and binomial models cap their sizes.
    • Edge-case fixes:
      • Brinson, Black-Litterman, cointegration, YTM, DCC-GARCH, Omega and the MWR (#306).
      • SAR, OBV, the McClellan Oscillator, Supertrend, support/resistance and the volume indicators per ticker over gaps (#309).
      • ETFs compared on common dates (#299).
      • Hurst lags (#297).
      • Brinson looks through funds (#296).
    • Speed (#310): the rolling CVaR, CDaR and Omega, the grouped Ulcer Index and period resampling are vectorised.
    • Clearer messages (#308): a missing key outside the statements says which data is missing, and inflation expectations name the countries they cover.
    • Fixes in this PR:
      • Discovery:
        • The screener sends the upper market cap bound.
        • UK home listings are recognised (SHEL.L instead of the NYSE ADR).
      • Performance: the whole-period Omega, Gain-to-Pain and Rachev ratios are no longer empty.
      • Company data:
        • Annual ESG scores take the year's latest disclosure.
        • Missing revenue segments are NaN, and names keep FMP's spelling ("iPhone").
        • A changed actual_dates applies to a cached earnings calendar.
        • Statements and analyst estimates are stored unrounded, so the rounding of a first call no longer sticks.
        • The statistics statement follows start_date and end_date.
      • Docstrings: the WLS and GLS examples use the estimated weights and the AR(1) Omega.
    • Docs and packaging (#302): docstring defaults match the co
  4. v2.3.0FinanceToolkit v2.3.02026-10-25 · 2026-10-25 19:41 UTC
    查看更新说明

    New release with some new modules, lots of verification checks and overall improvements. See the complete list below.

    Library

    New

    • toolkit.portfolio: optimal weights (minimum variance, maximum Sharpe, mean-variance, risk parity, HRP, inverse volatility, minimum CVaR, Black-Litterman), efficient frontier, risk contributions, stress tests, look-through exposure and Brinson-Fachler attribution. Portfolio takes weights, holdings or transactions and ships 13 presets (#281).
    • toolkit.etf: holdings, weightings, profile with premium/discount to NAV (stale_nav=True for a NAV that is not current), tracking, concentration, overlap, look-through valuation and liquidity (#288).
    • Models: peer comparison, Merton distance to default, synthetic credit rating, reverse DCF, Monte Carlo valuation and more (#282).
    • Options: put/call ratio, max pain, gamma exposure, implied move, model-free implied volatility and the volatility risk premium (#283).
    • Fixed income: zero-coupon curves, Nelson-Siegel-Svensson, yield curve PCA, Vasicek/CIR/Hull-White, callable bond OAS, implied default probabilities and Treasury auctions (#284).
    • Econometrics on any series (Econometrics(data=...)), Markov regime switching, structural breaks, time-varying beta, DCC-GARCH and pairs trading (#285).
    • Performance and technicals: style analysis, regional Fama-French factors, market breadth, seasonality, relative strength and index constituents (#287).

    Improved

    • Modules load statements and prices only when a calculation needs them (#290).
    • Every calculating method documents its formula with the defaults it uses, and every docstring example is regenerated live (#286).
    • Correctness, verified against the sources (#286): decimals everywhere, the traded close for market values, no look-ahead (figures apply from the fiscal period end), each ticker keeps its own history, quarterly ratios over a trailing year, continuous rates for options, the arch backcast for GARCH, and many method-level fixes.
    • show_columns selects numeric column labels such as years, thanks to @jackiectl2 (#292).

    Breaking

    • Toolkit.get_etf_holdings, get_etf_information, get_etf_sector_weightings and get_etf_country_weightings moved to toolkit.etf (get_holdings and so on).
    • ICE BofA option-adjusted spreads and the discovery quote changes are decimals.
    • A Toolkit whose only ticker is the benchmark raises a clear error; pass benchmark_ticker=None.

    MCP server

    • New portfolio and etf tools: 24 router tools.
    • Econometrics takes series= to analyse any indicator.
    • Descriptions follow the new methods, units and defaults; the bundle manifest is synced.

    Other

    • A weekly GitHub Actions run checks every keyless data source and opens an issue per broken source (#289).
  5. v2.2.3FinanceToolkit v2.2.32026-10-12 · 2026-10-12 07:30 UTC
    查看更新说明

    Mostly work for the MCP server to provide more reliable answers.

    MCP server

    • Answers stay readable: anything over 60,000 characters is cut to the most recent rows, with a note on how to narrow it. limit works as head/tail (5 first, -5 last) on every tool. Large outputs (simulations, binomial tree, ETF holdings) have compact defaults.
    • Better discovery: search_metrics returns the exact indicator and its tool and understands analyst wording ("how expensive is the stock"). The server sends usage instructions on connect. Every parameter has a real description, from the docstrings.
    • Notes explain the answer: tickers without data, ignored arguments, yearly-only data, sample yield curves, assumed bond inputs, where a series ends, fiscal-year mapping and currency conversion.
    • Inputs: show_columns matches any casing and countries accept short forms (USA, UK). Weights, yield curves, option strategy legs and lists can be passed. Transcripts come back in full per company and fiscal period. Option chains say which expiry they show.
    • Hosted server: at most 4 Economics and 64 Toolkit instances are kept, and one Global Macro Database copy is shared per process (memory stays flat across date ranges).
    • Tools: search_instruments is removed (Finance Database covers it), search_categories is renamed search_metric_categories, and EGARCH is no longer offered (~45s per fit).

    Package

    • Stale FMP data fixed: Commitment of Traders, sector and industry history and 8-K filings now request a date range.
    • Stock screener: market caps are in USD, primary_only keeps the home listing, and it returns stocks only unless is_etf=True.
    • Symbols: ISIN/CUSIP/CIK search uses its own parameters, and currency and crypto pairs are accepted in either notation (EURUSD or EURUSD=X).
    • Economics: quarterly and monthly rates use sources with that frequency, calendar event matching ignores spaces and hyphens, and Current Policies climate scenarios work.
    • Fixes and additions:
      • Daily GARCH forecasts are dated by business day.
      • Gainers and losers are sorted by change and ETF weights largest first.
      • Gross margin is empty where cost of goods sold is zero.
      • The Sharpe ratio takes annualize.
      • Option chains take strike_price_range.

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    FinanceToolkit

    GitHub Sponsors Buy Me a Coffee LinkedIn MCP Server Download MCP Bundle Smithery Glama Documentation Supported Python Versions PYPI Version PYPI Downloads

    While browsing a variety of websites, I repeatedly observed significant fluctuations in the same financial metric among different sources. Similarly, the reported financial statements often didn't line up, and there was limited information on the methodology used to calculate each metric.

    For example, Microsoft's Price-to-Earnings (PE) ratio on the 6th of May, 2023 is reported to be 28.93 (Stockopedia), 32.05 (Morningstar), 32.66 (Macrotrends), 33.09 (Finance Charts), 33.66 (Y Charts), 33.67 (Wall Street Journal), 33.80 (Yahoo Finance) and 34.4 (Companies Market Cap). All of these calculations are correct, however the method of calculation varies leading to different results. Therefore, collecting data from multiple sources can lead to wrong interpretation of the results given that one source could apply a different definition than another. And that is, if that definition is even available as often the underlying methods are hidden behind a paid subscription.

    This is why I designed the FinanceToolkit, this is an open-source toolkit in which all relevant financial methods (500+) are written down in the most simplistic way allowing for complete transparency of the method of calculation (proof). This enables you to avoid dependence on metrics from other providers that do not provide their methods. With a large selection of financial statements in hand, it facilitates streamlined calculations, promoting the adoption of a consistent and universally understood methods and formulas.

    Beyond Equities, it supports Options, Currencies, Cryptocurrencies, ETFs, Mutual Funds, Indices, Money Markets, Commodities, Key Economic Indicators and more, allowing you to obtain historical data as well as important performance and risk measurements such as the Sharpe Ratio and Value at Risk.

    Complementing this is the Finance Database 🌎, a database featuring 300.000+ symbols containing Equities, ETFs, Funds, Indices, Currencies, Cryptocurrencies and Money Markets. By utilising both, it is possible to do a fully-fledged competitive analysis with the tickers found from the FinanceDatabase inputted into the FinanceToolkit.


    🔌 The Finance Toolkit is also available as an MCP Server

    Query 500+ methods from Claude, Copilot, Cursor, Windsurf or any MCP-compatible client without writing code.

    • Hosted: connect to https://financetoolkit.jeroenbouma.com/mcp — OAuth handles the rest on first use.
    • Local: uvx --from "financetoolkit[mcp]" financetoolkit-mcp-setup — sets up your client config and API key automatically. See MCP Server Documentation for manual setup.

    Also on Smithery, Glama, MCP Servers and more.


    Table of Contents

    1. Installation
    2. Functionality
    3. MCP Server
    4. Questions & Answers
    5. Contributing
    6. Mentions
    7. Contact

    Installation

    Before installation, consider starring the project on GitHub which helps others find the project as well.

    To install the Finance Toolkit it simply requires the following:

    pip install financetoolkit -U
    

    Then within Python use:

    from financetoolkit import Toolkit
    
    companies = Toolkit(
        tickers=['AAPL', 'MSFT'],
        api_key="FINANCIAL_MODELING_PREP_KEY",  # replace with your actual API key
    )
    

    To be able to get started, you need to obtain an API Key from FinancialModelingPrep. This is used to gain access to 30+ years of financial statement both annually and quarterly. Note that the Free plan is limited to 250 requests each day, 5 years of data and only features companies listed on US exchanges.


    Obtain an API Key from FinancialModelingPrep here.


    Through the link you are able to subscribe for the free plan and also premium plans at a 15% discount. This is an affiliate link and thus supports the project at the same time. I have chosen FinancialModelingPrep as a source as I find it to be the most transparent, reliable and at an affordable price. I have yet to find a platform offering such low prices for the amount of data offered. When you notice that the data is inaccurate or have any other issue related to the data, note that I simply provide the means to access this data and I am not responsible for the accuracy of the data itself. For this, use their contact form or provide the data yourself.

    By default, the Finance Toolkit prioritizes Financial Modeling Prep for data retrieval. If data acquisition from Financial Modeling Prep is unsuccessful (e.g., due to plan restrictions or API key issues), the toolkit automatically switches to Yahoo Finance as a secondary source. To disable this fallback behavior and exclusively use Financial Modeling Prep, set enforce_source="FinancialModelingPrep" during Toolkit initialization. This configuration ensures that an error is raised if Financial Modeling Prep data cannot be accessed. Alternatively, you can set enforce_source="YahooFinance" to exclusively use Yahoo Finance as the data source.

    The same enforce_source argument is also accepted per call on get_historical_data, get_treasury_data and the four statement functions (get_balance_sheet_statement, get_income_statement, get_cash_flow_statement and get_statistics_statement), where it overrides whatever the Toolkit was initialised with.

    Functionality

    This section is an introduction to the Finance Toolkit. The documentation contains many more examples: every module page opens with a Getting Started section, from the basics to creating custom ratios and working with your own datasets.


    Find the Documentation, including the Getting Started guides, here.


    The sections below follow one analysis of the semiconductor sector from start to finish, where each step answers the question the previous one raises: which companies make up the sector, how their shares did, what drives their profits, how much risk came with the returns, what the option market expects next, how the economy shaped all of it, whether a fund is the better way in and how the sector fits into a diversified portfolio. Every module of the Finance Toolkit appears once, but each holds far more than shown here: 500+ methods in total, all described with examples in the documentation.

    Discovering the Sector

    An analysis starts with a set of companies. The Discovery module finds them without needing any tickers yet, through stock screeners, sector performance, news and lists of companies, ETFs, indices, currencies, cryptocurrencies and commodities.

    The screener below looks for semiconductor companies on NASDAQ that are worth more than $100 billion:

    from financetoolkit import Discovery
    
    # Initialize the standalone Discovery module
    discovery = Discovery(api_key="FINANCIAL_MODELING_PREP_KEY")
    
    # Find US semiconductor companies worth more than $100 billion
    semiconductors = discovery.get_stock_screener(
        industry="Semiconductors",
        country="US",
        exchange="NASDAQ",
        market_cap_higher=100_000_000_000,
        is_etf=False,
    )
    
    # Show the five largest
    semiconductors[["Name", "Market Cap", "Beta", "Price", "Dividend"]].head()
    

    For example, the five largest companies the screener returns are shown below.

    SymbolNameMarket CapBetaPriceDividend
    NVDANVIDIA Corporation50841360000002.216210.960.28
    AVGOBroadcom Inc.15355812549731.476321.682.6
    MUMicron Technology, Inc.9928776210002.226877.550.565
    AMDAdvanced Micro Devices, Inc.8436467769552.454516.790
    INTCIntel Corp.4596797135842.2386.960

    And below all of them are ranked by market cap.

    Following the Market

    The rest of this walkthrough follows three of them: Nvidia, AMD and Intel. They are loaded into the Toolkit in one line, and the S&P 500 comes along as the benchmark:

    from financetoolkit import Toolkit
    
    # Initialize the Toolkit for Nvidia, AMD and Intel from 2018 to 2025
    companies = Toolkit(
        ["NVDA", "AMD", "INTC"],
        api_key="FINANCIAL_MODELING_PREP_KEY",
        start_date="2017-12-31",
        end_date="2025-12-31",
    )
    

    Historical data comes on a daily, weekly, monthly, quarterly or yearly basis, with the return and cumulative return of each period, and so do the income statement, balance sheet and cash flow statement on an annual or quarterly basis. How far a share has travelled is one thing; whether the rally was stretched is another. The technicals module answers that with 50+ indicators, such as the Relative Strength Index (RSI), which moves between 0 and 100 and is commonly read as overbought above 70:

    # Obtain weekly market data for all tickers and the benchmark
    historical_data = companies.get_historical_data(period="weekly")
    
    # The 14-week Relative Strength Index
    relative_strength_index = companies.technicals.get_relative_strength_index(period="weekly", window=14)
    
    # Show the highest RSI of each year
    relative_strength_index.groupby(relative_strength_index.index.start_time.year).max()
    

    For example, the highest weekly RSI of each year is shown below.

    DateNVDAAMDINTCBenchmark
    201866.108790.971966.736366.0498
    201973.815681.244669.822575.9305
    202085.233782.121578.482780.2378
    202185.159382.098371.586274.4751
    202258.434358.942661.280659.9225
    202387.512977.50676.233271.4291
    202491.070282.140367.694980.0566
    202573.351482.528179.742971.6939

    And below the cumulative returns of all three are plotted against the S&P 500, with the RSI underneath.

    Zooming in on Competitors

    Nvidia's shares outran the other two by far, which raises the question whether its business did as well. From the financial statements the Toolkit calculates 80+ ratios in five categories: efficiency, liquidity, profitability, solvency and valuation. Each ratio has its own function, and a collect_ function returns a whole category at once:

    # Collect all Profitability Ratios for all tickers
    profitability_ratios = companies.ratios.collect_profitability_ratios()
    
    # Show the first ratios for Nvidia
    profitability_ratios.loc["NVDA"].head()
    

    For example, some of Nvidia's profitability ratios are shown below.

    201720182019202020212022202320242025
    Gross Margin0.59930.61210.61990.62340.64930.56930.72720.74990.7107
    Operating Margin0.33050.32470.26070.27180.37310.15660.54120.62420.6038
    Net Profit Margin0.31370.35340.25610.25980.36230.16190.48850.55850.556
    EBITDA Margin0.35090.3470.29560.33760.41670.21380.5660.63850.617
    Free Cash Flow Margin0.29950.26830.39130.28150.30210.14120.44350.46630.4477

    And below a few of them are shown with their latest value and their course over the years.

    A high return on equity can come from margins, from turnover or from debt. Models combine the ratios to tell these apart: the Extended DuPont Analysis splits the return on equity into five components that multiply into it: interest burden, tax burden, operating margin, asset turnover and equity multiplier.

    # Get the Extended DuPont Analysis for all tickers
    extended_dupont_analysis = companies.models.get_extended_dupont_analysis()
    
    # Show the results for Nvidia
    extended_dupont_analysis.loc["NVDA"]
    

    For example, the components for Nvidia are shown below.

    201720182019202020212022202320242025
    Interest Burden Ratio0.99561.02421.04360.97290.990.98981.02571.03161.0848
    Tax Burden Ratio0.95341.06290.94140.98250.9811.04470.880.86740.8488
    Operating Profit Margin0.33050.32470.26070.27180.37310.15660.54120.62420.6038
    Asset Turnover0.92150.95510.71340.72330.73760.63191.13971.47181.3564
    Equity Multiplier1.59311.45921.42051.58461.67751.75251.64281.44991.3456
    Return on Equity0.46050.49260.25950.29780.44830.17930.91461.19181.0149

    And below each component is shown for every fiscal year, with the latest value on top, multiplying into the return on equity.

    Other models include the Weighted Average Cost of Capital, Altman Z-Score, Piotroski F-Score and Intrinsic Valuation. Almost every function also accepts growth=True for the growth from one period to the next, trailing=4 for trailing twelve-month figures and standardize=True for Z-Scores.

    Weighing Risk and Return

    Strong businesses do not make for smooth shares. The market data feeds the performance and risk modules, which calculate their metrics for any period, from intraday to yearly:

    # The annualized Sharpe Ratio for each year
    sharpe_ratio = companies.performance.get_sharpe_ratio(period="yearly", annualize=True)
    
    # The deepest fall within each year
    maximum_drawdown = companies.risk.get_maximum_drawdown(period="yearly", within_period=True)
    
    # Show the Sharpe Ratios
    sharpe_ratio
    

    For example, the yearly Sharpe Ratios are shown below.

    DateNVDAAMDINTC
    2018-0.6131.10090.161
    20191.54581.91431.048
    20201.6561.419-0.0445
    20212.00031.23660.2976
    2022-0.8393-1.0532-1.5306
    20232.69861.91951.8358
    20242.0851-0.2615-1.5749
    20250.83251.17531.2061

    And below both are plotted for each year, the maximum drawdown together with the S&P 500.

    Together the two modules cover 70+ metrics, such as Value at Risk, GARCH, Jensen's Alpha, the Capital Asset Pricing Model and the Fama-French factors. Most of them also accept rolling=<n> for a value that moves through time.

    What the Option Market Expects

    The past shows how much risk came with the returns; the option market puts a price on the risk ahead. The options module prices options with Black-Scholes, the Binomial Model and others, calculates the Greeks up to the third order and reads the live option chains: the put-call ratio, max pain, dealer gamma exposure, the volatility skew and term structure and the implied move. As the chains are those of today, the Toolkit below runs up to today, and the numbers are those of the day this README was last updated:

    # Initialize the Toolkit up to today, as the option chains are live
    companies_today = Toolkit(["NVDA", "AMD", "INTC"], api_key="FINANCIAL_MODELING_PREP_KEY")
    
    # The volatility the options imply for the next 30 days against that of the past 30 days
    companies_today.options.get_volatility_risk_premium(days=30)
    

    The implied volatility is model-free, read with the method behind the VIX from all out-of-the-money options around the horizon, and the realized volatility is that of the daily returns over the same number of days. For example, both are shown below for each company.

    Implied VolatilityRealized VolatilityVolatility Risk PremiumVariance Risk PremiumImplied to Realized Ratio
    NVDA0.48450.27950.20490.15661.7331
    AMD0.6570.4980.1590.18361.3192
    INTC0.69910.51960.17950.21881.3456

    Options usually price more risk than follows, as their sellers want to be paid for taking it on, and here they priced far more turbulence for the coming month than the past month delivered: Nvidia's options implied 1.7 times the volatility its shares showed. And below the implied and realized volatility of each company are plotted next to each other.

    The Economic Environment

    All three are listed in the United States and valued on earnings that lie years ahead, which makes US inflation and interest rates the backdrop to their share prices. In 2022, the year the maximum drawdown above shows each of them falling by more than half, inflation reached 9% and the Federal Reserve raised its policy rate from 0.12% to 4.38%.

    The economics module covers 60+ countries with 50+ indicators, from GDP and unemployment to money supply and interest rates, and the fixed income module adds bond yields, yield curves, central bank rates and calculations on individual bonds. Both are reached through the same Toolkit instance, or on their own with from financetoolkit import Economics, FixedIncome:

    # Inflation on the same month a year earlier and the Federal Reserve's policy rate
    inflation_rate = companies.economics.get_inflation_rate("United States", period="monthly")
    policy_rate = companies.economics.get_central_bank_policy_rate("United States", period="monthly")
    
    # The daily U.S. Treasury par yield curve
    treasury_rates = companies.fixedincome.get_treasury_rates()
    
    # Show the curve on the last trading day of each year
    treasury_rates.groupby(treasury_rates.index.year).last()
    

    For example, the yield curve at the end of each year is shown below.

    Date1 Month2 Month3 Month6 Month1 Year2 Year3 Year5 Year7 Year10 Year20 Year30 Year
    20180.02440.02450.02450.02560.02630.02480.02460.02510.02590.02690.02870.0302
    20190.01480.01510.01550.0160.01590.01580.01620.01690.01830.01920.02250.0239
    20200.00080.00080.00090.00090.0010.00130.00170.00360.00650.00930.01450.0165
    20210.00060.00050.00060.00190.00390.00730.00970.01260.01440.01520.01940.019
    20220.04120.04410.04420.04760.04730.04410.04220.03990.03960.03880.04140.0397
    20230.0560.05590.0540.05260.04790.04230.04010.03840.03880.03880.0420.0403
    20240.0440.04390.04370.04240.04160.04250.04270.04380.04480.04580.04860.0478
    20250.03740.03670.03670.03590.03480.03470.03550.03730.03940.04180.04790.0484

    And below the yield curve at the end of each year is plotted. It went from almost zero at the short end in 2021 to above 4% across all maturities a year later, and when short-term yields lie above long-term ones, as at the end of 2022 and 2023, the curve is inverted.

    Economic Relations

    Rates rose and the shares fell, but a 10-year Treasury yield is made of two parts: the real yield, the return investors demand on top of inflation, and the inflation they expect over those ten years. The econometrics module tells such drivers apart with regressions, tests and forecasts built on statsmodels and linearmodels (pip install financetoolkit[econometrics]). Through the Toolkit it analyzes the returns of its tickers, and on its own, through Econometrics(data=...), any data at all, here the monthly returns of the three next to the monthly change in the US 10-year real yield and in 10-year inflation expectations:

    import pandas as pd
    
    from financetoolkit import Econometrics
    
    # The US 10-year real yield and inflation expectations at the end of each month
    real_yield = companies.economics.get_real_yield_curve("United States", period="monthly")
    inflation_expectations = companies.economics.get_breakeven_inflation_expectations(
        "United States", period="monthly"
    )
    
    # The monthly change in both next to the monthly returns
    monthly_returns = companies.get_historical_data(period="monthly")["Return"][["NVDA", "AMD", "INTC"]]
    monthly_returns["Real Yield"] = real_yield[("United States", "10Y")].diff()
    monthly_returns["Inflation Expectations"] = inflation_expectations[("United States", "10Y")].diff()
    
    # The data are changes already
    econometrics = Econometrics(data=monthly_returns, changes=None)
    
    # Regress the return of each company on the change in the real yield and inflation expectations
    regressions = pd.concat(
        {
            ticker: econometrics.get_ols(
                dependent_ticker=ticker, independent_tickers=["Real Yield", "Inflation Expectations"]
            )
            for ticker in ["NVDA", "AMD", "INTC"]
        }
    )
    
    # Show the results for Nvidia
    regressions.loc["NVDA"]
    

    For example, the coefficients for Nvidia are shown below.

    CoefficientStd. Errort-StatisticP-Value
    Intercept0.0490.01293.80280.0003
    Real Yield-22.81325.6358-4.04790.0001
    Inflation Expectations18.13299.10291.9920.0493

    And below each coefficient is shown with its 95% confidence interval. A rise of 0.1 percentage point in the real yield went with a monthly return about 2.3% lower for Nvidia, 3.4% for AMD and 1.9% for Intel, as a higher real yield discounts their distant earnings more heavily. Inflation expectations matter far less: only for Nvidia does their coefficient come close to significance.

    The module also covers unit root and cointegration tests, Granger causality, panel data, causal inference, ARIMA, VAR and VECM forecasts, regime switching, a time-varying beta and pairs trading.

    Comparing the Sector's ETFs

    Rather than picking three companies, a fund holds the whole industry. The ETF module analyzes the holdings, sector and country weightings, tracking, concentration, overlap, valuation and liquidity of any fund. Below it compares six semiconductor funds: three focused on the United States (SOXX, XSD and PSI), one global fund (SMH) and two that hold a single country, China (SMHC) and South Korea (KCHP):

    # Initialize the Toolkit for six semiconductor funds
    funds = Toolkit(
        ["SOXX", "XSD", "PSI", "SMH", "SMHC", "KCHP"],
        api_key="FINANCIAL_MODELING_PREP_KEY",
        start_date="2017-12-31",
        end_date="2025-12-31",
    )
    
    # Where each fund invests, how concentrated it is and how much the funds hold of the same
    country_weightings = funds.etf.get_country_weightings()
    concentration = funds.etf.get_concentration()
    overlap = funds.etf.get_overlap()
    
    # Show the overlap between every pair of funds
    overlap.round(2)
    

    For example, the overlap between every pair of funds is shown below: the share of the two portfolios that is the same. Holdings are those of today, as funds publish their current holdings only.

    SOXXXSDPSISMHSMHCKCHP
    SOXX10.380.460.700
    XSD0.3810.340.2800
    PSI0.460.3410.3800
    SMH0.70.280.38100
    SMHC00001.080
    KCHP000001

    The three US funds and SMH largely hold the same companies, with SOXX and SMH sharing 70% of their portfolios. SMH holds the most outside the United States, 9% in Taiwan and 6% in the Netherlands. The China and Korea funds share nothing with any other fund, which is what diversification within one sector looks like. Below, the country weights of each fund are plotted next to the overlap.

    Building a Diversified Portfolio

    A fund spreads the risk over the sector, but the sector still moves as one. The portfolio module builds portfolios from the tickers of any Toolkit: minimum variance, maximum Sharpe ratio, mean-variance, risk parity, Hierarchical Risk Parity, minimum CVaR, Black-Litterman, maximum diversification, minimum tracking error and growth optimal (Kelly) weights, the efficient frontier, risk contributions, stress tests and attribution. Below the semiconductor fund is combined with health care (XLV), energy (XLE), long-term Treasuries (TLT) and gold (GLD):

    # Initialize the Toolkit for funds across sectors and asset classes from 2021 to 2025
    assets = Toolkit(
        ["SMH", "XLV", "XLE", "TLT", "GLD"],
        api_key="FINANCIAL_MODELING_PREP_KEY",
        start_date="2021-01-01",
        end_date="2025-12-31",
    )
    
    # The efficient frontier and the maximum Sharpe ratio portfolio, with at most 40% per asset
    efficient_frontier = assets.portfolio.get_efficient_frontier(points=25, maximum_weight=0.4)
    maximum_sharpe = assets.portfolio.get_maximum_sharpe_weights(maximum_weight=0.4)
    
    # The portfolio in which every asset contributes the same share of the risk
    risk_parity = assets.portfolio.get_risk_parity_weights()
    
    # Show the risk parity portfolio
    risk_parity
    

    For example, the risk parity portfolio is shown below. Returns and volatilities are annualized and the risk contribution is each asset's share of the portfolio's volatility.

    WeightExpected ReturnVolatilitySharpe RatioRisk Contribution
    SMH0.10080.30670.35080.77820.2
    XLV0.23580.09010.14490.38890.2
    XLE0.14810.24630.26720.79540.2
    TLT0.275-0.07480.1606-0.67560.2
    GLD0.24030.16810.15620.86030.2
    Portfolio10.10840.10850.68881

    And below the efficient frontier is plotted with both portfolios and each asset on its own, next to the weights of both portfolios.

    Following the Portfolio

    Optimal weights on paper still have to be held. The Portfolio class follows a portfolio over time, given as weights, as the shares held, as your own transactions or as one of thirteen classic portfolios such as the 60/40 and the All Weather portfolio. Below the risk parity weights are invested at the start of 2021, brought back to their weights every year and followed up to today:

    from financetoolkit import Portfolio
    
    # Invest the risk parity weights and rebalance every year
    portfolio = Portfolio(
        weights=risk_parity,
        start_date="2021-01-01",
        rebalancing="yearly",
        api_key="FINANCIAL_MODELING_PREP_KEY",
    )
    
    # Get an overview of the positions against the benchmark
    overview = portfolio.get_portfolio_overview()
    
    # Show the main figures
    overview[["Weight", "Return", "Benchmark Return", "Volatility", "Alpha", "Beta"]]
    

    For example, the main figures of each position are shown below.

    IdentifierWeightReturnBenchmark ReturnVolatilityAlphaBeta
    GLD0.19690.93990.8490.28450.09090.8392
    SMH0.13072.06690.52360.40011.54332.4046
    TLT0.2273-0.20380.74570.096-0.94940.2198
    XLE0.20341.54580.22360.22121.3222-0.4119
    XLV0.24180.55020.79950.1632-0.24930.256
    Portfolio10.97031.11430.1047-0.1440.5075

    And below the return of each position is plotted against the return of the benchmark over the same period.

    With portfolio.toolkit the portfolio, the time-weighted sum of all positions, is loaded into the Toolkit, so every metric above can be calculated for it as well.

    MCP Server

    The Finance Toolkit MCP Server exposes 500+ financial methods directly to any AI assistant that supports the Model Context Protocol (MCP). Ask questions in plain English — the AI fetches live financial data on your behalf, backed by the transparent, open-source calculation methods of the Finance Toolkit.

    See an example of the Finance Toolkit MCP server in action in Claude Desktop below:

    https://github.com/user-attachments/assets/96ad5288-d83d-4497-a345-1841c48c29d5

    Remote server

    Connect directly to the hosted server at https://financetoolkit.jeroenbouma.com/mcp. Nothing needs to be installed locally. On first connection your client opens an OAuth consent page asking for your FMP API key; enter it once and the server handles authentication from there.

    ClientSteps
    Claude DesktopCustomize → Connectors → Add custom connector → paste the URL
    Claude.aiCustomize → Connectors → Add custom connector → paste the URL
    Claude Codeclaude mcp add --transport http finance-toolkit https://financetoolkit.jeroenbouma.com/mcp
    VS CodeCommand Palette → MCP: Add Server → HTTP → paste the URL
    CursorSettings → Features → MCP Servers → Add new → http → paste the URL
    WindsurfSettings → MCP Servers → Add Server → Remote/HTTP → paste the URL

    Local installation

    Run the setup wizard — it locates your client's config file and writes the MCP entry automatically, including the API key:

    uvx --from "financetoolkit[mcp]" financetoolkit-mcp-setup
    

    For manual config, add the following to your client's MCP config file (e.g. claude_desktop_config.json, .cursor/mcp.json, .vscode/mcp.json):

    {
      "mcpServers": {
        "finance-toolkit": {
          "command": "uvx",
          "args": ["--from", "financetoolkit[mcp]", "financetoolkit-mcp"],
          "env": { "FINANCIAL_MODELING_PREP_API_KEY": "YOUR_API_KEY_HERE" }
        }
      }
    }
    

    Alternatively, download the Finance Toolkit MCPB bundle and open it with Claude Desktop. An installation dialog will prompt for your FMP API key.

    Questions & Answers

    This section includes frequently asked questions and is meant to clear up confusion about certain results and/or deviations from other sources. If you have any questions that are not answered here, feel free to reach out to me via the contact details below.

    How do you deal with companies that have different fiscal years?

    For any financial statement, I make sure to line it up with the corresponding calendar period. For example, Apple's Q4 2023 relates to July to September of 2023. This corresponds to the calendar period Q3 which is why I normalize Apple's numbers to Q3 2023 instead. This is done to allow for comparison between companies that have different fiscal years.

    Why do the numbers in the financial statements sometimes deviate from the data from FinancialModelingPrep?

    When looking at a company such as Hyundai Motor Company (ticker: 005380.KS), you will notice that the financial statements are reported in KRW (South Korean won). As this specific ticker is listed on the Korean Exchange, the historical market data will also be reported in KRW. However, if you use the ticker HYMTF, which is listed on the American OTC market, the historical market data will be reported in USD. To deal with this discrepancy, the end of year or end of quarter exchange rate is retrieved which is used to convert the financial statements to USD. This is done to prevent ratio calculations such as the Free Cash Flow Yield (which is based on the market capitalization) or Price Earnings Ratio (which is based on the stock price) from being incorrect. This can be disabled by setting convert_currency=False in the Toolkit initialization. It is recommended to always use the ticker that is listed on the exchange where the company is based.

    How can I get TTM (Trailing Twelve Months) and Growth metrics?

    Most functions will have the option to define the trailing parameter. This lets you define the number of periods that you want to use to calculate the trailing metrics. For example, if you want to calculate the trailing 12-month (TTM) Price-to-Earnings Ratio, you can set trailing=4 when you have set quarterly=True in the Toolkit initialization. The same goes for growth metrics which can be calculated by setting growth=True. This will calculate the growth for each period based on the previous period. This also includes a lag parameter in which you can define lagged growth. Furthermore, you can also combine the trailing and growth parameters to get trailing growth. For example, set trailing=4 and growth=True for the Price-to-Earnings Ratio which will then calculate the TTM growth.

    Does the Finance Toolkit retrieve the same data every time I run it?

    No. Any data that comes from an external source (financial statements, historical prices, economic indicators, yield curves, news and so on) is cached automatically in a local SQLite database and reused on the next run, in the Toolkit as well as in the Economics, Fixed Income, Discovery and Portfolio modules. Anything the Finance Toolkit calculates itself, such as ratios, models and risk metrics, is never cached: it is always derived from that data on demand, so it reflects the latest version of the Finance Toolkit.

    Cached data does not go stale. Each dataset is retrieved again once it may have changed: prices and financial statements after a day (prices only for the last week, since older bars no longer change), quotes after a minute, company profiles after a month and economic releases according to how often they are published. An answer that a source has no data, such as the ETF holdings of a company, is cached as well, while a failed request, such as a rate limit, is not.

    The cache keeps track of what it already holds per ticker and per date range, which means changing a parameter does not throw the rest away:

    • Repeating the same request retrieves nothing at all.
    • Widening the period only retrieves the years that were missing.
    • Adding a ticker only retrieves that one ticker.

    The database lives in your user configuration directory, which is the same one the MCP server uses, so both share a single cache. You can choose where it is stored, or switch caching off:

    from financetoolkit import Economics, Toolkit
    
    # Store the cache in a specific folder
    toolkit = Toolkit(["AAPL", "MSFT"], use_cached_data="datasets")
    
    # Retrieve everything every time
    toolkit = Toolkit(["AAPL", "MSFT"], use_cached_data=False)
    economics = Economics(use_cached_data=False)
    

    Setting the FINANCE_TOOLKIT_CACHE_ENABLED environment variable to 0 switches caching off by default everywhere, which suits environments where nothing should be written to disk, such as a continuous integration job. FINANCE_TOOLKIT_CACHE_DB moves the shared database to another file.

    To see what is currently stored, use toolkit.get_cache_contents(). It reports the entries grouped by source and dataset:

    sourcedatasetentitiesentriesoldest_writenewest_write
    FinancialModelingPrephistorical222025-01-14 09:12:032025-01-14 09:12:05
    FinancialModelingPrepstatements222025-01-14 09:12:012025-01-14 09:12:02

    The Finance Toolkit never clears the cache on its own, not even when its own internal structure changes. Removing data is always something you ask for explicitly with toolkit.clear_cache(), and it can be narrowed instead of wholesale:

    # Remove only the price history of a single ticker
    toolkit.clear_cache(source="FinancialModelingPrep", ticker="AAPL")
    
    # Remove everything retrieved from the OECD
    toolkit.clear_cache(source="OECD")
    
    # Remove the entire cache, which has to be confirmed
    toolkit.clear_cache(confirm=True)
    

    The source names match the ones used by the enforce_source parameter, so "FinancialModelingPrep" and "YahooFinance" mean the same thing in both places.

    What is the "Benchmark" that is automatically obtained when acquiring historical data?

    This is related to the benchmark_ticker parameter which is set to "SPY" (S&P 500) by default. This is important when calculating performance metrics such as the Sharpe Ratio or Treynor Ratio that require a market return. This can be disabled by setting benchmark_ticker=None in the Toolkit initialization.

    Data collection seems to be slow, what could be the issue?

    Generally, it should take less than 15 seconds to retrieve the historical data of 100 tickers. If it takes much longer, this could be due to reaching the API limit (the Starter plan has 250 requests per minute), due to a slow internet connection or due to unoptimized code. The Finance Toolkit collects data with a bounded pool of worker threads (10 by default, configurable through the FINANCETOOLKIT_MAX_WORKERS environment variable) over a shared connection, so it is recommended to initialize the Toolkit with all tickers you want to analyze at once rather than one at a time. If it is taking 10+ minutes consider having a look at this issue that managed to resolve the problem.

    I work behind a corporate proxy and get "certificate verify failed" errors, how do I solve this?

    Many corporate networks inspect encrypted traffic. The proxy opens every HTTPS connection on your behalf and presents a certificate signed by your company's own root certificate instead of the website's real one. Your browser trusts that root certificate because IT installed it on your computer, but Python does not: it checks certificates against its own list of public certificate authorities (the certifi package), which does not include your company's. The result is an error such as SSLError: certificate verify failed: self-signed certificate in certificate chain.

    When a certificate cannot be verified, the Finance Toolkit first retries with your operating system's certificate file, where Python can find one (usually on Linux, not on Windows). If that fails as well, what happens next depends on whether the request carries an API key:

    • Requests without an API key, such as those to the ECB, Eurostat or the BIS, are retried without verifying the certificate. A warning is logged when this happens.
    • Requests with an API key, such as those to FinancialModelingPrep and FRED, are not retried without verification. The key is part of the web address, so anyone who can intercept an unverified connection could read it and use your subscription. The request fails with an error that explains the options below.

    The recommended solution is to tell Python to trust your company's root certificate, so every connection stays verified:

    1. Obtain the root certificate as a .pem (or .crt) file. Your IT department can usually provide it. You can also export it from your browser by opening the certificate details of any HTTPS website and exporting the top certificate in the chain ("Base-64 encoded" on Windows).

    2. Combine it with Python's public certificates. The next step replaces Python's list rather than adding to it, so without the public certificates every connection that does not go through the proxy would fail:

      # Prints the location of Python's public certificates
      python -c "import certifi; print(certifi.where())"
      
      # macOS and Linux: combine both into one file
      cat /path/printed/above/cacert.pem /path/to/company-root.pem > ~/combined-certificates.pem
      

      On Windows you can open both files in a text editor and paste the company certificate at the end of a copy of cacert.pem.

    3. Point REQUESTS_CA_BUNDLE to the combined file before using the Finance Toolkit:

      # macOS and Linux, e.g. in ~/.bashrc or ~/.zshrc
      export REQUESTS_CA_BUNDLE=~/combined-certificates.pem
      
      # Windows (PowerShell), for every window opened afterwards
      setx REQUESTS_CA_BUNDLE "C:\Users\you\combined-certificates.pem"
      

      setx does not change the window it runs in, so open a new terminal (or restart your editor) afterwards.

      Or set it within Python, before the first request:

      import os
      
      os.environ["REQUESTS_CA_BUNDLE"] = "/path/to/combined-certificates.pem"
      
      from financetoolkit import Toolkit
      

      When you use the MCP server, add the variable to the env section of the server in your AI assistant's configuration instead.

    Alternatively, if your company's root certificate is already installed in your operating system (which is usually the case on managed Windows and macOS computers), the truststore package lets Python use the operating system's certificates directly. Install it with pip install truststore and run import truststore; truststore.inject_into_ssl() at the start of your script.

    If none of this is possible, you can accept the risk and allow requests with an API key to be sent without verification by setting FINANCETOOLKIT_ALLOW_UNVERIFIED_SSL=1 in the same way as above. Only do so on a network you trust: the connection is then encrypted to whoever answers it, which may not be the website you think you are talking to, and your API key is readable to them.

    Are you part of FinancialModelingPrep?

    No, I am not. I've merely picked them as the primary data provider given that they have a generous free tier and fair pricing compared to other providers. Therefore, any questions related to the data should go through their contact form. When it comes to any type of ratios, performance metrics, risk metrics, technical indicators or economic indicators, feel free to reach out to me as this is my own work.

    Contributing

    First off all, thank you for taking the time to contribute (or at least read the Contributing Guidelines)! 🚀


    Find the Contributing Guidelines here.


    The goal of the Finance Toolkit is to make any type of financial calculation as transparent and efficient as possible. I want to make these type of calculations as accessible to anyone as possible and seeing how many websites exists that do the same thing (but instead you have to pay) gave me plenty of reasons to work on this.

    Mentions

    The Finance Toolkit has been mentioned in various blogposts, research papers, newsletters and social media. Below is a list of some of the mentions that I am aware of. If you have any other mentions, feel free to reach out to me so I can add them to this list.

    Blogposts

    Research

    Newsletters & Social Media

    Contact

    If you have any questions about the Finance Toolkit or would like to share with me what you have been working on, feel free to reach out to me via:

    If you'd like to support my efforts, either help me out by contributing to the package or Sponsor Me.