Skip to content
python.financial
Platform
Backtesting framework
License
GPL-3.0-or-later
Pricing
Free and open source
Live trading
Broker integrations exist but require independent validation
Best for
Maintaining existing Backtrader code or running small stateful, bar-based simulations

Backtrader makes the most sense when maintaining an existing Backtrader strategy or building a small, stateful simulation around its strategy and broker objects. It can coordinate several data feeds through one broker, simulate common order types, apply commission and slippage rules, resample data, and attach analyzers. The main concern is maintenance: the official package and repository have not changed since April 2023.

How does Backtrader work?

A Cerebro engine owns the broker, data feeds, strategy classes, analyzers, and run configuration. A strategy subclasses bt.Strategy, creates indicators in __init__(), and handles each newly available bar in next(). Indicators expose time-indexed "lines," so self.data.close[0] is the current value and negative indexes refer to earlier values.

The strategy and broker move through time one bar at a time. Backtrader can preload data and calculate many indicators in a batch, but strategy decisions and orders still run through Python for every bar. This makes rules that depend on earlier trades easy to write, but large parameter searches can be slow.

Minimal Backtrader example

This complete example creates deterministic daily OHLCV data in memory. The strategy buys ten units when a 5-day simple moving average crosses above a 15-day average and closes the position on the reverse crossover. It applies 0.1% commission and 0.05% percentage slippage.

import math

import backtrader as bt
import pandas as pd

index = pd.date_range("2025-01-01", periods=120, freq="D")
close = [100 + 0.05 * i + 3 * math.sin(i / 4) for i in range(len(index))]
prices = pd.DataFrame(
    {
        "open": close,
        "high": [price + 0.5 for price in close],
        "low": [price - 0.5 for price in close],
        "close": close,
        "volume": 1_000,
    },
    index=index,
)


class SmaCross(bt.Strategy):
    params = (("fast", 5), ("slow", 15))

    def __init__(self):
        fast = bt.ind.SMA(self.data.close, period=self.p.fast)
        slow = bt.ind.SMA(self.data.close, period=self.p.slow)
        self.cross = bt.ind.CrossOver(fast, slow)

    def next(self):
        if not self.position and self.cross > 0:
            self.buy(size=10)
        elif self.position and self.cross < 0:
            self.close()


cerebro = bt.Cerebro()
cerebro.adddata(bt.feeds.PandasData(dataname=prices))
cerebro.addstrategy(SmaCross)
cerebro.broker.setcash(10_000)
cerebro.broker.setcommission(commission=0.001)
cerebro.broker.set_slippage_perc(perc=0.0005)
cerebro.run()
print(f"Final equity: {cerebro.broker.getvalue():.2f}")

This code was executed with Python 3.11.8 and Backtrader 1.9.78.123 on September 19, 2026. It printed final equity of 9,948.11. The synthetic series and toy strategy test the API only. They do not demonstrate a trading edge or represent the costs and liquidity of a real instrument.

What can the broker simulation represent?

Area Built-in behavior Research implication
Multiple instruments Several feeds can advance through one strategy and share one simulated broker. Synchronization, stale bars, calendars, and portfolio sizing still need deliberate rules.
Orders Market, close, limit, stop, and stop-limit execution are documented. Validity dates, trailing stops, bracket orders, and order cancellation are also available. Bar data cannot reveal queue position or every intrabar price path.
Commission and financing Percentage or fixed commissions, futures multipliers and margin, leverage, and credit interest can be configured per instrument. Broker schedules, tiering, borrow availability, and changing funding rates may require a custom CommissionInfo.
Slippage The simulated broker accepts fixed-point or percentage slippage with controls for opening prices, limit caps, bar matching, and fills outside the bar. A constant adjustment is an assumption, not a liquidity model. Volume fillers must be configured separately.
Data and analysis CSV, pandas, resampling, replay, multiple timeframes, indicators, observers, and analyzers are built in. Data quality, point-in-time constituents, corporate actions, and exchange calendars remain user responsibilities.

The official order execution documentation states that the current bar has already happened and normally cannot fill a newly created order. A market order therefore uses the next available price, typically the next bar's open. "Cheat on open" and "cheat on close" modes deliberately change that timing. Use them only when the strategy could actually submit the order before the modeled price became unavailable.

Backtrader's slippage controls and commission schemes are more detailed than a single fee percentage. They still do not infer market impact, queue position, latency, or available borrow from OHLCV data. Those limitations should be explicit in any result.

Where is Backtrader still useful?

  • Stateful strategy code. Orders, positions, indicators, timers, and several feeds are available to each callback, which suits rules that depend on portfolio state or a sequence of events.
  • Configurable simulation. The broker API covers more order, commission, slippage, margin, and short-interest settings than many small research libraries.
  • Existing systems and reference material. The official documentation, source samples, and older community discussions remain useful when a team already owns Backtrader code.
  • Few required dependencies. The core package is pure Python. Plotting and some data or broker integrations add their own dependencies.

What should a new project consider?

  • Inactive upstream. There has been no official release or repository commit after April 19, 2023. Compatibility fixes in forks or pull requests are not part of the package installed from PyPI.
  • Old compatibility metadata. PyPI classifiers stop at Python 3.7 even though the current wheel imported and ran under Python 3.11.8 in this review. Treat newer Python and dependency combinations as configurations to test, not versions promised by current upstream metadata.
  • Python-level scaling costs. A readable event loop can be adequate for a few bar-based simulations. Large universes, tick data, and repeated optimization multiply callback and object-management work. Benchmark the actual workload before choosing the engine.
  • Legacy live integrations. The repository includes stores for brokers and platforms such as Interactive Brokers, OANDA, and Visual Chart. Their presence does not prove compatibility with current third-party APIs. Validate authentication, order semantics, reconnection, and reconciliation in a paper environment before considering live use.
  • GPL obligations. The official repository is licensed under GPL version 3 or later. Review distribution and modification obligations with appropriate counsel for a commercial deployment.

Should you use Backtrader?

Use Backtrader when you have an existing codebase, require its particular broker model, or can own compatibility testing and maintenance. For a new project, compare it with an actively maintained engine using your data volume, portfolio structure, order assumptions, and deployment target. A familiar API and an old tutorial archive do not compensate for an upstream dependency that your team cannot support.

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