bt

Python backtesting for allocation and rebalancing rules, not entries and exits.

by Philippe Morissette

Last updated

From
Free
Licence
MIT
Self-hosted
Yes
Platforms
Library

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 bidoffer frame 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.pyA single-instrument Python backtester — one OHLC series, one strategy, no live trading.
  • BacktraderAn event-driven Python backtester with 122 indicators, frozen since April 2023.
  • fastquantA one-call wrapper over Backtrader, dormant since 2023 and broken on PyPI.
  • QSTraderAn institutional-shaped Python backtester whose last commit to master was June 2024.
  • Zipline-reloadedThe maintained fork of Quantopian's Zipline. Bring your own data — it ships almost none.
  • AmiBrokerWindows 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.