bt
Python backtesting for allocation and rebalancing rules, not entries and exits.
by Philippe Morissette
Last updated
What it is
bt takes a pandas DataFrame of prices and a Strategy built from an ordered list of algos —
RunMonthly(), SelectAll(), WeighEqually(), Rebalance() is the canonical four-liner — and
walks the index one row at a time, tracking positions, transactions and costs.
The distinction that decides whether this is your tool: bt tests allocation rules, not entries
and exits. The fifty-odd algos that ship are scheduling (RunDaily through RunYearly,
RunIfOutOfBounds), selection (SelectMomentum, SelectWhere) and weighting (WeighInvVol,
WeighERC, WeighMeanVar, TargetVol). Nothing addresses a stop, a limit order or a trade
lifecycle. If the question is whether a momentum tilt beats 60/40 after costs, bt is built for
it; if it is whether a five-minute breakout fills, it is the wrong library.
Strategies nest: a child is priced by running it on a notional $1,000,000 and handing its price series to the parent, so a portfolio of strategies is the same object as a portfolio of securities.
Pricing
Free, MIT-licensed, nothing to buy: no pro build, no hosted tier, no data bundle.
pip install bt is the entire product.
Data & coverage
bt ships no market data. The only bundled fetcher is bt.get, re-exported from ffn, which pulls
Yahoo Finance adjusted close via yfinance; everything else you load yourself, from a CSV or a
market data API. Instrument modelling is specific rather than
generic: Security for equities and ETFs, CouponPayingSecurity and FixedIncomeStrategy for bonds,
per-security multipliers and a Margin algo for futures. Markets are whatever your price series
covers.
Integrations
ffn is the companion library by the same author, and the coupling is tight: bt depends on
ffn>=1.1.2, bt.Result subclasses ffn.GroupStats, and the stats table, the plots and
to_csv come from there. Python 3.9 or newer, with core.py cythonized and shipped as platform
wheels. Repository state on 13 September 2026: release v1.2.3 on 11 September, last commit to
master on 12 September, not archived, 13 open issues.
Limitations
- No live trading and no broker. Nothing in the source routes an order.
- One price per row: a fill happens at the bar's price, with no intrabar sequencing. A bid/offer
spread is modelled only if you hand the backtest a
bidofferframe alongside the prices, in which case half the spread is charged on each trade; otherwise slippage is whatever cost model you supply. - No options — no pricing model, no greeks, no chain handling.
- Positions are integers by default, which quietly skips allocations a small account could not
fill; fractional shares need
integer_positions=False. - PyPI still classifies it Development Status :: 4 - Beta after twelve years.
Alternatives
backtrader and Backtesting.py for event-driven, signal-level testing; vectorbt where speed over large parameter sweeps matters more than portfolio structure. For the statistics without the simulation, ffn alone is the smaller dependency.
Specs
- Interfaces
- Python, Python
- Export
- CSV
- Asset classes
- Stocks, ETF, Bonds, Futures
- Markets
- Global
- Platforms
- Library
- AI features
- None
- Capabilities
- Backtesting
- Pricing verified
- Capabilities verified
- Coverage verified
Also from Philippe Morissette
Also worth comparing
- Backtesting.py — A single-instrument Python backtester — one OHLC series, one strategy, no live trading.
- Backtrader — An event-driven Python backtester with 122 indicators, frozen since April 2023.
- fastquant — A one-call wrapper over Backtrader, dormant since 2023 and broken on PyPI.
- QSTrader — An institutional-shaped Python backtester whose last commit to master was June 2024.
- Zipline-reloaded — The maintained fork of Quantopian's Zipline. Bring your own data — it ships almost none.
- AmiBroker — Windows portfolio backtester scripted in AFL, sold as a perpetual licence.
Named as a replacement for
FAQ
Is bt still maintained?
Yes, and unusually actively for a twelve-year-old library. Version 1.2.3 shipped on 11 September 2026, the last commit to master landed 12 September 2026, and the repository is not archived. The 1.2.1 release alone merged a dozen pull requests from seven first-time contributors, so issues are being answered by more than one person.
Can bt trade live or connect to a broker?
No. There is no broker integration, no order routing and no live loop anywhere in the source — the words broker and live trading do not appear in it. The internal paper-trade flag is not a broker paper account; it is how a nested child strategy is priced, by running it on a notional one million dollars.
What data does bt need, and does it come with any?
It needs a pandas DataFrame of prices indexed by date. The only bundled fetcher is bt.get, an alias for ffn.get, which downloads Yahoo Finance adjusted close through yfinance. Any other source you load yourself, and the framework does not care which.
How is bt different from backtrader or Backtesting.py?
Those model a trade lifecycle — signal, order, fill, stop. bt models a weight vector — which securities to hold, at what weights, rebalanced on what schedule. If your strategy is expressed as a target allocation rather than an entry and an exit, bt fits it directly and the others make you simulate it.