Skip to content
python.financial
Platform
Backtesting library
License
AGPL-3.0
Pricing
Free and open source
Live trading
Not supported
Best for
Quick bar-based tests of entry and exit rules on one instrument

Backtesting.py is a good fit when you want to test entry and exit rules on one instrument without building a simulation engine first. A strategy is a small Python class, the input is an OHLC or OHLCV pandas DataFrame, and one run returns trades, equity, performance statistics, and an interactive chart. It is less suitable when positions in several instruments must compete for the same cash or when fills depend on quotes, order-book depth, or exchange latency.

How does Backtesting.py work?

You subclass Strategy and implement two methods. init() precomputes indicators, usually with NumPy or pandas through Strategy.I(). next() runs once for each newly revealed bar and makes trading decisions from the data available at that point. The official quick-start guide explains an important fill assumption: a market order normally executes at the next bar's open. Setting trade_on_close=True moves that fill to the current bar's close.

Each Backtest instance receives one price table and maintains one cash account. The library's MultiBacktest wrapper can run the same strategy independently over several datasets in parallel. It does not model a portfolio in which several symbols share cash, margin, or allocation constraints.

Minimal moving-average example

This complete example uses the sample daily GOOG data distributed with the package. It closes an existing position before reversing direction, charges 0.2% commission at entry and exit, and closes any open trade on the final bar so that it appears in the statistics.

import pandas as pd
from backtesting import Backtest, Strategy
from backtesting.lib import crossover
from backtesting.test import GOOG


def sma(values, period):
    return pd.Series(values).rolling(period).mean()


class SmaCross(Strategy):
    fast_period = 10
    slow_period = 20

    def init(self):
        self.fast = self.I(sma, self.data.Close, self.fast_period)
        self.slow = self.I(sma, self.data.Close, self.slow_period)

    def next(self):
        if crossover(self.fast, self.slow):
            self.position.close()
            self.buy()
        elif crossover(self.slow, self.fast):
            self.position.close()
            self.sell()


backtest = Backtest(
    GOOG,
    SmaCross,
    cash=10_000,
    commission=0.002,
    exclusive_orders=True,
    finalize_trades=True,
)
stats = backtest.run()
print(stats[["Return [%]", "# Trades", "Max. Drawdown [%]"]])
backtest.plot()

The non-plotting portion was executed with Backtesting.py 0.6.6 on September 19, 2026 and completed with 94 trades. The sample result is a software check, not evidence that a moving-average crossover has a tradable edge. The bundled dataset, bar frequency, commission assumption, and lack of spread or slippage limit what the result can say.

What can it model?

The Backtest API documents the main controls:

Area Built-in behavior What still needs care
Data Open, high, low, and close columns are required. Volume is optional, and custom columns are allowed. You supply and validate the data. Point-in-time membership and corporate-action handling are outside the engine.
Orders Market, limit, stop, stop-loss, and take-profit prices are supported. Hedging and exclusive-order modes are configurable. New decisions occur once per complete bar. The engine cannot reconstruct the sequence of prices inside a candle.
Costs spread models a constant relative bid-ask spread. commission accepts a rate, a fixed-plus-relative tuple, or a callable. Slippage, market impact, borrow fees, funding, and latency need explicit custom assumptions.
Leverage margin sets one required-margin ratio. Initial and maintenance margin are not modeled separately. Liquidation rules require custom work.
Research Grid or model-based parameter optimization, heatmaps, trade records, statistics, and Bokeh charts are included. Choosing the best in-sample result can overfit. Use out-of-sample tests and account for repeated trials.

Stop-loss and take-profit orders are contingent, good-till-canceled orders. There is no general day, immediate-or-cancel, fill-or-kill, or order-book queue model. Read the library's behavior alongside the order types used in backtests before treating a bar-level fill as executable.

Where does it work well?

  • A compact API. The strategy class keeps indicator setup and per-bar decisions in two predictable methods.
  • Useful inspection tools. Backtest.run() returns a pandas Series with trade and risk statistics. Backtest.plot() creates an interactive Bokeh report with price, trades, profit and loss, equity, and optional drawdown panels.
  • Cost inputs that cover common prototypes. A spread, fixed or proportional commissions, maker rebates, and custom commission functions are available without replacing the broker simulation.
  • Small-scale optimization. Constrained grid search and SAMBO model-based search are built in. Both should be paired with out-of-sample validation rather than used to select the highest historical score blindly.

What are its limits?

  • No shared multi-asset portfolio. Independent runs across symbols are useful for comparison, but they do not answer allocation, rotation, or cross-asset margin questions.
  • Bar data hides intrabar order. If a bar crosses several order prices, the recorded OHLC values may not reveal which event happened first. Finer data or a more detailed simulator is necessary when that order changes the outcome.
  • Execution costs are not automatic. A zero-cost default is convenient for an API demo but optimistic for research. Set commission and spread, then test additional transaction-cost and slippage assumptions outside the built-in constant-spread model.
  • No built-in live-trading system. Backtesting.py produces research results. Broker connectivity, order reconciliation, monitoring, and recovery belong in a separate execution layer.
  • The license affects some deployments. Backtesting.py uses the GNU Affero General Public License v3. If you modify the covered program and let users interact with that modified version over a network, AGPL section 13 requires an offer of the corresponding source to those users. This page is not legal advice, so review the license for the actual deployment.

When should you choose Backtesting.py?

Choose it for a readable first implementation of a bar-based strategy on one instrument, especially when interactive trade inspection matters. Choose a portfolio-oriented engine when symbols must share capital. Choose an execution simulator when queue position, partial fills, latency, borrow availability, or order-book liquidity drives the result. Backtesting.py can answer whether code behaves as specified under explicit bar-level assumptions. It cannot establish that a strategy will remain profitable after real trading frictions.

Choose which optional services may run. You can change these settings at any time.