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 逻辑包含:

  1. 检查持仓状态: 通过 self.position 判断当前是否持有头寸。
  2. 生成交易信号: 比较当前价格、指标值、持仓状态,决定买入、卖出或持有。
  3. 下单执行: 使用 self.buy()、self.sell()、self.close() 等方法提交订单。
  4. 避免重复下单: 检查 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 之间的协作关系:

Strategy 生命周期与回调协作流程 __init__ next (逐 bar) self.buy() / self.sell() notify_order notify_trade stop (可选) 下一个 bar 重置 order=None 回测结束 说明 • init:只执行一次,准备指标和变量 • next:逐 bar 执行,核心交易逻辑 • 回调不阻塞 next 执行顺序

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 策略的完整生命周期。掌握这四者的协作关系,是后续编写复杂策略(多数据、多时间框架、动态仓位管理)的基础。