BigQuant使用文档

模拟交易变量持久化

由qxiao创建,最终由qxiao 被浏览 11 用户

1. 回测 vs 模拟交易,最大的“隐藏差异”是什么?

在回测里,策略通常是一个连续进程跑完整个区间:

  • initialize() 只执行一次
  • 变量在内存里一直存在(计数器、上次调仓日、上次权重……)

但在模拟交易里,系统很常见的运行方式是:

  • 每个交易日(或每次任务触发)启动一次策略
  • 执行 initialize()、handle_data() 后退出
  • 第二天再次启动时,内存变量全部丢失

所以,如果如果把“策略状态”只放在 Python 变量里,模拟交易就会“失忆”。

2. 什么叫“变量持久化”?

变量持久化 = 把策略的关键状态从“内存”搬到“可恢复的存储”里,让策略下次启动还能“记得昨天做过什么”。

在 BigTrader 体系里最直接的方式是 context.user_store

  • 它是一个字典
  • 用来存放你的用户状态
  • 在模拟交易等模式下会自动保存和恢复
  • 但存进去的值需要支持 JSON 序列化

3. 反例:没有进行变量持久化的双均线策略

我们使用一个最简单、最常见的策略——双均线策略(短均线/长均线金叉买入、死叉卖出),并设定“每 5 个交易日才进入一次交易逻辑”来展示:

  • 不做持久化会出现什么问题(反例)
  • 使用 context.user_store 后如何修正

策略逻辑:

  • 计算短均线 MA(short_n) 与长均线 MA(long_n)
  • 若 MA(short) > MA(long):买入(满仓)
  • 否则:卖出(空仓)
  • 为了展示状态问题,加入一个节奏控制:每 5 个交易日才执行一次交易逻辑

参数示例:

  • short_n = 5
  • long_n = 20
  • rebalance_days = 5
  • 标的:510300.SH(示例:沪深300ETF)

关键问题:使用 context.counter 作为计数器,它只是内存变量,模拟交易重启就会归零。

https://bigquant.com/codesharev3/fe834bd1-d447-415d-bd72-657fd24528ce

此代码在回测中可以正常运行,但在模拟交易中策略往往会按天调度、可能反复启动/重启进程,若使用 context.counter这类仅存在于内存的变量来记录调仓计数,就会在重启后被重置,导致“每 5 天执行一次”的节奏失真;因此需要改用 context.user_store对计数器等关键状态进行持久化,才能保证模拟交易跨天连续、稳定运行。

4. “模拟交易标准”的正确写法

4.1 幂等初始化:只在第一次设置默认值

模拟交易可能会按天启动策略进程。若在 initialize() 里每次都给计数器赋值,就会把昨天恢复的状态覆盖掉。正确做法是只在不存在时写入默认值(幂等初始化)。

def initialize(context):
    context.rebalance_days = rebalance_days

    # ✅ 幂等初始化:只在第一次创建 counter
    if "counter" not in context.user_store:
        context.user_store["counter"] = 0

这就是“幂等”:

  • 第一次运行user_store 里没有 counter → 写入默认值 0
  • 之后每次启动:counter 已存在(且平台会恢复昨天保存的值)→ 不覆盖
  • 这样策略才能“记住昨天过了几天”,保证调仓节奏稳定。

也可以用更短写法:context.user_store.setdefault("counter", 0),含义一致。

4.2 持久化计数器

防止重启的情况下变量丢失

# ✅ 持久化计数器:跨天/重启不丢
context.user_store["counter"] += 1
if context.user_store["counter"] < context.rebalance_days:
    return
context.user_store["counter"] = 0
  • 这段是“节奏控制”的核心:每天 +1,到第 5 天才进入交易逻辑。
  • 如果用内存变量,重启后会回到 0,节奏就会失真。
  • 换成 user_store["counter"] 后,哪怕重启也能从昨天的值继续累加。

5. user_store 的边界与注意事项

user_store 适合“状态”,不适合“数据”。

5.1 可以存

  • int/float/str/bool
  • list/dict(内部元素也必须是可序列化类型)
  • 小体量状态:计数器、日期、权重字典、开关

5.2 不建议/不要存

  • DataFrame
  • numpy array、scipy 对象
  • 自定义类实例
  • 大量历史数据

如果需要保存表格化结果(如每日信号面板、调仓记录、因子表),应使用更合适的数据存储方式(例如写入表),而不是塞进 user_store

6. 总结

我们在模拟交易中做变量持久化,是为了保证策略具备“连续记忆”,使其运行方式更接近未来的实盘。

\

标签

模拟交易
{link}