程序员量化交易实战 45:每日运行 runbook
原创 · 约 14 分钟阅读 · 阅读 --
Last updated on

程序员量化交易实战 45:每日运行 runbook

作者: Alex Xiang


程序员量化交易实战 45:每日运行 runbook

古董级程序员,大厂出来后一直在创业公司,现在仍活跃在一线做 AI 相关的开发。这个专栏会把一个 A 股量化平台从 0 到 1 拆开写:数据、策略、回测、模拟盘、提醒和生产化,尽量用真实代码和真实运行结果说话。更完整的更新也会同步到微信公众号「字与码」。

第 44 篇有了执行决策,但告警里只写 repair_market_data 这种动作名,还不够值班。

第 45 篇把执行决策转成 runbook。也就是:如果可以执行,下一步是什么;如果不能执行,需要先做哪些检查或修复。

ZiCode 工程师查看每日运行 runbook

runbook 对象

第 45 章新增 app/ops_runbook.py

@dataclass(frozen=True)
class RunbookStep:
    title: str
    command: str
    required: bool


@dataclass(frozen=True)
class OpsRunbook:
    trade_date: str
    status: str
    steps: tuple[RunbookStep, ...]

这里的 command 还不是自动执行的 shell 命令,而是运维动作说明。原因很简单:修数据、查归档、等运行窗口这些事情,有些需要人工确认,不能直接自动化。

动作映射

本章先把前面定义过的动作映射成可读步骤。

_COMMAND_BY_ACTION = {
    "disable_dry_run": "rerun with dry_run=false after manual confirmation",
    "inspect_archive": "check report archive index for the previous successful run",
    "inspect_run_health": "inspect recent run health events and retry only after recovery",
    "repair_market_data": "reload missing market data and rerun checklist",
    "wait_next_window": "wait until the configured run window opens",
    "manual_review": "open the artifact and review the failed checklist item manually",
}

这个映射很朴素,但已经比只给动作名更适合发到告警里。

从执行决策生成 runbook

核心函数如下:

def build_ops_runbook(plan: DailyRunPlan) -> OpsRunbook:
    decision = decide_execution(plan)
    if decision.allowed:
        steps = (
            RunbookStep("confirm artifact", "open the daily-run artifact before execution", True),
            RunbookStep("execute plan", "start the simulated trading daily run", True),
        )
    else:
        steps = tuple(
            RunbookStep(action, _COMMAND_BY_ACTION.get(action, _COMMAND_BY_ACTION["manual_review"]), True)
            for action in decision.required_actions
        )
    return OpsRunbook(trade_date=plan.result.trade_date, status=plan.result.status, steps=steps)

ready 计划生成的是确认 artifact 和执行计划。

blocked 计划生成的是处理失败动作,例如:

2026-02-15 status=blocked
- repair_market_data: reload missing market data and rerun checklist

接到可运行示例

第 45 篇对应的 runbook 输出来自同一个章节命令:

uv run python -m scripts.chapter_examples paper-command

本章对应的输出如下:

每日运行 runbook 输出

这次 runbook 只有一个步骤:repair_market_data。这不是装饰性的“建议”,而是由第 35 篇的 checklist、第 39 篇的 failure action、第 44 篇的 execution guard 一路传下来的处理动作。

runbook 的粒度不应该太细。比如“重新下载哪一天哪只股票的行情”需要数据修复模块提供更具体的上下文;本章先把动作翻译成人能看懂的操作方向:重新加载缺失行情,然后重新跑 checklist。这样告警不会只剩一个英文动作名,也不会冒进到自动修数据。

测试

本章测试覆盖:

  • ready 计划生成执行步骤。
  • dry-run-ready 计划要求手动确认关闭 dry run。
  • blocked 计划跟随失败动作。
  • runbook 能转成适合告警展示的多行文本。

运行命令:

uv run pytest tests/test_ops_runbook.py tests/test_execution_guard.py tests/test_daily_run_plan.py

本批次补充 paper-command 后,全量测试通过:

276 passed, 2 warnings

本章更新与代码仓库

本章更新内容:

  • 新增 app/ops_runbook.py
  • 新增 RunbookStepOpsRunbook
  • 实现 build_ops_runbook()
  • 实现 runbook_as_lines()
  • 新增 tests/test_ops_runbook.py,覆盖 ready、dry-run-ready、blocked 和告警文本。
  • 完成第 41-45 篇阶段 review。
  • scripts/chapter_examples.py 中接入 runbook 输出,形成第 41-45 篇可运行闭环。

代码仓库:

https://github.com/ax2/zi-quant-platform

本章代码:

git clone https://github.com/ax2/zi-quant-platform.git
cd zi-quant-platform
git checkout chapter-41-45-paper-command
uv sync --extra dev
uv run python -m scripts.chapter_examples paper-command
uv run pytest tests/test_ops_runbook.py tests/test_execution_guard.py tests/test_daily_run_plan.py tests/test_chapter_examples.py

第 41-45 篇共用 tag chapter-41-45-paper-command。当前全量测试通过:276 passed,只有既有 FastAPI deprecation warning。

第 41-45 篇阶段 review

这一组没有继续扩展策略能力,而是把每日运行入口往生产可用推进了一层。

第 41 篇新增 DailyRunSummary,把计划压成日志和命令行友好的一行摘要。

第 42 篇新增 DailyRunArtifact,把每日运行上下文写成 JSON,方便排查和归档。

第 43 篇新增 DailyRunCommandResponse,把状态、消息、artifact 路径和 exit code 包成命令层对象。

第 44 篇新增 ExecutionDecision,把真实执行前的判断集中到执行闸门。

第 45 篇新增 OpsRunbook,把执行决策转成运维步骤。

这五篇补的是运行系统的外围骨架:摘要、证据、命令响应、闸门和 runbook。它们不直接决定买卖,但决定系统能不能每天稳定地跑、能不能被人排查、能不能避免误执行。

本批次新增的可运行入口是:

uv run python -m scripts.chapter_examples paper-command

它故意构造了一次 data_gaps blocked 场景,并贯穿输出摘要、artifact、命令响应、执行闸门和 runbook。读者可以从同一条命令看到第 41-45 篇之间的依赖关系,而不是分别阅读五个孤立模块。

本篇小结

runbook 是把系统状态翻译成人能执行的步骤。

到第 45 篇,每日运行已经有了从计划到摘要、artifact、命令响应、执行决策和运维步骤的闭环。后面再接 CLI 或任务调度时,可以直接沿着这条链路往外包,而不是把判断散落在入口脚本里。