Skip to content

Releases

FinanceToolkit v2.3.3

Choose a tag to compare

@github-actions github-actions released this 09 Nov 13:13
375f820

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's 'james_stein') (#386, #391).
  • get_resampled_efficient_weights (Michaud resampling), get_diversification_metrics (concentration, effective number of assets and of bets, diversification ratio) and get_risk_contributions(risk_measure="cvar") for the contributions to expected shortfall. Every CVaR uses the exact Rockafellar-Uryasev tail (#386, #391).
  • covariance= gains the Ledoit-Wolf constant-correlation and single-factor targets, codependence= ('pearson', 'spearman' or 'kendall') sets the correlation behind HRP, HERC and NCO, get_mean_variance_weights takes target_volatility= for the highest expected return at a volatility, and Black-Litterman takes risk_aversion="market" (implied by the benchmark) and reports the posterior volatility (#394).
  • get_discrete_allocation turns weights into whole shares for a portfolio value (integer programme or greedy), get_portfolio_risk_metrics gives the return, volatility, Sharpe, Sortino, maximum drawdown, VaR and CVaR of given weights next to the benchmark, and get_risk_contributions adds semideviation, mean absolute deviation and CDaR (#393).
  • The portfolio docstrings describe every optimizer by its paper and formula (#392).
  • Removed: optimization_model.get_black_litterman_returns returning only the returns; it now returns the returns and the posterior covariance (#394).

Ratios

  • Gross profitability (Novy-Marx), operating profitability (Fama-French), cash-based operating profitability, cash return on invested capital, free cash flow conversion, free cash flow to EBITDA, capex intensity and capex to depreciation (#361).
  • EBITDA, EBITDA minus capex and cash interest coverage, FFO to debt and discretionary cash flow to debt (S&P, Moody's), the degrees of operating, financial and total leverage, the free cash flow payout ratio, EV to invested capital and price to tangible book (#373).
  • The investment and issuance anomalies: asset growth (Cooper, Gulen and Schill), net operating assets (Hirshleifer et al.), percent accruals (Hafzalla, Lundholm and Van Winkle), net share issuance (Pontiff and Woodgate), composite equity issuance (Daniel and Titman) and net external financing (Bradshaw, Richardson and Sloan) (#380).

Models

  • get_altman_z_score(model=...): the original Z, Z' (private firms), Z'' (non-manufacturers) and Z''-EM (emerging markets), each with Altman's own coefficients and zones, and get_taffler_z_score, the UK model of Taffler (1983) (#369).
  • get_campbell_hilscher_szilagyi_score: the failure probability of Campbell, Hilscher and Szilagyi (2008), with its components (#390).
  • On quarterly data the distress scores (Altman, Taffler, Ohlson, Zmijewski, Springate, Grover, Fulmer, Piotroski, Beneish) cover a trailing year and compare with the same quarter a year earlier (#387).
  • The valuation models warn when the required return is less than two percentage points above the growth kept forever (#387).
  • Removed: the model function parameter market_value_of_equity_to_book_value_of_total_liabilities_ratio of altman_model.get_altman_z_score, now equity_to_total_liabilities_ratio (#369).

Risk and performance

  • Each ticker uses its own trading days, and measures against the benchmark pair returns only on dates both traded (#353).
  • The drawdown table gains calendar-day and year durations, and get_drawdown_series a deepest_since= date (#354).
  • Calculations run on unrounded prices, returns and Treasury yields; only the returned tables are rounded (#367).
  • Lo's autocorrelation-adjusted Sharpe ratio (method="lo", with Moran's bias correction and at least 30 returns), get_sharpe_ratio_standard_error (iid, non-normal and GMM), get_minimum_track_record_length, and get_coskewness and get_cokurtosis with the benchmark (#379).
  • Drawdown and tail ratios no longer drop a period for every ticker when one ticker has no value; a zero denominator gives NaN instead of ±inf; returns that do not vary have no skewness or kurtosis; and a bad OHLC bar only leaves out that day in the range-based volatility estimators (#364).

Robustness

  • Supplied historical= data is checked and normalised (dates of any type, sorted, duplicates removed, returns calculated when missing), and supplied statements without a ticker level or with repeated line items are refused with a clear message (#371).
  • All Options methods carry @handle_errors; a ticker without a price on the pricing date is left out instead of failing the others, and a start_date on a non-trading day uses the last trading day before it (#371).
  • The package no longer silences RuntimeWarnings for the whole process (#371).
  • Symbols are percent-encoded in every FMP request, so M&M.NS is no longer read as Macy's (M); FMP errors sent with status 200 are classified, and one failing ticker no longer discards the results of the others (#363).

Analyst estimates

  • The latest price target's date and the days since it (#355).
  • The number of analysts behind the revenue and the EPS estimates as separate rows, and min_analysts= on the forward P/E and PEG to leave out thinly covered years. Estimate years follow the same calendar labelling as the statements, so for fiscal years ending January to May they move one year back and the forward PEG compares the right years. Removed: the averaged "Number of Analysts" row (#381).
  • The market-wide earnings calendar returns every release of a range instead of the latest 4,000, with each company's name, exchange and market cap in USD (from its primary listing), and min_market_cap, country, exchange, primary_only and sort_by (#381).

Commodities

  • get_commodity_term_structure: the front and far contracts, spread, slope, annualised roll yield and backwardation or contango per date, on the curve as listed each day or on fixed contracts (#382).
  • get_commodity_forward_curve takes generic=True for the front month and the next eleven as listed each day, and growth/lag; its end date is no...
Read more

FinanceToolkit v2.3.2

Choose a tag to compare

@github-actions github-actions released this 06 Nov 19:43
2ddd43a

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 the close (#345).
  • Technical indicators are calculated on a year of prices before the start date, so smoothed indicators (RSI, ATR, ADX, MACD, moving averages) no longer depend on it (#349).
  • The daily P/E, P/B, earnings yield and dividend yield carry the latest reported figures to the latest close instead of dropping periods before the start date (#349).
  • get_factor_analysis leaves out a metric that fewer than three tickers have (e.g. the preferred dividend coverage ratio in ratios.get_factor_analysis(metrics="all")), with a warning, instead of failing the whole analysis.

MCP server

  • limit selects rows per ticker in multi-ticker answers (#342).
  • A requested ticker that is also the benchmark is returned by methods without a benchmark, such as quotes (#346).
  • benchmark_ticker "None", "null" or "" means no benchmark (#318).
  • All new methods are available on their tools; there are still 25 router tools.
  • A note says when the last daily row comes from an unclosed session (#345).
  • Setup wizard (financetoolkit-mcp-setup):
    • Claude Desktop's Linux path is ~/.config/Claude.
    • The Windsurf client is replaced by "Devin Desktop (Windsurf)" (devin): it writes ~/.config/devin/mcp_config.json, or the old Windsurf file where it still exists.
    • VS Code entries carry "type": "stdio".
    • A new copilot client writes the global ~/.copilot/mcp-config.json.
  • server.json is published to the MCP Registry on every release (#319), and financetoolkit.mcpb is built and attached to every release by the release workflow (#351).

Removed

  • The windsurf choice of financetoolkit-mcp-setup --client; use devin.

The version is 2.3.2 in pyproject.toml, server.json, the bundle manifest, mcp_server/mcpb/pyproject.toml (including the financetoolkit[mcp]== pin) and uv.lock.

FinanceToolkit v2.3.1

Choose a tag to compare

@JerBouma JerBouma released this 03 Nov 11:03
94db1c1

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 code, and the package metadata has project links.

Breaking

  • The reverse_dates and smooth_widow parameters are removed (#305, #302).
  • ROC, PPO, TRIX and the KST are decimals instead of percentages (#309).
  • Economics country names follow the Global Macro Database: Macedonia, Macau, Cape Verde, Sao Tome and Principe. The official names are accepted too (#309).
  • The rolling Omega is inf for a window with gains and no losses, like get_omega_ratio (#306, #310).

MCP server

  • Tools:
    • New tool portfolio_performance. Its inputs are validated before anything is fetched (one way to describe the portfolio, at most 1,000 transactions and 50 tickers), and transactions never reach the server as a file path.
    • 25 router tools.
  • OAuth hardening (#303):
    • Single-use authorization codes that expire after 5 minutes.
    • Validated redirect URIs.
    • PKCE S256 is required.
    • Field length caps.
    • An invalid token gets a 401.
  • Request handling (#303):
    • Tools run in a bounded thread pool with a lock per cached Toolkit.
    • A call waiting for a busy Toolkit gives up its slot.
    • Default dates are computed per call.
    • Ticker, search and series counts are capped.
    • Credentials are redacted from the access log.
    • The secret file is created private.
  • Inputs (#295): fractional, JSON and estimated inputs are accepted.

Other

  • Tests:
    • The flaky CI tests are fixed. 16 portfolio and point-in-time tests built Toolkits from supplied prices but without Treasury data, so valuing them retrieved Treasury yields from Yahoo Finance in parallel threads, which locked yfinance's SQLite cache ("database is locked"). Every such Toolkit now gets the supplied Treasury yields; with yfinance blocked, no test reaches it any more. Another test re-read the shared Portfolio's dataset and sent later tests online; it now uses its own Portfolio, and each test process gets its own yfinance cache.
    • 20 technical indicator tests that only recorded NaN now run on 60 sample bars and assert values.
    • New offline tests for the company data parsers.
  • Weekly source checks: a source that returns nothing is reported with what it logged, and a refusal over a request limit is skipped. The BLS allows 25 keyless requests a day per IP address, which GitHub's runners share (#315).
  • Dependencies:
    • tabulate moves from the mcp extra to the dev group.
    • Dependabot: tornado 6.6, joserfc 1.7.6, authlib 1.9.1, dnspython 2.9.0 (#312–#314, #316).
  • Dead code: the dead "pip install yfinance" branches are removed (yfinance is a required dependency).

FinanceToolkit v2.3.0

Choose a tag to compare

@JerBouma JerBouma released this 25 Oct 19:41
a704999

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).

FinanceToolkit v2.2.3

Choose a tag to compare

@JerBouma JerBouma released this 12 Oct 07:30
62315dc

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.

FinanceToolkit v2.2.2

Choose a tag to compare

@JerBouma JerBouma released this 10 Oct 14:40
37ed6f0

This release adds new FMP endpoints and recent economic and market data from official sources that need no API key. It also adds scenario and credit inputs, caches external data by default, speeds up many calculations, and fixes a range of calculations and data issues.

New data

  • FinancialModelingPrep:
    • Toolkit: executives and compensation, company notes, employee count, shares float, M&A, stock splits, insider statistics, stock grades, ETF holdings, information and weightings, and earnings call transcripts. Stock news now covers crypto and forex.
    • Discovery: market-wide earnings calendar, 8-K filings and latest insider trades.
    • Economics: economic calendar and market risk premium (optional key).
  • No API key needed:
    • Monthly inflation, CPI and unemployment; quarterly GDP growth.
    • Daily policy, overnight and long-term rates.
    • Government yield curves for nine economies, plus every EU member's 10-year yield.
  • FRED no longer required for the mortgage rate, industrial production, the recession indicator, real yields and breakevens. FRED is still used when a key is set.
  • Credit:
    • The Treasury's HQM corporate curve and spreads, and Moody's Aaa/Baa yields.
    • The excess bond premium and corporate bond yields by country.
    • Rating transition matrices and default rates from ESMA's CEREP database.
    • ECB borrowing costs and stress index.
  • Insurance and long horizons:
    • EIOPA risk-free curves, incl. shocks and the symmetric adjustment.
    • Eurostat life tables and Shiller's US stock market data.
    • Long-run asset returns 1870–2020 (opt-in, non-commercial licence).
    • The Bank of England's UK series from 1086.
  • Scenario inputs:
    • Real and breakeven inflation curves for the US, UK and Germany, and survey inflation expectations.
    • Implied volatility indices (VIX, VSTOXX, MOVE).
    • Fed and ESRB stress-test scenarios and DNB pension scenario sets.
    • NGFS climate scenarios and the EU carbon price.
    • Listed proxies for private markets.
  • Global Macro Database: uses the latest quarterly release. IMF projections are excluded by default.

Caching

  • On by default: data from external sources is cached in the Toolkit, Economics, Fixed Income, Discovery and Portfolio modules. Each dataset is refreshed on its own schedule, and calculated metrics are never cached.
  • Empty answers: an answer that a source has no data is cached too; a failed request is not.
  • FMP first: with an FMP key, FMP data takes priority. Yahoo Finance is used when it has the longer history, for example on the Free plan.

Performance

Before After
EGARCH / GARCH 186 s / 7.9 s 13 s / 1.2 s
Monte Carlo option prices 66 s 2.5 s
All option greeks 5.4 s 0.15 s
All technical indicators 3.3 s 0.7 s
from financetoolkit import Toolkit 2.5 s 0.9 s
Reading prices from the cache 3.8 s 1.1 s

Excel files are read with calamine, modules load on first use, and repeated module access is about twice as fast.

Breaking changes

  • get_real_yield_curve and get_breakeven_inflation_expectations take countries= and return (Country, Maturity) columns labelled 5Y.
  • The market risk premium and percentage releases in the economic calendar are now decimals.
  • GMDB series end at the last observation; gmdb_forecasts=True on a method includes the projections.
  • Corrected calculations change some results:
    • Drawdowns now count a loss on the first day.
    • RSI and CMO start one day later, matching Wilder's definition and TA-Lib.
    • Growth from zero is missing instead of infinite.
    • Missing values no longer skew beta, VaR/CVaR or the portfolio average.
  • External data is cached by default. Opt out with use_cached_data=False or FINANCE_TOOLKIT_CACHE_ENABLED=0.
  • Requests carrying an API key are no longer retried without certificate verification. Behind a corporate proxy, set REQUESTS_CA_BUNDLE; the README Q&A explains how.

Fixes

  • Data:
    • FMP timeouts and server errors are retried per ticker instead of failing the whole request.
    • Cached prices survive a provider switch.
    • Holidays no longer invent returns or volume.
    • CIK and CUSIP keep their leading zeros.
    • Yahoo listing dates use the exchange's timezone.
  • Calculations:
    • WACC is correct for companies without debt, and the Graham Number for loss-making companies.
    • Barrier options are priced correctly once the barrier has been crossed.
    • Black-Scholes at expiry, bond coupon counts and yields, and binomial tree inputs are handled correctly.
  • Consistency:
    • rounding=0 and rounding=None work everywhere.
    • One error handler serves all modules, so strict mode now covers Performance and Technicals.
  • Other:
    • EIOPA shocked curves and the life tables are fixed.
    • The enterprise value breakdown and implied volatility work again.
    • The economic calendar's order is now deterministic.
    • Moved BIS, Fed and NBER endpoints are updated.
  • Docstrings: all 553 examples were run and their output tables refreshed.

MCP server

  • New methods are added to the existing tools, and an empty result explains why.
  • Tool descriptions are no longer cut off.
  • Daily rolling performance metrics work.
  • A hosted server caches every source except FMP.
  • Optional usage statistics at /stats with FT_MCP_ANALYTICS=1.
  • The server reports the Finance Toolkit's version to clients.

Dependencies

All new requirements use wide version ranges, so the Finance Toolkit fits alongside other packages without forcing upgrades.

Change Package Why
Added python-calamine>=0.3.0 Reads Excel workbooks up to 10× faster than openpyxl. Used for the large official workbooks, such as the Bank of England, EIOPA and ESRB files. Not installed on Python 3.15 until wheels are published there; openpyxl reads the files instead.
Added xlrd>=2.0 Reads the older .xls workbooks some official sources still publish, when calamine is not available or cannot read a file.
Declared numpy>=1.26, scipy>=1.10 Already used throughout, but until now they were only installed because other packages depended on them. They are now listed explicitly.
Removed scikit-learn Only used for the linear regressions of the factor models (e.g. Fama-French). These now use SciPy's least squares, with the same results, which removes a large dependency.

Unchanged: pandas>=3.0, requests, yfinance, openpyxl and pyyaml, and the optional econometrics and mcp extras.

FinanceToolkit v2.2.1

Choose a tag to compare

@JerBouma JerBouma released this 01 Oct 19:08
5662be3

A focused maintenance release. Its most urgent fix: a fresh install of the 2.2.0 MCP server crashed on startup, because the mcp dependency had no upper bound and mcp 2.x removed a module the server imports. The local install command on the website therefore failed for everyone. This release caps mcp below 2.0 and fixes two MCP data bugs on top: the rates tool returned no Treasury yields at all, and a benchmark that was also a requested ticker was silently swapped for a different index.

The second theme is daily-first analysis. Risk and Econometrics now default to daily calculations over the whole series instead of quarterly/yearly per-period values, which removes the intraday-data requirement that made period="daily" unusable in Econometrics. Some results change for existing code as a result; see Changed Defaults below.

Underneath, data collection is faster and better behaved. A bounded worker pool replaces one thread per ticker, HTTP connections are reused, and retries back off with jitter. The package now ships type information (py.typed), and the type checker runs in CI.

Every method below hangs off the matching Toolkit sub-module (e.g. toolkit.risk.get_value_at_risk()) or its standalone class (Economics(...), FixedIncome(...), Discovery(...)). Full runnable examples live in the documentation, which now has a dedicated page for every method.

Changed Defaults

  • Econometrics defaults to period="daily" across all methods (previously quarterly or yearly, depending on the Toolkit). within_period now defaults to False on the five diagnostic tests that take it (ARCH-LM, Jarque-Bera, Ljung-Box, CUSUM, Variance Ratio). Every Econometrics method previously rejected period="daily" outright, even though only the within-period nesting needs intraday data. Intraday data is now only required for period="daily" combined with within_period=True, and the error message says how to avoid it. Full examples: docs/econometrics.
  • Risk defaults to period="daily" and within_period=False as well, so metrics such as Value at Risk, CVaR and the GARCH family are calculated over the whole daily series by default. Per-period aggregates (variance, volatility, excess volatility, MAD, coefficient of variation) keep their quarterly/yearly default, since a single daily return has no spread to measure. Full examples: docs/risk.
  • If your code relied on the old defaults, pass period="quarterly"/"yearly" (and within_period=True) explicitly to get the previous behaviour.

Performance

  • Bounded worker pool. Every data collection function used to start one bare thread per ticker, with a 0.1-second stagger between them. A 100-ticker universe spent 10 seconds just starting threads, exceptions died silently inside their thread, and the number of concurrent API calls grew with the universe. All 13 collection sites now share one ThreadPoolExecutor with 10 workers by default (configurable via FINANCETOOLKIT_MAX_WORKERS) that re-raises worker exceptions.
  • Connection reuse. Every request goes through one shared requests session with enlarged connection pools, so repeated calls to the same API reuse TCP connections and TLS handshakes instead of paying for a new handshake each time.
  • Retries back off with jitter, so ten workers hitting a rate limit don't all retry at the same moment.
  • Treasury rate windows are fetched in parallel through the same pool, instead of one by one with sleeps in between.
  • Memoized slices. Risk (_get_returns), Econometrics and Performance cache the return and column slices their methods start from, so collecting many metrics, as the MCP server does in one session, no longer recomputes them for every metric.

Bug Fixes

Risk & Econometrics

  • Whole-series Risk calculations on resampled periods returned NaN, because the first resampled return is always NaN. That row is now dropped before the calculation.
  • get_arch_lm_test(within_period=False) produced no values at all under the old yearly default: four yearly observations can't support a 5-lag ARCH test. With the daily default it now returns real results.
  • Fresh installs now resolve statsmodels 0.15, where the ADF test (get_augmented_dickey_fuller) and the ARCH-LM test (get_arch_lm_test) printed a FutureWarning about an upcoming change to their return format. The toolkit is unaffected by that change until statsmodels 0.16, so these two notices are now silenced. Results are identical on statsmodels 0.14 and 0.15.

API key handling

  • Passing the documentation placeholder api_key="FINANCIAL_MODELING_PREP_KEY" used to reach FinancialModelingPrep and come back as a generic "invalid API key", without saying that the example value was never replaced. It's now reported as a placeholder, with a link to get a key, and treated as no key at all (e.g. the Toolkit falls back to Yahoo Finance). This applies to Toolkit, Portfolio, Discovery, FixedIncome and the MCP server.

MCP Server

  • Fresh installs crashed on startup. mcp 2.x removed mcp.server.fastmcp, which the server imports, and the mcp extra had no upper bound, so pip install financetoolkit[mcp] resolved mcp 2.x and failed immediately. The extra now requires mcp[cli]>=1.27.0,<2.
  • rates → get_treasury_rates returned no data. The server built FixedIncome without the FMP API key, which the Treasury par yield curve needs, and the error was swallowed into "No data available". The key is now passed on, and both the FMP and FRED keys are part of the instance cache key, so instances are never shared between keys.
  • The benchmark could silently be a different security. When a requested ticker was also the benchmark (e.g. tickers="AAPL,SPY" with benchmark_ticker="SPY"), the server replaced the benchmark with the first unused fallback. "Benchmark" was then QQQ (739.77 instead of SPY's 762.63 on 2026-09-30), so every beta, alpha and excess return was measured against the wrong index. The requested benchmark is now kept, matching the library; a fallback is only used when the benchmark is the sole ticker. Either way, the response includes a note explaining where the benchmark's data is.
  • The startup log reported "Registered router group '…' → True tool(s)" instead of a count; it now names the registered group.
  • Daily period is no longer blocked for the risk tool, matching the new default.
  • Per-call timing is logged at debug level, so a slow tool can be diagnosed from the logs alone.

Documentation

  • Every method has its own documentation page. The 76 README links that pointed to an anchor on a module page (docs/ratios#collect_profitability_ratios) now point to that method's dedicated page (docs/ratios/all-profitability-ratios).
  • 21 Econometrics methods, including get_vif, get_ols, the heteroskedasticity and specification tests, the nested-model tests, Fama-MacBeth, synthetic control and the VAR forecast, previously had a single sentence plus a pointer to an internal function the website doesn't show. Each now explains what it computes, the formula, how to read the result for the tickers involved, and the original reference.
  • 31 Econometrics docstrings still said period followed the Toolkit's quarterly/yearly setting; they now document the actual "daily" default.
  • FixedIncome.get_government_bond_yield opened with the 10-year description even when short_term=True returns the 3-month rate. Both maturities are now described, including that the OECD short-term figure is the 3-month interbank rate rather than a Treasury bill yield.
  • get_dual_gamma reused the gamma description; it now describes the second derivative with respect to the strike price.
  • The dead Global Macro Database link in get_gross_domestic_product now points to the GMD documentation page.

Typing

  • The package now ships py.typed, so downstream type checkers see its annotations.
  • uv check (Astral's ty) runs in pre-commit and in the linting workflow. Five rules are back at their default severity (call-non-callable, not-iterable, not-subscriptable, unsupported-operator, unknown-argument), with the code they flagged fixed. 29 stale type: ignore comments are gone. The rules that only reflect pandas' very wide Series | DataFrame return types stay disabled.

Test Coverage & CI

  • Toolkit parameter validation (dates, risk-free rate, source, intraday period, tickers) now lives in its own module, validation_model, so bad input can be tested without building a Toolkit and fetching data.
  • CI runs the suite in parallel (pytest-xdist) with the uv cache. The Economics tests skip cleanly when offline or without a FRED key, instead of erroring.
  • The recorder gains --rewrite-failing, which regenerates only the stored outputs that fail comparison, so a regeneration can't churn unrelated files through float noise.
  • New tests cover the MCP provider (the treasury key and the benchmark handling) and the placeholder API key.
  • A version-alignment test makes sure pyproject.toml, server.json, the MCPB manifest and the MCPB bundle's own pyproject.toml all carry the same version.
  • A Python 3.15 job runs in CI and is skipped until the lock file contains SciPy wheels for 3.15, rather than compiling SciPy from source on the runner.

Dependencies

  • mcp[cli]>=1.27.0,<2 in the mcp extra (see MCP Server above).
  • Lockfile updates: cryptography 50.0.0, httpx2/httpcore2 2.12.0, jupyterlab 4.6.4, notebook 7.6.3, pyjwt 2.15.0, tornado 6.5.9, urllib3 2.8.0.

Full comparison: v2.2.0...v2.2.1

FinanceToolkit v2.2.0

Choose a tag to compare

@JerBouma JerBouma released this 18 Aug 12:47

This is the largest release to date. The headline addition is a brand new Econometrics module (toolkit.econometrics) — 48 methods covering regression, panel data, causal inference, unit root/cointegration testing, Granger causality, diagnostics, and forecasting, all funneled through statsmodels/linearmodels instead of hand-built math. Alongside it, Risk, Performance, Models and Economics roughly double in depth with systemic-risk, market-timing, bankruptcy-scoring and crisis-dating metrics, and Technicals, Ratios, Fixed Income and Options each pick up a batch of previously-missing metrics.

The second large addition is a rebuilt caching layer. Three separate, incompatible caching mechanisms have been replaced by one incremental, range-aware SQLite cache that knows what it already holds per ticker and per date range — widening a period now retrieves only the missing years, and adding a ticker retrieves only that ticker. It also removes a genuine correctness bug in the old one, which silently overwrote the tickers and dates you asked for with whatever an earlier cached run had used. See Caching below.

Just as importantly, this release includes an extensive formula-correctness pass across nearly every module, carried out over two separate audit rounds — the second explicitly re-checking the first round's own fixes rather than trusting them. Every accepted finding was verified against live FMP/FRED/OECD/ECB/NY Fed data, published figures from BLS/BEA/the US Treasury/Ken French/the source papers, a reference library (TA-Lib/arch/statsmodels/linearmodels/py_vollib) where one exists, or analytic ground truth via Monte Carlo and finite differences. Combined, this fixed over 200 defects. Several of these are not edge-case bugs — Sharpe Ratio, Sortino Ratio, M2 Ratio, RSI, ADX, ATR, EWMA Volatility, the Hurst Exponent, Macaulay's Duration, bond DV01, Portfolio Volatility, US "headline" unemployment and every price-to-fundamental ratio on the LSE/JSE/TASE were all silently returning the wrong number in prior releases. See Bug Fixes below for the full list with what changed and why.

Minimum requirements changed: pandas>=3.0 (was >=2.2) and Python 3.11+ (was 3.10+, since pandas 3.0 itself drops 3.10 support).

Every method below hangs off the matching Toolkit sub-module (e.g. toolkit.econometrics.get_ols()) or its standalone class (Discovery(...), Economics(...), FixedIncome(...)). Full runnable examples with real output live in the documentation — each section below links to its module's page.

New Features

Econometrics (new module)

toolkit.econometrics is a new, optional module for testing statistical properties of price/return series and estimating causal effects — installed via the financetoolkit[econometrics] extra (statsmodels/linearmodels). Every result is a plain dict (matching the rest of the codebase's convention of returning pd.Series/pd.DataFrame rather than opaque result objects), with a matching *_summary_table/*_summary companion wherever a .summary() would otherwise be expected. Full examples: docs/econometrics.

  • Regression: get_ols, get_wls, get_gls (nonrobust/HC0-3/cluster/HAC-Newey-West standard errors), get_logistic_regression, get_probit_regression, get_quantile_regression.
  • Panel data: get_fixed_effects, get_random_effects, get_hausman_test (which specification to prefer).
  • Causal inference: get_difference_in_differences, get_iv_2sls, get_propensity_score_matching, get_regression_discontinuity, get_synthetic_control (Abadie/Diamond/Hainmueller 2010, with placebo-based inference).
  • Time series forecasting: get_arima_forecast, get_var_forecast (plus get_impulse_response_function and get_variance_decomposition), get_vecm_forecast.
  • Cross-sectional asset pricing: get_fama_macbeth_regression (Fama-MacBeth two-pass regression).
  • Event studies: get_event_study (MacKinlay 1997 market-model cumulative abnormal return analysis).
  • Unit root & cointegration: get_augmented_dickey_fuller, get_kpss_test, get_phillips_perron_test, get_zivot_andrews_test; get_engle_granger_cointegration, get_johansen_cointegration.
  • Granger causality: get_granger_causality.
  • Diagnostics: get_arch_lm_test, get_jarque_bera_test, get_ljung_box_test, get_cusum_test, get_variance_ratio_test.
  • Specification & hypothesis tests: get_breusch_pagan_test, get_white_test, get_durbin_watson_test, get_vif, get_ramsey_reset_test, get_chow_test, get_f_test, get_likelihood_ratio_test, get_wald_test, get_hausman_wu_test, get_two_sample_t_test.
  • Forecast evaluation: get_rmse, get_mae, get_diebold_mariano_test, get_out_of_sample_validation.

Risk

Call these via toolkit.risk.<method>(). Full examples: docs/risk.

  • get_covar (CoVaR / Delta-CoVaR) — how much returns' own tail risk worsens when conditioning_returns (e.g. the financial system, or a specific counterparty) is itself in distress, via quantile regression. Reference: Adrian, T. & Brunnermeier, M.K. (2016), American Economic Review.
  • get_marginal_value_at_risk / get_component_value_at_risk — Euler risk decomposition of portfolio VaR: Marginal VaR is each asset's Beta to the portfolio times portfolio VaR; Component VaR is that scaled by the asset's weight, and the components sum exactly to total portfolio VaR (Garman 1997, Litterman 1996).
  • get_amihud_illiquidity (Amihud 2002) and get_roll_spread (Roll 1984) — market-microstructure liquidity measures derived purely from price/volume, without needing order-book data.
  • get_volatility(method=...) — four realized-volatility estimators ("parkinson", "garman_klass", "rogers_satchell", "yang_zhang") built from daily OHLC(V) prices rather than just closes, each using more of the day's price action (and, for Yang-Zhang, overnight gaps) to estimate volatility more efficiently than a close-to-close standard deviation. The default method="close_to_close" is the existing behaviour.
  • get_har_rv_forecast (Corsi 2009 HAR-RV) — forecasts future realized variance from a simple linear combination of daily, weekly and monthly lagged realized variance, a cheap and surprisingly effective alternative to a full GARCH fit.
  • get_hill_estimator — a nonparametric estimate of the tail index of the return distribution, i.e. how fat the tails actually are.
  • get_gjr_garch / get_egarch (plus _forecast/_parameters variants, and get_garch_parameters for the plain model) — asymmetric GARCH models where negative and positive shocks affect future volatility differently (the leverage effect), unlike plain GARCH. References: Glosten, Jagannathan & Runkle (1993); Nelson (1991).
  • get_var_backtest — builds a rolling, out-of-sample VaR path and backtests it with the Kupiec (1995) proportion-of-failures test and the Christoffersen (1998) independence test, to check whether a VaR model's breach rate and breach clustering match what the confidence level implies.
  • get_acerbi_szekely_test — the counterpart for Expected Shortfall, backtesting a CVaR model against realized returns via the Acerbi-Szekely (2014) Z2 statistic, since the breach-counting tests above only validate VaR.
  • get_tail_dependence_coefficient, get_copula_parameters / get_copula_simulation / get_best_fitting_copula — Gaussian, Student-t, Clayton, Gumbel and Frank copulas with MLE fitting, simulation, and AIC-based family comparison, for modelling joint tail behaviour between two return series beyond what linear correlation captures. Default to running across every unique ticker pair on the Toolkit instance when no explicit pair is given.

Performance

Call these via toolkit.performance.<method>(). Full examples: docs/performance.

  • get_sharpe_ratio(method=...) — three corrections to the plain Sharpe Ratio: "adjusted" for skewness/kurtosis, "probabilistic" for estimation uncertainty given the sample size, and "deflated" for multiple-testing bias when many strategies were tried before picking the best one. The default method="standard" is the existing behaviour.
  • get_appraisal_ratio — Jensen's Alpha divided by the idiosyncratic (residual) standard deviation left over from the CAPM regression that produced it: how much stock-picking skill an active manager is generating per unit of the risk that skill itself introduces.
  • get_fama_decomposition (Fama 1972) — splits total excess return into Selectivity and Diversification, decomposing Jensen's Alpha further than the Alpha figure alone can.
  • get_henriksson_merton_model and get_treynor_mazuy_model — market-timing regressions that test whether a manager's returns show evidence of successfully timing the market, not just picking good securities.
  • get_rachev_ratio (R-Ratio) and get_starr_ratio — tail-focused alternatives to Sharpe/Sortino that measure reward per unit of tail risk (CVaR-based) rather than per unit of standard deviation or downside deviation.
  • get_carhart_four_factor_model (Carhart 1997) — adds a momentum factor to the existing Fama-French regression machinery.

Models

Call these via toolkit.models.<method>(). Full examples: docs/models.

  • get_fulmer_h_score, get_grover_score, get_ohlson_o_score, get_springate_score, get_zmijewski_score — five more bankruptcy/distress prediction models alongside the existing Alt...
Read more

FinanceToolkit v2.1.4

Choose a tag to compare

@JerBouma JerBouma released this 14 Jul 13:43
1afcbb9

This is one of the larger feature releases to date. It roughly doubles the depth of three modules — Models, Performance, and Risk — and rounds out Technicals, Ratios, and Discovery with metrics that were previously missing.

Two capabilities now cut across nearly the whole toolkit:

  • rolling and trailing windows. Many metrics used to return one value per reporting period. They can now be computed over a sliding window (rolling=<n>) or a trailing sum/average (trailing=<n>), turning a snapshot into a proper time series.
  • standardize (Z-Score). Most get_* methods across Economics, Ratios, Technicals, Risk, Performance, Models, Options, and Fixed Income now accept standardize=True. It converts raw values into standard deviations from their own historical mean, so metrics on completely different scales become directly comparable — useful for ranking, scoring, or spotting an unusual reading at a glance.

On the fix side: swaption prices are discounted correctly now, a case-mismatch bug that was silently zeroing out diluted EPS is gone, and the new Forward P/E / Forward PEG ratios cache analyst estimates properly instead of double-fetching.

Volatility, Excess Return, and Excess Volatility are gone from toolkit.get_historical_data(). Use these instead:

  • toolkit.risk.get_volatility(period=...)
  • toolkit.risk.get_excess_volatility(period=...)
  • toolkit.risk.get_variance(period=...)
  • toolkit.performance.get_excess_return(risk_free_rate=..., cumulative=...)

Every method below hangs off the matching Toolkit sub-module (e.g. toolkit.models.get_graham_number()) or its standalone class (Discovery(...), Economics(...), FixedIncome(...)). Full runnable examples with real output live in the documentation — each section below links to its module's page.

New Features

Standardization (Z-Score)

standardize: bool = False is now available on nearly every controller — Economics, Ratios, Technicals, Risk, Performance, Models, Options, and Fixed Income, roughly 270 methods in total.

Z-Score = (value - mean) / standard deviation

Mean and standard deviation come from each series' own history: per ticker for entity-indexed data like ratios, per column for date-indexed data like economic indicators. With growth=True, it standardizes the growth values instead of the raw ones. Use it to compare metrics that live on incompatible scales, build a quick cross-sectional ranking straight from toolkit output, or spot when a current reading is an unusual number of standard deviations from its own norm.

Financial Models

Call these via toolkit.models.<method>(). Full examples: docs/models.

get_economic_value_added (EVA, economic profit) — whether a company earns more than its true cost of capital, something Net Income alone can't tell you.

  • NOPAT = EBIT × (1 − Effective Tax Rate)
  • Invested Capital = Total Equity + Total Debt (each smoothed as a 2-period average, or a trailing-period average, to soften a single noisy balance-sheet snapshot)
  • EVA = NOPAT − (WACC × Invested Capital)
  • Read it as: positive EVA creates value for capital providers; negative EVA destroys it, even in periods where net income is positive.

get_beneish_m_score (earnings manipulation score) — Messod Beneish's model for flagging likely earnings manipulation, a companion to the Altman Z-Score and Piotroski F-Score already in the toolkit.

  • M-Score = -4.84 + 0.92·DSRI + 0.528·GMI + 0.404·AQI + 0.892·SGI + 0.115·DEPI − 0.172·SGAI + 4.679·TATA − 0.327·LVGI
  • Each of the eight inputs is its own function in beneish_model.py: get_days_sales_in_receivables_index (DSRI — receivables outgrowing sales), get_gross_margin_index (GMI — margin deterioration), get_asset_quality_index (AQI — a rising share of non-core assets), get_sales_growth_index (SGI — fast growth raises manipulation pressure), get_depreciation_index (DEPI — a slowing depreciation rate flatters earnings), get_selling_general_and_administrative_expenses_index (SGAI), get_leverage_index (LVGI), and get_total_accruals_to_total_assets (TATA — the accrual share of earnings, a red flag across most accounting-fraud models).
  • Read it as: above roughly -1.78, manipulation is more likely; below it, less likely. It's probabilistic, not a verdict — pair it with real fundamental analysis. The first period is always NaN since every input needs a prior period to compare against.
  • Reference: Beneish, M. D. "The Detection of Earnings Manipulation." Financial Analysts Journal, Vol. 55, No. 5, 1999, pp. 24-36.

get_sustainable_growth_rate (SGR) — the fastest a company can grow revenue on internal funds alone, without new equity or added leverage.

  • SGR = Return on Equity × (1 − Dividend Payout Ratio)
  • Read it as: growing faster than SGR without outside financing means improving margins, cutting the payout, or taking on more debt — so actual growth versus SGR is a quick tell for how a company is funding its expansion.

get_internal_growth_rate (IGR) — a stricter version of SGR: growth funded from retained earnings only, with no debt added at all.

  • IGR = (ROA × Retention Ratio) / (1 − (ROA × Retention Ratio))
  • Read it as: IGR is always below SGR for a levered company. The gap between them is roughly how much of that company's "sustainable" growth actually depends on debt.

get_graham_number (Graham fair value) — Benjamin Graham's conservative ceiling on what a defensive investor should pay.

  • Graham Number = √(22.5 × EPS × Book Value per Share)
  • Read it as: most useful for stable, profitable companies with positive book value. Negative earnings or book value produce NaN (the square root of a negative number is undefined) — comparing the current price against this number is a quick margin-of-safety check.

Ratios

Call these via toolkit.ratios.<method>(). Full examples: docs/ratios.

Efficiency

  • get_research_and_development_ratio, get_selling_and_marketing_ratio, get_general_and_administrative_ratio — R&D, S&M, and G&A each as a share of Revenue. Most companies only report these lumped into SG&A; splitting them out lets you compare R&D intensity or customer-acquisition spend independent of admin overhead.
  • get_stock_based_compensation_ratio — SBC ÷ Revenue. A high or rising number is a quality-of-earnings flag, since SBC gets added back in cash flow from operations (flattering FCF) while still diluting existing shareholders.
  • get_deferred_revenue_ratio — Deferred Revenue ÷ Revenue. A leading indicator for subscription/SaaS businesses: a growing balance here signals revenue that hasn't hit the income statement yet.

Profitability

  • get_cash_tax_rate — taxes actually paid in cash ÷ Income Before Tax, versus the accrual-based Effective Tax Rate.
  • get_tax_rate_divergence — Cash Tax Rate minus Effective Tax Rate. Persistently positive means more cash tax paid than expensed (e.g. deferred liabilities unwinding); persistently negative can flag aggressive tax deferral.

Solvency

  • get_debt_to_capital_ratio — Total Debt / (Total Debt + Total Equity). Stays between 0 and 1, unlike Debt-to-Equity, which makes capital structure easier to compare across companies.
  • get_preferred_dividend_coverage_ratio — Net Income ÷ |Preferred Dividends|: how many times earnings cover the obligation to preferred shareholders.
  • get_interest_paid_to_expense_ratio — Interest Paid ÷ Interest Expense. Well below 1 suggests interest is being accrued rather than paid (e.g. payment-in-kind debt); well above 1 suggests catch-up payments or a cash/accrual timing gap.

Valuation

  • get_ev_to_free_cash_flow_ratio — Enterprise Value ÷ Free Cash Flow, a multiple that (unlike EV/EBITDA) accounts for capex and working capital.
  • get_buyback_yield — -(Repurchases + Issuances) / Market Cap. Positive means the company is a net repurchaser; negative means it's a net issuer, diluting shareholders.
  • get_shareholder_yield — Dividend Yield + Buyback Yield: total cash returned to shareholders through both channels.
  • get_sbc_adjusted_free_cash_flow — Free Cash Flow minus Stock-Based Compensation, treating SBC as the real cost it is instead of the non-cash add-back FCF normally lets it be.
  • get_forward_price_earnings_ratio (Forward P/E) — Stock Price / Estimated EPS Average, using the analyst consensus estimate for a future period instead of trailing EPS. Needs a Premium FMP subscription; estimates are fetched once per Toolkit instance and cached automatically, so there's no need to call get_analyst_estimates() first.
  • get_forward_price_earnings_growth_ratio (Forward PEG) — Forward P/E / (Estimated EPS Growth Rate × 100), where growth bridges the analyst estimate to the company's most recent actual EPS (get_estimated_eps_growth_rate, its own reusable function) rather than comparing two historical periods the way growth=True does everywhere else. Read it as: near or below 1 is the classic (simplistic) heuristic for fairly priced growth; well above 1 means the market is paying a premium for it.

Technical Indicators

Call these via toolkit.technicals.<method>(). Full examples: docs/technicals.

Overlap

  • get_weighted_moving_average (WMA) — weights recent prices more, so it tracks price more closely than a Simple Moving Average while staying smoother than an Exponential one.
  • get_hull_moving_average (HMA) — combines a half-window WMA, a full-window WMA, and a √window WMA specifically to cut moving-average lag without g...
Read more

FinanceToolkit v2.1.3

Choose a tag to compare

@JerBouma JerBouma released this 27 Jun 09:03

Minor release with mostly bug fixes and some minor enhancements.

Bug Fixes

  1. Corrected trailing rolling axis for valuation ratios: The show_daily and trailing combination in get_enterprise_value, get_market_cap, and related valuation ratios was applying the rolling window on the wrong axis (tickers instead of dates), producing incorrect results when both parameters were active simultaneously.

  2. Resolved trailing parameter having no effect in get_market_cap: The if/else branches for trailing were identical, meaning the parameter was silently ignored regardless of what was passed.

  3. Fixed cumulative return calculations for edge case data: Replaced (1 + returns).cumprod() with (1 + returns.fillna(0)).cumprod() across historical_model.py and risk_model.py, and added .replace([np.inf, -np.inf], np.nan) before cumulative product computation to prevent inf propagation when input data contains gaps or anomalies.

  4. Resolved pandas FutureWarning in performance controller: Added future_stack=True to stack() calls in performance_controller.py to silence the upcoming default behaviour change in pandas.

  5. Fixed type annotation in helpers.py: Corrected pd.PeriodIndex to pd.DatetimeIndex in a function signature.

New Features

  1. trailing parameter for Models: Added a trailing parameter to the Models sub-module (e.g. get_weighted_average_cost_of_capital). When supplied, financial statement inputs are rolled over the trailing period before calculation, enabling TTM-style model outputs consistent with the same parameter in Ratios and Performance.

  2. trailing parameter for Ratios: Valuation ratios (P/E, P/B, free cash flow yield, price-to-earnings, etc.) now accept an explicit trailing parameter. Previously, quarterly data defaulted unconditionally to trailing=4; the parameter now allows overriding or disabling that behaviour.

Test Coverage

Added missing snapshot tests for: collect_custom_ratios, get_cash_conversion_efficiency, get_effective_tax_rate, get_debt_service_coverage_ratio, get_weighted_dividend_yield, get_reinvestment_rate, get_ev_to_ebit, collect_all_metrics (performance + risk), and get_compound_growth_rate. Updated snapshots for valuation methods affected by the trailing and show_daily axis fixes. Added httpx2 as a dev dependency to resolve StarletteDeprecationWarning in MCP OAuth tests.

MCP Server

Updated MCPB manifest and build script to reflect the latest configuration. Removed conflicting description remarks from the registry and tools model.

Full comparison: v2.1.2...v2.1.3