程序员量化交易实战 41:把每日运行计划压成摘要
原创 · 约 12 分钟阅读 · 阅读 --
Last updated on

程序员量化交易实战 41:把每日运行计划压成摘要

作者: Alex Xiang


程序员量化交易实战 41:把每日运行计划压成摘要

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

第 40 篇已经有了 DailyRunPlan,它包含请求、结果、失败动作和动作汇总。

但计划对象不适合直接打到日志里。生产环境里看日志时,我们通常只需要先知道一句话:今天能不能跑,跑的是哪天,有多少股票,失败了几项。

ZiCode 工程师查看每日运行摘要

摘要对象

第 41 章新增 app/daily_run_summary.py

@dataclass(frozen=True)
class DailyRunSummary:
    trade_date: str
    status: str
    dry_run: bool
    symbol_count: int
    failed_check_count: int
    action_summary: str
    executable: bool

它不是替代 DailyRunPlan,而是从计划对象里提取一层“人第一眼要看的信息”。

字段用途
trade_date确认这次运行对应哪个交易日
status快速判断 ready、dry-run-ready 或 blocked
symbol_count观察本次覆盖的股票数量是否异常
failed_check_count不展开细节也能知道失败规模
action_summary判断是 warning、blocker 还是无需处理
executable是否允许真实执行

从计划构造摘要

摘要函数只读 DailyRunPlan,不重新计算业务规则。

def build_daily_run_summary(plan: DailyRunPlan) -> DailyRunSummary:
    return DailyRunSummary(
        trade_date=plan.result.trade_date,
        status=plan.result.status,
        dry_run=plan.result.dry_run,
        symbol_count=len(plan.request.required_symbols),
        failed_check_count=len(plan.result.failed_checks),
        action_summary=plan.action_summary,
        executable=plan_can_execute(plan),
    )

这里继续复用 plan_can_execute()。如果后面执行标准变化,摘要层不用跟着复制判断逻辑。

一行日志

日志里最怕结构太散。第 41 章补了一个稳定格式:

def format_daily_run_summary(summary: DailyRunSummary) -> str:
    return (
        f"{summary.trade_date} "
        f"status={summary.status} "
        f"symbols={summary.symbol_count} "
        f"failed_checks={summary.failed_check_count} "
        f"actions={summary.action_summary} "
        f"executable={str(summary.executable).lower()}"
    )

blocked 示例输出:

2026-02-11 status=blocked symbols=1 failed_checks=1 actions=blocker executable=false

这行文字可以直接放进 CLI 输出、定时任务日志或告警消息。它不负责解释全部细节,只负责让人知道接下来要不要点开 artifact。

接到可运行示例

本章的摘要对象已经接入专栏代码仓库里的章节示例命令。为了让第 41-45 篇共用同一个真实场景,示例故意构造了一次 data_gaps 未通过的每日运行:运行窗口正常、历史归档正常、运行健康正常,只有行情数据检查失败。

运行命令:

uv run python -m scripts.chapter_examples paper-command

本章对应的输出如下:

每日运行摘要命令输出

这里最重要的是两段信息。

第一段是一行摘要:status=blockedfailed_checks=1actions=blockerexecutable=false。它适合放进日志和告警标题里,让人不用展开 JSON 就知道今天不能真实执行。

第二段是结构化字段:dry_run=Falsesymbol_count=2failed_check_count=1。这类字段适合后续接入 CLI、任务平台或监控系统时继续拆分,而不是靠字符串解析。

摘要不是审计凭证。它只是入口层的“状态标题”。真正要排查为什么 blocked,需要看下一篇落盘的 artifact。

测试

本章测试覆盖两件事:

  • ready 计划能正确统计去重后的股票数量。
  • blocked 计划能输出稳定的一行摘要。

运行命令:

uv run pytest tests/test_daily_run_summary.py tests/test_daily_run_plan.py

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

276 passed, 2 warnings

本章更新与代码仓库

本章更新内容:

  • 新增 app/daily_run_summary.py
  • 新增 DailyRunSummary
  • 实现 build_daily_run_summary()
  • 实现 format_daily_run_summary()
  • 新增 tests/test_daily_run_summary.py,覆盖 ready 与 blocked 摘要。
  • scripts/chapter_examples.py 中接入 paper-command,可直接复现第 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_daily_run_summary.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 篇把每日运行计划压缩成摘要。下一步要解决的是:摘要之外的完整上下文怎么落盘,出了问题以后能不能回放当时的请求、失败检查和处理动作。