title: Strategy API description: Complete Strategy class API reference
Strategy API¶
The Strategy class is the base class for all user-defined trading strategies in Backtrader. It provides order management, position tracking, indicator integration, and event-driven execution.
Class Definition¶
class backtrader.Strategy:
"""Base class for trading strategies."""
```bash
## Parameters
### `params`
Tuple of parameter definitions for the strategy.
```python
class MyStrategy(bt.Strategy):
params = (
('period', 20),
('threshold', 1.5),
)
```bash
Access parameters via `self.p.parameter_name` or `self.params.parameter_name`.
## Core Methods
### `__init__(self)`
Called once before backtesting starts. Use to initialize indicators and calculations.
```python
def __init__(self):
super().__init__() # Always call super first
self.sma = bt.indicators.SMA(self.data.close, period=self.p.period)
```bash
### `start(self)`
Called before backtesting begins, after initialization is complete.
```python
def start(self):
self.initial_cash = self.broker.getcash()
```bash
### `prenext(self)`
Called for each bar before minimum period is reached.
### `nextstart(self)`
Called once when minimum period is first reached.
### `next(self)`
Called for each bar after minimum period is reached. Contains main trading logic.
```python
def next(self):
if self.data.close[0] > self.sma[0]:
self.buy()
```bash
### `stop(self)`
Called after backtesting ends.
```python
def stop(self):
final_value = self.broker.getvalue()
print(f'Final Portfolio Value: {final_value}')
```bash
## Order Methods
### `buy(self, **kwargs)`
Create a buy order.
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `data` | Data | None | Data feed to trade |
| `size` | float | None | Position size (positive) |
| `price` | float | None | Limit price |
| `plimit` | float | None | Limit price for stop-limit |
| `stoplimit` | float | None | Stop-limit activation price |
| `exectype` | Order.ExecType | None | Execution type |
| `valid` | Order.Valid | None | Validity period |
| `oco` | Order | None | One-cancels-other order |
```python
# Market order
order = self.buy()
# Limit order
order = self.buy(price=100.0)
# Specific size
order = self.buy(size=10)
# Stop-limit order
order = self.buy(stoplimit=95.0, price=94.5)
```bash
### `sell(self, **kwargs)`
Create a sell order. Same parameters as `buy()`.
```python
# Sell entire position
order = self.sell()
# Stop loss
order = self.sell(stop=95.0)
```bash
### `close(self, **kwargs)`
Close existing position. Same parameters as `buy()` but automatically determines size.
```python
# Close position
order = self.close()
# Close with limit price
order = self.close(price=105.0)
```bash
### `cancel(self, order)`
Cancel a pending order.
```python
self.cancel(order)
```bash
## Order Notification
### `notify_order(self, order)`
Called when order status changes.
```python
def notify_order(self, order):
if order.status in [order.Submitted, order.Accepted]:
return
if order.status == order.Completed:
if order.isbuy():
self.log(f'BUY EXECUTED, Price: {order.executed.price:.2f}')
else:
self.log(f'SELL EXECUTED, Price: {order.executed.price:.2f}')
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log(f'Order {order.getstatusname()}')
```bash
- *Order Status Values**:
| Status | Description |
|--------|-------------|
| `Order.Created` | Order created |
| `Order.Submitted` | Submitted to broker |
| `Order.Accepted` | Accepted by broker |
| `Order.Partial` | Partially filled |
| `Order.Completed` | Fully filled |
| `Order.Canceled` | Canceled |
| `Order.Margin` | Margin insufficient |
| `Order.Rejected` | Rejected |
## Trade Notification
### `notify_trade(self, trade)`
Called when a trade is closed.
```python
def notify_trade(self, trade):
if not trade.isclosed:
return
self.log(f'Trade P&L: {trade.pnl:.2f}, Commission: {trade.commission:.2f}')
```bash
- *Trade Attributes**:
| Attribute | Description |
|-----------|-------------|
| `trade.pnl` | Gross profit/loss |
| `trade.pnlcomm` | Net profit/loss (after commission) |
| `trade.commission` | Commission paid |
| `trade.isclosed` | Whether trade is closed |
## Position Management
### `position`
Access position information for a data feed.
```python
# Get position for current data
position = self.position
# Get position for specific data
position = self.getposition(data)
# Check if has position
if self.position:
size = self.position.size
price = self.position.price
```bash
- *Position Attributes**:
| Attribute | Type | Description |
|-----------|------|-------------|
| `size` | float | Current position size (positive=long, negative=short) |
| `price` | float | Average entry price |
| `price_adj` | float | Adjusted price (for stocks) |
### `getposition(self, data=None, broker=None)`
Get position object for specific data feed.
```python
position = self.getposition(self.datas[1])
```bash
## Data Access
### `data` / `datas`
Access data feeds in the strategy.
```python
# Current (first) data feed
price = self.data.close[0]
# Access by index
price1 = self.datas[0].close[0]
price2 = self.datas[1].close[0]
# Access by name if specified
price = self.aapl.close[0]
```bash
### `getdatabyname(self, name)`
Get data feed by name.
```python
data = self.getdatabyname('AAPL')
```bash
## Broker Access
### `broker`
Access broker methods.
```python
cash = self.broker.getcash()
value = self.broker.getvalue()
```bash
- *Common Broker Methods**:
| Method | Description |
|--------|-------------|
| `getcash()` | Get available cash |
| `getvalue()` | Get portfolio value |
| `getposition(data)` | Get position for data |
| `setcash(amount)` | Set cash amount |
## Indicator Integration
Indicators defined in `__init__` are automatically calculated and updated.
```python
def __init__(self):
self.sma20 = bt.indicators.SMA(self.data.close, period=20)
self.sma50 = bt.indicators.SMA(self.data.close, period=50)
self.crossover = bt.indicators.CrossOver(self.sma20, self.sma50)
def next(self):
if self.crossover > 0:
self.buy()
```bash
## Logging
### `log(self, msg, dt=None)`
Log messages with timestamp.
```python
def next(self):
self.log(f'Close: {self.data.close[0]:.2f}')
```bash
## Strategy Lifecycle
```mermaid
stateDiagram-v2
[*] --> __init__: Strategy Created
__init__ --> start: Initialization Complete
start --> prenext: Backtest Starts
prenext --> prenext: minperiod not reached
prenext --> nextstart: minperiod reached
nextstart --> next: First valid bar
next --> next: Processing bars
next --> stop: Backtest ends
stop --> [*]: Cleanup
```bash
## Multiple Data Feeds
```python
class MyStrategy(bt.Strategy):
def __init__(self):
# Access multiple data feeds
self.data0 = self.datas[0] # First data
self.data1 = self.datas[1] # Second data
def next(self):
# Trade based on both data feeds
if self.data0.close[0] > self.data1.close[0]:
self.buy(data=self.data0)
```bash
## Timer Events
### `notify_timer(self, timer, when)`
Called when a timer event fires.
```python
def __init__(self):
# Add timer
self.add_timer(
when=datetime.time(hour=14, minute=30),
allow=True
)
def notify_timer(self, timer, when):
self.log(f'Timer fired at {when}')
```bash
## Data Events
### `notify_data(self, data, status, *args, **kwargs)`
Called when data status changes.
```python
def notify_data(self, data, status, *args, **kwargs):
if status == data.LIVE:
self.log(f'{data._name} is now LIVE')
```bash
## Signal Strategy
For signal-based trading, use `SignalStrategy`:
```python
class MySignalStrategy(bt.SignalStrategy):
params = (('period', 20),)
def __init__(self):
self.sma = bt.indicators.SMA(self.data.close, period=self.p.period)
self.signal_add(bt.SIGNAL_LONG, self.data.close > self.sma)
```bash
## Full Example
```python
import backtrader as bt
class MyStrategy(bt.Strategy):
"""
Sample moving average crossover strategy.
"""
params = (
('fast_period', 10),
('slow_period', 30),
)
def __init__(self):
super().__init__()
self.fast_ma = bt.indicators.SMA(self.data.close, period=self.p.fast_period)
self.slow_ma = bt.indicators.SMA(self.data.close, period=self.p.slow_period)
self.crossover = bt.indicators.CrossOver(self.fast_ma, self.slow_ma)
self.order = None
def next(self):
if self.order:
return
if not self.position:
if self.crossover > 0:
self.order = self.buy()
else:
if self.crossover < 0:
self.order = self.sell()
def notify_order(self, order):
if order.status in [order.Submitted, order.Accepted]:
return
if order.status == order.Completed:
if order.isbuy():
self.log(f'BUY EXECUTED: {order.executed.price:.2f}')
else:
self.log(f'SELL EXECUTED: {order.executed.price:.2f}')
self.order = None
def notify_trade(self, trade):
if trade.isclosed:
self.log(f'Trade P&L: {trade.pnl:.2f}')
def stop(self):
self.log(f'Final Value: {self.broker.getvalue():.2f}')
```bash
## Next Steps
- [Indicators API](indicator.md) - Indicator development
- [Analyzers API](analyzer.md) - Performance analysis
- [Data Feeds API](data-feeds.md) - Data sources