前言

服务器重启、策略升级、异常退出后,进程内的变量全没了:网格档位计数、昨日信号标志、自定义止损线,若只靠 position 恢复,往往不够。我遇到过重启后策略以为「还没开过仓」又开一遍,或与真实持仓叠加。

天勤 TqSdkpositionaccount 会随柜台更新,但业务状态(第几根 K 线、内部计数器、参数版本号)要自己做持久化。下面用 JSON 文件示意保存与恢复,适合个人和小团队;大规模可用 SQLite,思路相同。

一、什么该持久化、什么不该

宜保存:

  • 策略内部状态机阶段(如 grid_level、last_signal)
  • 上次处理的 K 线 datetime
  • 配置版本号、随机种子(若可复现)

不宜只靠文件保存:

  • 真实持仓、资金(以 get_positionget_account 为准)
  • 未成交挂单(以 order 查询为准)

重启后先读柜台,再读文件,文件与柜台冲突时以柜台为准并打日志。

二、JSON 持久化示例

import json
import os
from pathlib import Path

STATE_PATH = Path("data/strategy_state.json")

def load_state():
    if not STATE_PATH.exists():
        return {}
    with STATE_PATH.open(encoding="utf-8") as f:
        return json.load(f)

def save_state(state: dict):
    STATE_PATH.parent.mkdir(parents=True, exist_ok=True)
    tmp = STATE_PATH.with_suffix(".tmp")
    with tmp.open("w", encoding="utf-8") as f:
        json.dump(state, f, ensure_ascii=False, indent=2)
    tmp.replace(STATE_PATH)

# 主循环片段
state = load_state()
state.setdefault("last_bar_dt", None)
state.setdefault("grid_level", 0)

while True:
    api.wait_update()
    if api.is_changing(kl.iloc[-1], "datetime"):
        bar_dt = str(kl.datetime.iloc[-2])
        if bar_dt != state["last_bar_dt"]:
            state["last_bar_dt"] = bar_dt
            # ... 信号逻辑,可能改 state["grid_level"]
            save_state(state)

用临时文件再 replace,降低写到一半进程死掉导致 JSON 损坏的概率。

三、重启恢复流程

  1. 启动脚本,TqApi 连接成功后 wait_update 一到两帧。
  2. positionget_order(若有挂单查询需求)。
  3. load_state()
  4. 对比:若 position 非零但 state 显示空仓,记录告警,按团队规则决定是否人工介入或重置 state。
  5. 进入主循环;关键状态变更后 save_state

不要把「重启」和「换月移仓」混在一次里不做日志。

四、与无人值守、日志配合

持久化文件进 .gitignore;备份到与日志同目录便于复盘。进程外监控发现重启时,应检查 state 文件 mtime 与内容是否合理。

若用 pickle,注意 Python 版本兼容;JSON 更易人工查看,推荐优先。

五、多策略多文件

每个策略 strategy_a_state.json 分开,勿多进程写同一文件。多进程写需要文件锁,小团队用单进程单策略更简单。

总结

进程重启后,positionaccount、活跃委托应以 wait_update 后的 TqSdk 查询为准;网格档位、上一根 K 线 datetime、内部计数器等业务状态不会自动回来,需 JSON 等文件持久化。恢复顺序:连接成功 → 读柜台持仓与挂单 → load_state() → 若文件显示空仓但 position 非零,打告警并按规程人工介入或重置 state → 再进入主循环。冲突一律以柜台为准。

保存宜用「写临时文件再 replace」降低损坏概率;data/.gitignore,Docker 挂载卷保留 state。多策略各用各的 state 文件,避免多进程共写。不宜用文件保存真实持仓代替 get_position

建议每策略维护重启检查表:position 手数、挂单列表、state 文件 mtime 与关键字段各记一行日志后再续跑;升级脚本或换月当日额外做一次核对。

FAQ

1)多久 save 一次?

状态变更时写;每根 K 线最多一次通常够。

2)state 能放 Git 吗?

不要;仅放服务器本地。

3)Docker 重启容器?

挂载 data/ 卷,否则 state 丢。

4)回测要写 state 吗?

一般不必;回测要可重复。

风险提示

本文用于工程实践说明,不构成投资建议。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐