Skip to content

热启动 (Warm Start) 指南

AKQuant 提供了强大的热启动 (Warm Start) 功能,允许你保存回测引擎的当前状态(快照),并在未来某个时间点恢复该状态继续运行。这对于长周期策略的分段回测、滚动训练(Rolling Window)以及模拟实盘环境非常有用。

1. 什么是热启动?

在传统的事件驱动回测中,每次运行都是从头开始(Cold Start),所有状态(持仓、资金、指标历史)都需要从零积累。

热启动允许你: 1. 保存 (Snapshot): 将引擎的当前内存状态(包括持仓、未成交订单、策略变量、指标状态等)序列化保存到磁盘文件。 2. 恢复 (Resume): 从磁盘文件加载状态,恢复引擎和策略,就像中间没有中断过一样,接着处理新的数据。

2. 基本用法

2.1 保存快照 (Phase 1)

在第一阶段回测结束时(或在策略逻辑中任意时刻),调用 save_snapshot 保存状态。

from akquant.checkpoint import save_snapshot

# 运行第一阶段回测
result1 = run_backtest(data=data_phase1, strategy=MyStrategy, ...)

# 保存快照到文件
checkpoint_file = "checkpoint_phase1.pkl"
save_snapshot(result1.engine, result1.strategy, checkpoint_file)
print(f"Snapshot saved to {checkpoint_file}")

2.2 恢复并继续运行 (Phase 2)

使用 run_warm_start 函数从快照恢复,并传入第二阶段的数据。

注意:快照仅保存了动态状态(Portfolio, Orders, Strategy Attributes),不包含 静态配置(Instrument, MarketModel)。因此在恢复时,你必须重新配置这些静态信息。

import akquant as aq

# 准备第二阶段数据
data_phase2 = ...

# 从快照恢复并运行
result2 = aq.run_warm_start(
    checkpoint_path="checkpoint_phase1.pkl",
    data=data_phase2,
    symbol="AAPL",  # 你的主要标的
    # 重要:必须重新传入市场费用配置,因为 MarketModel 不会被保存
    commission_rate=0.0003,
    stamp_tax=0.001,
    t_plus_one=True  # 如果是 A 股
)

3. 策略适配 (关键)

为了支持热启动,你的策略代码需要正确处理初始化 (Initialization)恢复 (Restoration) 的区别。

3.1 生命周期钩子

AKQuant 为策略提供了两个关键的启动钩子:

  • on_start(): 无论冷启动还是热启动,都会调用。用于通用初始化(如订阅行情)。
  • on_resume(): 仅在热启动时调用(在 on_start 之前)。用于恢复特定的连接或资源。

3.2 避免覆盖状态

最常见的错误是在 on_start 中无条件地重新初始化指标,导致从快照恢复的指标状态被覆盖(重置为 0)。

错误写法 ❌

def on_start(self):
    # 错误!如果从快照恢复,self.sma 已经有值了,这里会将其覆盖为新对象
    self.sma = SMA(30)
    self.subscribe(self.symbol)

正确写法 ✅

使用 self.is_restored 属性判断当前是否为恢复模式。

def on_start(self):
    # 1. 初始化指标 (仅在冷启动时)
    if not self.is_restored:
        self.sma = SMA(30)
        # 初始化其他非持久化状态...
    else:
        self.log("Resumed from snapshot. Indicators retained.")

    # 2. 注册指标 (必须执行,以便 Engine 知道需要更新它)
    self.register_indicator("sma", self.sma)

    # 3. 订阅行情 (必须执行,因为连接是临时的)
    self.subscribe(self.symbol)

3.3 指标持久化

AKQuant 内置的指标(如 SMA, EMA)已经支持 Pickle 序列化。如果你使用自定义指标或第三方库(如 TA-Lib),请确保它们支持 pickle,或者在 __getstate____setstate__ 中手动处理状态保存。

4. 注意事项

  1. Instrument 需重新注册run_warm_start 会尝试自动为新数据中的 Symbol 注册默认 Instrument。如果你的策略依赖特定的 lot_sizemultiplier,建议在 on_start 中手动检查并调用 self.ctx.engine.add_instrument(...)
  2. MarketModel 重置:费用设置(佣金、印花税)和交易规则(T+1)不会保存在快照中。务必在 run_warm_startkwargs 中传入正确的参数。
  3. 初始资金显示result2.metrics.initial_cash 会自动调整为恢复时的资金,确保收益率计算是基于第二阶段的实际起始资金,而不是账户的历史初始资金。
  4. 数据连续性:确保 Phase 1 的结束时间与 Phase 2 的开始时间是连续的。如果中间有长时间中断,指标计算可能会出现跳跃。

5. 完整示例

请参考项目中的 examples/21_warm_start_demo.py 获取完整的可运行代码。

# 示例摘要
class MyStrategy(Strategy):
    def on_start(self):
        if not self.is_restored:
            self.sma = SMA(10)
        self.register_indicator("sma", self.sma)

# ... 运行 Phase 1 ...
save_snapshot(engine, strategy, "checkpoint.pkl")

# ... 运行 Phase 2 ...
run_warm_start("checkpoint.pkl", data_new, ...)