程序员量化交易实战 38:给日报归档建立索引
程序员量化交易实战 38:给日报归档建立索引
古董级程序员,大厂出来后一直在创业公司,现在仍活跃在一线做 AI 相关的开发。这个专栏会把一个 A 股量化平台从 0 到 1 拆开写:数据、策略、回测、模拟盘、提醒和生产化,尽量用真实代码和真实运行结果说话。更完整的更新也会同步到微信公众号「字与码」。
第 32 篇已经能把每日运行结果写成 JSON,第 33 篇能做简单历史汇总。
第 38 篇补一个夹在中间的小工具:给归档目录建立索引。后面无论做 CLI 展示、页面列表还是人工排查,都不应该每次手写 glob 和 JSON 读取逻辑。

索引项包含什么
日报索引不需要复制完整报告,只保留列表页真正需要的信息。
| 字段 | 含义 |
|---|---|
trade_date | 交易日 |
status | 当日健康状态 |
path | 归档文件路径 |
完整报告仍然留在 JSON 文件里,需要详情时再读。
索引对象
第 38 章新增 app/report_index.py。
@dataclass(frozen=True)
class ReportIndexEntry:
trade_date: str
status: str
path: Path
这个对象以后可以直接用于命令行表格,也可以喂给一个简单的 Web 页面。
扫描归档目录
实现逻辑复用第 32 章的读取函数。
for path in sorted(Path(directory).glob("*-paper-report.json")):
payload = read_archived_report(path)
entries.append(
ReportIndexEntry(
trade_date=payload["trade_date"],
status=payload["health"]["status"],
path=path,
)
)
排序基于文件名。归档文件名本身以交易日开头,所以这个排序稳定且直观。
获取最新报告
索引为空时返回 None,不要让调用方处理下标异常。
def latest_report_entry(entries: tuple[ReportIndexEntry, ...]) -> ReportIndexEntry | None:
if not entries:
return None
return entries[-1]
这类小函数看起来简单,但在生产代码里能减少很多重复判断。
当前联动运行结果
paper-run-plan 会在临时目录里写入三天日报归档,然后生成索引:
uv run python -m scripts.chapter_examples paper-run-plan

索引里能看到 2026-03-04、2026-03-05、2026-03-06 三条记录,其中中间一天是 blocker。索引不读取完整正文,只保留列表页和排障入口需要的最小字段。
测试索引顺序
运行本章测试:
uv run pytest tests/test_report_index.py tests/test_report_archive.py tests/test_run_history.py
关键断言:
assert [entry.trade_date for entry in entries] == ["2026-02-05", "2026-02-06"]
assert [entry.status for entry in entries] == ["ok", "blocker"]
assert latest_report_entry(entries) == entries[-1]
这说明索引能稳定列出归档报告,并能取到最新一条。
本章更新与代码仓库
本章更新内容:
- 新增
app/report_index.py。 - 实现
ReportIndexEntry。 - 从归档目录生成报告索引。
- 实现
latest_report_entry()。 - 增加
paper-run-plan联动示例,展示三天归档如何变成可查询索引。 - 新增
tests/test_report_index.py,覆盖索引顺序和空索引。
代码仓库:
https://github.com/ax2/zi-quant-platform
本章代码:
git clone https://github.com/ax2/zi-quant-platform.git
cd zi-quant-platform
git checkout chapter-38
uv sync --extra dev
uv run pytest tests/test_report_index.py tests/test_report_archive.py tests/test_run_history.py
第 38 章提交为 6d848ce,tag 为 chapter-38。
本篇小结
日报归档有了索引,历史文件就不再只是散落在目录里的 JSON。
第 38 篇把交易日、状态和路径抽成轻量列表。下一篇会处理 blocked 结果:检查失败以后,系统应该给出明确处理动作,而不是只告诉你失败了。