4. 策略基类:Strategy 类结构、next 方法、init 方法、notify_order / notify_trade 回调
Backtrader 的策略基类 Strategy 是所有自定义策略的父类。理解其类结构、生命周期方法以及回调机制,是编写正确回测脚本的核心前提。本节将拆解 Strategy 的骨架,并重点说明 init、next、notify_order 和 notify_trade 四个关键入口。
4.1 Strategy 类结构总览
一个标准的策略类继承自 bt.Strategy,通常包含以下组成部分:
| 组成部分 | 调用时机 | 核心职责 |
|---|---|---|
__init__ |
策略初始化时(仅一次) | 定义指标、设置变量、绑定数据引用 |
next |
每个 bar 触发一次 | 实现核心交易逻辑:判断信号、下单 |
notify_order |
订单状态变化时 | 跟踪订单提交、成交、取消、拒绝 |
notify_trade |
交易(持仓)开/平/更新时 | 记录盈亏、管理交易生命周期 |
stop |
回测结束时(可选) | 收尾统计、输出最终结果 |
关键认知:
init 只执行一次,用于准备;next 逐 bar 执行,是策略引擎的“心脏”;notify_order 和 notify_trade 是异步回调,不阻塞 next 的执行顺序,但提供订单和交易的实时状态反馈。
4.2 init 方法:策略的“构造函数”
__init__ 在回测启动时被调用一次,主要完成以下工作:
- 绑定数据线: 通过
self.datas[0]或self.data.close访问价格序列。 - 定义指标: 使用
bt.indicators.SMA、RSI等内置指标,并赋值给self.sma等实例变量。 - 设置参数: 从
params中读取用户传入的参数,如均线周期、止损比例。 - 初始化状态变量: 如订单引用、持仓标记、计数器等。
class MyStrategy(bt.Strategy):
params = (('period', 20),)
def __init__(self):
# 绑定收盘价
self.close = self.datas[0].close
# 定义均线指标
self.sma = bt.indicators.SMA(self.close, period=self.params.period)
# 初始化订单引用
self.order = None
self.trade_count = 0
提示: 在
init 中定义的指标会自动参与回测的预计算,next 方法可以直接使用 self.sma[0] 获取当前 bar 的指标值,无需手动更新。
4.3 next 方法:逐 bar 交易引擎
next 是策略的核心循环体,每个 bar 都会执行一次。典型的 next 逻辑包含:
- 检查持仓状态: 通过
self.position判断当前是否持有头寸。 - 生成交易信号: 比较当前价格、指标值、持仓状态,决定买入、卖出或持有。
- 下单执行: 使用
self.buy()、self.sell()、self.close()等方法提交订单。 - 避免重复下单: 检查
self.order是否为None,防止 pending 订单未完成时再次下单。
def next(self):
# 避免在已有未完成订单时重复下单
if self.order:
return
# 未持仓:买入信号
if not self.position:
if self.close[0] > self.sma[0]:
self.order = self.buy()
# 已持仓:卖出信号
else:
if self.close[0] < self.sma[0]:
self.order = self.sell()
常见陷阱:
next 中不要使用 while 循环或长时间阻塞操作;不要假设 self.datas[0].close[0] 一定存在(回测初期可能无数据);务必在 next 中处理 len(self) 不足的情况,或使用 if len(self) < self.params.period: return 跳过预热期。
4.4 notify_order 回调:订单状态跟踪
当订单状态发生变化时(提交、部分成交、全部成交、取消、拒绝),Backtrader 自动调用 notify_order。该方法接收一个 Order 对象,常用属性包括:
| Order 属性 | 类型 | 说明 |
|---|---|---|
status |
int | 订单状态码:Created、Submitted、Accepted、Partial、Completed、Canceled、Rejected |
executed.price |
float | 成交均价(仅当状态为 Completed 或 Partial 时有效) |
executed.size |
int | 成交数量 |
executed.value |
float | 成交金额 |
executed.comm |
float | 佣金 |
def notify_order(self, order):
if order.status in [order.Submitted, order.Accepted]:
# 订单已提交/接受,等待成交
return
if order.status in [order.Completed]:
if order.isbuy():
self.log(f'买入成交,价格={order.executed.price:.2f}')
else:
self.log(f'卖出成交,价格={order.executed.price:.2f}')
# 重置订单引用,允许 next 再次下单
self.order = None
elif order.status in [order.Canceled, order.Rejected]:
self.log(f'订单失败,状态={order.status}')
self.order = None
最佳实践: 在
notify_order 中始终将 self.order 重置为 None(无论成功或失败),否则 next 中的 if self.order: return 会永久阻塞后续下单。
4.5 notify_trade 回调:交易生命周期管理
notify_trade 在交易(持仓)开仓、平仓或持仓更新时被调用。它接收一个 Trade 对象,常用属性包括:
| Trade 属性 | 说明 |
|---|---|
status |
交易状态:Created、Open、Closed |
pnl |
当前浮动盈亏(未平仓)或最终盈亏(已平仓) |
pnlcomm |
扣除佣金后的净盈亏 |
size |
持仓数量(正数为多头,负数为空头) |
price |
开仓均价 |
commission |
累计佣金 |
def notify_trade(self, trade):
if not trade.isclosed:
# 交易未平仓,只记录开仓信息
return
self.log(f'交易平仓,毛盈亏={trade.pnl:.2f},净盈亏={trade.pnlcomm:.2f}')
self.trade_count += 1
使用场景:
notify_trade 适合做交易级别的统计(胜率、盈亏比、最大回撤),而 notify_order 更适合做订单级别的日志和风控(如撤单重试、滑点记录)。
4.6 策略生命周期与回调协作流程
下图展示了从回测启动到结束,init、next、notify_order、notify_trade 之间的协作关系:
4.7 完整策略骨架示例
将上述四个方法组合成一个可运行的策略骨架:
import backtrader as bt
class SmaCrossStrategy(bt.Strategy):
params = (('fast', 10), ('slow', 30))
def __init__(self):
self.close = self.datas[0].close
self.fast_sma = bt.indicators.SMA(self.close, period=self.params.fast)
self.slow_sma = bt.indicators.SMA(self.close, period=self.params.slow)
self.order = None
self.trade_log = []
def next(self):
if self.order:
return
if not self.position:
if self.fast_sma[0] > self.slow_sma[0]:
self.order = self.buy()
else:
if self.fast_sma[0] < self.slow_sma[0]:
self.order = self.sell()
def notify_order(self, order):
if order.status in [order.Completed]:
self.order = None
elif order.status in [order.Canceled, order.Rejected]:
self.order = None
def notify_trade(self, trade):
if trade.isclosed:
self.trade_log.append({
'pnl': trade.pnl,
'pnlcomm': trade.pnlcomm,
'size': trade.size,
'price': trade.price
})
总结:
init 搭骨架,next 做决策,notify_order 管订单,notify_trade 管交易。四个方法各司其职,共同构成 Backtrader 策略的完整生命周期。掌握这四者的协作关系,是后续编写复杂策略(多数据、多时间框架、动态仓位管理)的基础。