ffn
Performance stats, drawdowns and portfolio weights from a DataFrame of prices.
by Philippe Morissette
Last updated
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-reloaded — The maintained fork of Quantopian's empyrical — risk statistics, no plots.
- QuantStats — HTML tearsheets and about eighty risk metrics from one pandas series of returns.
- arch — GARCH and the rest of the volatility-model family, plus the tests you need around them.
- pandas-ta — The DataFrame indicator library whose repo is gone and whose last release is a year old.
- PyPortfolioOpt — Prices in, weights out — efficient frontier, Black-Litterman and HRP.
- Riskfolio-Lib — Twenty-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.