Backtesting.py
A single-instrument Python backtester — one OHLC series, one strategy, no live trading.
by Zach Lûster
Last updated
What it is
A Python library of about 3,900 lines — 1,800 of them the engine itself — that takes one
OHLC(V) DataFrame and one Strategy subclass, walks the bars, and returns a pandas Series of
statistics — return, CAGR, Sharpe, Sortino, Calmar, max drawdown, win rate, profit factor, SQN —
plus the trade list and an interactive Bokeh chart of the equity curve and fills. Two classes
and about a dozen keyword arguments is the whole surface, and that is the point.
The engine is event-driven per bar. Market orders fill at the next bar's open unless you set
trade_on_close=True; limit, stop and stop-limit orders fill when the bar's range touches them.
spread, commission (a rate, a (fixed, relative) tuple, or a callable on size and price),
margin, hedging and exclusive_orders are the entire cost and position model.
Indicators are declared in init() and computed once across the whole series — self.I() refuses
anything that is not an array as long as the data — so an indicator never sees the state the
simulation is in, and anything that depends on an open position is written by hand in next().
The run also does not begin until every declared indicator is non-NaN, which quietly costs a
200-bar moving average the first 200 bars of the sample.
Pricing
Free, with nothing to buy — no pro build, no hosting, no data bundle, just a GitHub Sponsors link. The cost is the licence: AGPL-3.0-or-later is stronger copyleft than most Python quant libraries carry, and it is the thing to check before this goes near a product.
Data & coverage
Ships no market data beyond three sample sets used in the documentation. You supply the
DataFrame — Open, High, Low, Close, optionally Volume, on a datetime or plain range
index, extra columns readable from the strategy. Any instrument, any market, any bar size works,
because the engine never learns what the instrument is.
Integrations
Indicator-library-agnostic: self.I() wraps any callable returning an array, so TA-Lib,
pandas-ta or your own NumPy function work unchanged. Optimisation is grid search or the SAMBO
model-based optimiser, run across processes, with a heatmap of the parameter space. NumPy,
pandas and Bokeh; Python 3.9 and up.
Limitations
- No live trading and no paper trading. Not a broker interface nobody implemented — there is no interface.
- One instrument per backtest. No portfolio-level sizing, no rebalancing, no shared cash across symbols.
- Bar resolution caps the realism. When a contingent stop-loss or take-profit would fire in the same bar its parent stop or limit order became a trade, the library warns that it cannot assert the intra-candle path, defers to the next matching bar, and calls the resulting trade "somewhat dubious" in its own message.
- Whole units only, unless you wrap the run in
FractionalBacktest. - Volume is decoration. The column is optional, filled with NaN when absent, and the broker never reads it: an order fills in full at the price the bar touched whatever its size. No partial fills, no volume cap, no market impact.
- No borrow cost, no financing, no dividends. Beyond the spread and the commission, none of the three appears anywhere in the engine.
- An order the account cannot afford is cancelled, not reduced. Short of margin, the broker
drops it with a
UserWarning; a relative size (0 < size < 1) is floored to whole units of the margin available, and when that floors to zero the order simply goes away. On the defaultcash=10_000the library also warns at construction if any close exceeds the account. - No options and no multi-leg positions.
- Slow release cadence. 0.6.5 in July 2025, 0.6.6 in July 2026.
Alternatives
VectorBT for parameter sweeps at a scale this will not reach, bt for portfolio-level strategy composition, NautilusTrader when the strategy has to run live without a rewrite. Backtrader is the other name everyone offers; Backtesting.py's own alternatives list files it under "Obsolete / Unmaintained".
Specs
- Interfaces
- Python, Python
- Export
- None
- Asset classes
- Stocks, Futures, Forex, Crypto
- Markets
- Global
- Platforms
- Library
- AI features
- None
- Capabilities
- Backtesting
- Pricing verified
- Capabilities verified
- Coverage verified
Also worth comparing
- Backtrader — An event-driven Python backtester with 122 indicators, frozen since April 2023.
- bt — Python backtesting for allocation and rebalancing rules, not entries and exits.
- fastquant — A one-call wrapper over Backtrader, dormant since 2023 and broken on PyPI.
- 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.
- Blueshift — Free hosted Python backtesting with bundled minute data and broker execution.
FAQ
Can Backtesting.py trade live?
No. There is no broker connectivity of any kind in the library — no order routing, no paper-trading endpoint, no scheduler. A run ends with a pandas Series of statistics and an HTML plot, and getting from there to a live order is code you write yourself against a broker API.
Can it backtest a portfolio of several instruments?
No. A Backtest takes exactly one OHLC(V) DataFrame. The MultiBacktest wrapper added in 0.6.3 runs the same strategy over a list of datasets in parallel to compare the results per ticker; each run has its own cash and its own equity curve, so there is no cross-asset position sizing, no shared capital and no rebalancing.
Is Backtesting.py still maintained?
Yes, but slowly. The repository is not archived, the last commit to master is 5 August 2026, and 0.6.6 shipped on 22 July 2026 — a year after 0.6.5 in July 2025, and almost entirely bug fixes. 46 issues and 37 pull requests are open. The GitHub releases tab is empty and always has been — the project tags a version and pushes it to PyPI without ever cutting a GitHub release — so an empty releases page here is not the sign of death it usually is.
Does the AGPL licence matter for my strategy code?
It depends on what you do with it. Running backtests privately triggers nothing. Distributing a product built on the library, or offering one over a network, is where AGPL-3.0 asks for the corresponding source of your version — which is why commercial shops often reach for an MIT- or Apache-licensed engine instead.