程序员量化交易实战 31:给每日任务加运行时间窗
程序员量化交易实战 31:给每日任务加运行时间窗
古董级程序员,大厂出来后一直在创业公司,现在仍活跃在一线做 AI 相关的开发。这个专栏会把一个 A 股量化平台从 0 到 1 拆开写:数据、策略、回测、模拟盘、提醒和生产化,尽量用真实代码和真实运行结果说话。更完整的更新也会同步到微信公众号「字与码」。
第 30 篇生成了每日运行健康报告。系统已经能告诉我们一次模拟盘运行是健康、警告还是阻断。
第 31 篇开始处理另一个生产化问题:任务不能什么时候想跑就跑。模拟盘日报如果在行情没收完、复权没更新、人工还没确认的时候运行,结果再漂亮也不可信。

时间窗解决什么
定时任务最怕两种错误。
一种是晚了不跑,日报缺一天。另一种是早了乱跑,拿着半截数据生成建议。
第 31 章不直接接 cron,也不绑定具体调度平台,只抽一个小对象:给定当前时间和允许运行窗口,判断现在能不能跑;如果不能跑,告诉调用方下一次窗口从什么时候开始。
| 场景 | 结果 |
|---|---|
| 当前时间在窗口内 | allowed=True |
| 当前时间在窗口外 | allowed=False,返回 next_run_at |
| 窗口跨午夜 | 支持 23:00 到 01:00 这类配置 |
运行窗口对象
第 31 章新增 app/run_window.py。
@dataclass(frozen=True)
class RunWindow:
start: time
end: time
timezone_name: str = "Asia/Shanghai"
@dataclass(frozen=True)
class RunWindowStatus:
allowed: bool
reason: str
next_run_at: datetime | None = None
这里的 timezone_name 暂时只是配置说明,当前判断直接使用传入 datetime 的时区。这样第一版足够简单,后面接真实调度时再统一做时区转换。
判断逻辑
普通时间窗很好判断,start <= now <= end。
跨午夜窗口要单独处理,例如 23:00 到 01:00,00:30 也应该被允许。
def is_within_run_window(now: datetime, window: RunWindow) -> bool:
current = now.time()
if window.start <= window.end:
return window.start <= current <= window.end
return current >= window.start or current <= window.end
窗口外的场景会计算下一次开始时间。
candidate = datetime.combine(now.date(), window.start, tzinfo=now.tzinfo)
if candidate <= now:
candidate += timedelta(days=1)
这段逻辑不主动睡眠,也不启动后台任务。它只提供一个确定的判定结果,方便上层调度器决定跳过、延迟还是报警。
当前联动运行结果
第 31-35 篇现在可以通过同一条命令运行:
uv run python -m scripts.chapter_examples paper-ops-check
这条命令会先判断运行时间窗,再生成归档、历史摘要、数据缺口计划和运维检查清单。时间窗部分输出如下:

示例里当前时间是 15:20,窗口是 15:10-15:40,所以 allowed=True。这里的判断不是策略逻辑,而是运行准入逻辑:系统先确认现在是可信的运行时段,再进入后面的归档和检查。
测试覆盖
这章的测试不复杂,但边界必须明确。
uv run pytest tests/test_run_window.py
测试覆盖三种情况:
15:10到15:40内,15:20允许运行。16:00已经错过当天窗口,下一次运行时间是第二天15:10。23:00到01:00的跨午夜窗口,23:30和00:30都允许,02:00不允许。
本章更新与代码仓库
本章更新内容:
- 新增
app/run_window.py。 - 实现
RunWindow和RunWindowStatus。 - 支持普通窗口和跨午夜窗口。
- 窗口外返回下一次可运行时间。
- 增加
paper-ops-check联动示例,展示时间窗如何进入每日运维检查链路。 - 新增
tests/test_run_window.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-31
uv sync --extra dev
uv run pytest tests/test_run_window.py
第 31 章提交为 4ce2ca8,tag 为 chapter-31。
本篇小结
运行时间窗是一个很小的模块,但它把“什么时候可以跑”从调度器里抽了出来。
第 31 篇以后,每日流程不再只关心自己能不能算,还要先确认现在是不是一个可信的运行时间。下一篇会把每日运行结果落成稳定归档文件,方便后续做历史统计和追查。