ffn

Performance stats, drawdowns and portfolio weights from a DataFrame of prices.

by Philippe Morissette

Last updated

From
Free
Licence
MIT
Self-hosted
Yes
Platforms
Library

What it is

ffn takes a pandas DataFrame of prices and gives back a statistics object. prices.calc_stats().display() prints total and annualised returns, Sharpe, Sortino, Calmar, max drawdown and drawdown details, monthly and yearly return tables, and lookback returns — per column and across the group. GroupStats handles many series at once, to_csv writes the table out, and plot() and plot_corr_heatmap() draw the usual two pictures.

Beyond the stats table there are two things that are not obvious from the name. Portfolio weighting is built in — calc_inv_vol_weights, calc_mean_var_weights with a Ledoit-Wolf covariance estimate, calc_erc_weights for equal risk contribution, plus limit_weights and the clustering helpers calc_clusters and calc_ftca. And so is a small set of overfitting diagnostics — calc_deflated_sharpe_ratio and calc_prob_backtest_overfitting — which is more than most performance libraries in this category offer at all.

Pricing

Free, MIT-licensed, nothing to buy. pip install ffn is the entire product. The dependency list is heavier than the code suggests — pandas, numpy, scipy, scikit-learn, matplotlib, tabulate, decorator and yfinance — which is why the README still recommends installing into a scientific Python distribution.

Data & coverage

ffn ships no market data. The one fetcher is ffn.get('aapl,msft', start='2010-01-01'), which downloads Yahoo Finance prices through yfinance; anything else you load yourself from a CSV or a market data API. The library has no instrument model at all, so asset classes and markets are whatever your price columns happen to be.

Integrations

bt is the companion backtester by the same author and the tie is structural rather than nominal — bt depends on ffn>=1.1.2, bt.Result subclasses ffn.GroupStats, and the stats table, the plots and to_csv a bt user sees are all this package. yfinance is the price source behind ffn.get.

Repository state on 19 September 2026: release 1.2.2 on 17 September, last commit to master the same day, 4 open issues, not archived. Python 3.9 through 3.13.

Limitations

  • Prices in, not returns. Feeding a returns series directly is a common first mistake; convert it with to_price_index() first.
  • No simulation. There is no order, no cost model and no rebalancing schedule here — that is bt, and it is a separate install.
  • No HTML report. The output is a printed table, a DataFrame or a CSV, which is the opposite trade-off from QuantStats.
  • The weighting functions are convenience, not an optimizer. No custom objective, no linear constraints, no transaction-cost term.
  • PyPI still classifies it Development Status :: 4 - Beta after twelve years, the same as bt.
  • yfinance is a hard dependency even if you never touch ffn.get.

Alternatives

QuantStats if what you want is a tearsheet to send someone; empyrical-reloaded if you want the bare numbers and the smallest dependency footprint; bt when the question has moved from measuring a series to simulating a rule.

Specs

Interfaces
Python, Python
Export
CSV
Asset classes
Stocks, ETF
Markets
Global
Platforms
Library
AI features
None
Pricing verified
Capabilities verified
Coverage verified

Also from Philippe Morissette

Also worth comparing

  • empyrical-reloadedThe maintained fork of Quantopian's empyrical — risk statistics, no plots.
  • QuantStatsHTML tearsheets and about eighty risk metrics from one pandas series of returns.
  • archGARCH and the rest of the volatility-model family, plus the tests you need around them.
  • pandas-taThe DataFrame indicator library whose repo is gone and whose last release is a year old.
  • PyPortfolioOptPrices in, weights out — efficient frontier, Black-Litterman and HRP.
  • Riskfolio-LibTwenty-six convex risk measures, four objectives, one cvxpy-backed optimiser.

FAQ

Is ffn maintained, and by whom?

Yes, and it is the liveliest library in this section. Version 1.2.2 was released on 17 September 2026 and the last commit to master is from the same day, with four open issues and no archive flag. Philippe Morissette remains the repository owner and the name on PyPI, but the handover is older than the version numbers suggest — every tagged release since v0.3.5 in January 2021 was cut by Tim Paine, who now has more commits on the repository than Morissette does, and Morissette's own last commit landed in April 2018.

What is the difference between ffn and bt?

They are the same author's two halves of one idea. ffn measures — statistics, drawdowns, weighting schemes — and bt simulates, walking a price index one row at a time. bt depends on ffn, its Result object subclasses ffn.GroupStats, and bt.get is an alias for ffn.get. If you only want the statistics, install ffn alone and skip the backtester.

Does ffn take prices or returns?

Prices. prices.calc_stats() is the entry point, and returns-only inputs go through to_price_index() first. This is the practical difference from QuantStats and empyrical, both of which start from a returns series.

Can ffn compute portfolio weights?

Yes — inverse volatility, mean-variance with a Ledoit-Wolf covariance estimate, and equal risk contribution, plus clustering helpers and a limit_weights cap. It is not a dedicated optimizer with constraints and objectives, but for a handful of standard schemes it saves pulling in one.