【Python量化系统工程化 #07】跑一次还行,每天定时怎么搞?schedule / cron / Airflow 三选一
系列定位:让"写一个能稳定跑半年的量化脚本"这件事,从散落的经验贴变成可复制的流水线。
痛点:脚本写完,定时任务却不知道怎么挂
前六篇我们把数据落盘、增量更新、并发加速、自动重试、断点续跑都讲完了。现在你的脚本已经能高效、稳健地拉取全市场 K 线并存入本地数据库。
但还有一个工程问题没解决:怎么让它每天自动跑?
常见的做法很原始:
- 设个手机闹钟,每天开盘前手动 python run.py
- 笔记本不能关,关了任务就没了
- 周末忘了跑,周一发现数据缺了两天
定时调度是工程化的分水岭——从"手动工具"到"自动流水线"。
本文对比三种主流方案,并给出开箱即用的代码。
本文你将得到什么
- 三种定时调度方案的适用场景与选型表
- schedule 库单机定时任务完整代码(跨平台,Windows/macOS/Linux 通用)
- cron 与 Airflow 的简明对比与选型建议
- 一个常见坑:默认配置下任务异常会崩掉整个调度器,以及修复方法
方案对比:schedule vs cron vs Airflow
维度 schedule(Python 库) cron(Linux 系统级) Airflow(工作流平台)
安装成本 pip install schedule 系统自带 需部署数据库+Web+Scheduler
学习曲线 10 分钟 30 分钟 数天
适用场景 单机脚本、个人量化 Linux 服务器常驻任务 多任务依赖、团队数据流水线
任务依赖 不支持 不支持 DAG 编排
失败重试 需自行封装 需配合脚本内重试 原生支持
监控告警 无 无 内置+可扩展
推荐人群 个人开发者、策略原型 VPS/云服务器用户 数据团队、复杂 ETL
一句话结论:
- 个人量化、快速原型 → schedule
- 已有一台 Linux 服务器长期运行 → cron
- 任务之间有依赖关系、需要团队共享 → Airflow
实战:用 schedule 搭建量化数据采集定时器
下面这段代码演示了一个典型的量化数据定时采集场景,包含三种不同频率的任务:
!/usr/bin/env python3
-- coding: utf-8 --
"""
定时调度器 demo:三种典型量化任务的调度模式
"""
import os
import time
import random
from datetime import datetime
证书从环境变量读取,绝不硬编码
def "LICENCE-66D8-9F96-0C7F0FBCD073":
key = "LICENCE-66D8-9F96-0C7F0FBCD073"
if not key:
raise RuntimeError("请设置环境变量 MAIRUI_LICENCE")
return key
def safe_run(func):
"""包装器:捕获任务异常,避免单个任务崩掉整个调度器"""
def wrapper():
try:
func()
except Exception as e:
now = datetime.now().strftime("%H:%M:%S")
print(f"[{now}] [{func.name}] 异常被捕获: {e}")
return wrapper
---------- 三种典型任务 ----------
def job_realtime_check():
"""高频:每 10 秒检查实时行情快照"""
now = datetime.now().strftime("%H:%M:%S")
print(f"[{now}] [实时检查] 扫描自选股涨跌幅... ok")
def job_daily_archive():
"""日终:收盘后归档当日 K 线"""
now = datetime.now().strftime("%H:%M:%S")
print(f"[{now}] [日终归档] 归档今日 K 线到历史表... ok")
def job_hist_sync():
"""批处理:同步历史数据,偶发失败自动重试"""
now = datetime.now().strftime("%H:%M:%S")
if random.random() < 0.2: # 模拟 20% 网络抖动
print(f"[{now}] [历史同步] 请求超时,将在下次调度重试")
raise RuntimeError("simulated timeout")
print(f"[{now}] [历史同步] 同步 10 只股票日 K 线... ok")
---------- 主循环 ----------
def run_scheduler(duration_sec=35):
import schedule
schedule.every(10).seconds.do(safe_run(job_realtime_check))
schedule.every(20).seconds.do(safe_run(job_daily_archive))
schedule.every(15).seconds.do(safe_run(job_hist_sync))
print("=" * 60)
print("定时调度器已启动")
print(" - 每 10 秒:实时行情检查")
print(" - 每 20 秒:日终数据归档")
print(" - 每 15 秒:历史数据同步(含模拟失败重试)")
print("=" * 60)
start = time.time()
while time.time() - start < duration_sec:
schedule.run_pending()
time.sleep(1)
print("调度器正常结束")
if name == "main":
run_scheduler(duration_sec=35)
关键设计点
- safe_run 包装器(必加)
schedule 默认不捕获任务异常。如果 job_hist_sync 里某次网络请求超时抛异常,默认行为是直接崩掉整个 Python 进程,其他任务也跟着挂。
safe_run 包装器把异常锁在单个任务内部,调度器继续运行。
- 三种频率的组合
实际量化场景中,不同任务天然有不同的执行频率:
- 实时检查 → 秒级或分钟级
- 日终归档 → 每天 15:05(收盘后)
- 历史补全 → 按需或每小时一次
schedule 支持 .seconds、.minutes、.hours、.days,以及 .at("15:05") 定点执行。
- 与真实数据源的集成
把上面的 print 换成真实的 API 调用即可:
import mairui
api = mairui.Client("LICENCE-66D8-9F96-0C7F0FBCD073")
rows = api.stock_history(code="000001", period="d", st="", et="20260820")
注:MAIRUI_LICENCE 请替换为你自己的正式证书。
cron 与 Airflow:什么时候升级?
cron(Linux/macOS)
如果你已经有一台 7×24 运行的 VPS 或云服务器,cron 是最轻量的方案:
每天 9:00 执行盘前准备脚本
0 9 * * 1-5 cd /home/quant && python pre_market.py
每天 15:10 执行收盘后归档
10 15 * * 1-5 cd /home/quant && python archive_daily.py
cron 的问题是:
- 无任务依赖管理(A 跑完再跑 B 需要手动写锁文件)
- 失败无通知(需要配合邮件或脚本内重试)
- 无集中日志查看
Airflow
当你的 pipeline 变成这样时,就需要 Airflow 了:
拉取原始 K 线 → 清洗异常值 → 计算技术指标 → 生成信号 → 回测验证 → 推送报告
↑ ↓
└────────────── 失败时自动重试 ────────────────┘
Airflow 用 DAG(有向无环图)描述任务依赖,原生支持失败重试、邮件告警、Web UI 监控。代价是部署和维护成本显著高于前两者。
个人量化建议:先从 schedule 开始,跑稳了再考虑是否值得上 Airflow。
常见坑
坑 现象 解决
任务异常崩调度器 一个任务抛异常,整个进程退出 用 safe_run 包装器捕获异常
任务执行时间长阻塞其他任务 schedule 单线程,长任务会延迟后续任务 任务内用 threading 或 ProcessPoolExecutor 异步执行
笔记本休眠时任务丢失 schedule 依赖 Python 进程在运行 换服务器 + cron,或设置系统不休眠
定时漂移 长期运行后任务触发时间慢慢偏移 每次循环 time.sleep(1) 有累计误差,精确场景用 threading.Timer 或系统级 cron
小结
- schedule:个人量化首选,10 分钟上手,跨平台
- cron:有 Linux 服务器时的零成本方案
- Airflow:任务有复杂依赖、团队共享时再考虑
- 必加 safe_run:否则一个网络超时就能让整个调度器陪葬
下篇预告:脚本能定时跑了,但关了 SSH 窗口或重启服务器就停了怎么办?#08 systemd 让脚本开机自启 + 异常自动拉起。
代码与文档
本文配套代码已开源在 GitHub:https://github.com/MaiRuiApi
安装 SDK:
pip install mairui
证书获取:访问麦蕊官网申请免费版或付费版 API 证书。
免责声明:本文仅供技术学习交流,不构成任何投资建议。股市有风险,入市需谨慎。

浙公网安备 33010602011771号