Strategy class is the abstract base class for every trading strategy in backtesting.py. You extend it, declare your indicators, and implement your decision logic. The engine calls your methods at the right time during the simulation.
Overview
Every strategy must subclassStrategy and override exactly two abstract methods:
| Method | When called | What to do |
|---|---|---|
init() | Once, before simulation starts | Declare indicators, precompute arrays |
next() | Once per bar (candle) | Read data, place or close orders |
Strategy parameters
Define tunable parameters as class-level variables. The engine injects the correct values when running or optimizing.The init() method
init() is called once before the simulation begins. Use it to precompute anything that can be calculated in a vectorized fashion — primarily indicators.
Call super().init() if composing strategies
If your strategy extends a composable base from
backtesting.lib (such as TrailingStrategy), call super().init() first so the parent class can set up its own indicators.Declare indicators with self.I()
Wrap every indicator function with In
self.I(). This tells the engine to gradually reveal the indicator values bar-by-bar during the simulation, matching self.data behavior.init(), self.data arrays are available at full length, which is what indicator libraries need to compute the full result array.The next() method
next() is called once for each bar (candle) in the dataset, after the indicator warm-up period. It receives no arguments — all data is accessed through self.data and your declared indicator attributes.
next(), self.data arrays are sliced to only the current bar and all prior bars. The last element ([-1]) is always the most recent (current) value.
If you extend a composable strategy from
backtesting.lib, call super().next() to let the parent class run its own logic.Declaring indicators: self.I()
self.I(func, *args, **kwargs) wraps an indicator function so the framework can plot it and reveal its values gradually bar-by-bar.
func is any callable that returns a NumPy array (or tuple of arrays) of the same length as self.data.Close. All positional and keyword arguments after the function are forwarded to it.
Parameters
A function that accepts the data arguments and returns a NumPy array of the same length as the input data. For example,
ta.SMA, ta.MACD, or your own function.*args
Positional arguments forwarded to
func. Typically the price series and any window size.Label shown in the plot legend. If
func returns multiple arrays (e.g. MACD), pass a list of strings. Defaults to the function name with arguments.Whether to include this indicator in the plot.
If
True, draws the indicator on top of the price chart (suitable for moving averages). If False, draws it in a separate panel below. Defaults to a heuristic based on value range.A hex RGB color (
"#1a7f4b") or X11 color name ("red"). Defaults to the next available color in the palette.If
True, plots the indicator as circles instead of a connected line.Examples
- Simple moving average
- Named indicator
- Overlay vs panel
- Custom function
Strategy properties
The following attributes are available inside bothinit() and next():
self.data
The price data, as a custom _Data structure with Open, High, Low, Close, and Volume arrays. In init(), the full array is available. In next(), only the current bar and all prior bars are visible.
self.equity
Current account equity: cash plus the market value of all open positions.
self.position
The current aggregate position. See Position.
self.orders
A tuple of pending Order objects waiting to be filled. See Order.
self.trades
A tuple of currently active Trade objects. See Trade.
self.closed_trades
A tuple of all settled Trade objects since the start of the backtest.
Placing orders
self.buy()
Place a long order and return the Order object.
self.sell()
Place a short order and return the Order object.
Order size. If between 0 and 1 (exclusive), interpreted as a fraction of available equity. If 1 or greater, interpreted as an absolute number of units. Defaults to nearly the full available equity.
Limit price. If set, creates a limit order that fills when the market reaches this price. For long orders, fills when price falls to or below this value. For short orders, fills when price rises to or above it.
Stop price that activates the order. Once hit, the order becomes a market order (stop-market) or limit order (stop-limit, if
limit is also set).Stop-loss price. When the order fills, a contingent stop-market order is automatically placed at this price to close the resulting trade.
Take-profit price. When the order fills, a contingent limit order is automatically placed at this price to close the resulting trade.
An arbitrary value attached to the order and the resulting trade, useful for tracking or conditional logic.
Unless
trade_on_close=True, market orders fill on the next bar’s open. Limit and stop orders fill when their price condition is met during a subsequent bar.Closing positions
To exit a trade, useTrade.close() or Position.close() rather than placing a counter order: