☰
PanWatch APScheduler 调度体系:cron 解析、交易日历与 Agent 定时触发
2026/10/1 12:55:58 网站建设 项目流程

PanWatch APScheduler 调度体系:cron 解析、交易日历与 Agent 定时触发

【免费下载链接】PanWatchPanWatch — AI stock monitoring for A-shares, HK & US markets, powered by TradingAgents. Portfolio insights, real-time alerts & automated reports.|盯盘侠:覆盖 A股/港股/美股的 AI 盯盘、持仓分析、实时提醒与自动报告。项目地址: https://gitcode.com/GitHub_Trending/pa/PanWatch

PanWatch(盯盘侠)是一款覆盖 A股、港股、美股的 AI 股票监控系统,它的"心脏"是一套基于 APScheduler 的定时调度体系:统一解析 cron 表达式、用交易日历判断当天是否开市,再按时自动触发 AI Agent 完成盘前分析、盘中盯盘和盘后总结。本文带你快速读懂这套体系的四大核心模块——cron 解析器、交易日历、时区处理与 Agent 定时触发,帮助新手理解"为什么它的提醒总是准点、且从不在节假日打扰你"。

调度体系全景:一个平台层 + 多个业务调度器

PanWatch 把所有"和定时有关"的公共能力集中在 src/platform/scheduling/ 目录,形成四件套:

模块职责
schedule_parser.py解析 cron / interval 表达式,生成 APScheduler 触发器
trading_calendar.py回答"这一天开不开市"(含 A 股节假日)
timezone.py统一时区存储与显示,默认 Asia/Shanghai
scheduler_registry.py调度器健康注册表,供系统自检读取

在此之上,各业务模块挂载自己的 APScheduler 实例:Agent 调度器、价格提醒调度器、模拟盘调度器、上下文维护调度器。每个调度器启动时都会把自己注册进注册表,系统自检时据此判断"调度器是否在跑"——无调度的 CLI 进程注册表为空,则优雅跳过。

cron 表达式解析:解决"周日到底是不是 0"

PanWatch 在界面和配置里接受标准的 5 段 cron:分 时 日 月 周。但这里藏着一个经典陷阱:

  • POSIX cron:0或7都表示周日
  • APScheduler:0表示周一,6表示周日

如果直接把用户的 cron 丢给 APScheduler,"每周一执行"就可能变成"每周日执行"。PanWatch 的 normalize_cron_day_of_week_field() 专门做了三层处理:先把字段展开成具体数字集合(支持*、区间a-b、步长*/s、逗号列表),再按"POSIX → APScheduler"映射(0 变 6,其余减 1),最后把集合压缩回简洁的 cron 区间字符串;若字段含mon-fri这类字母写法则原样透传。解析失败时不做任何改动,宁可保守也不改变语义。

除 cron 外,还支持更简单的间隔表达式,如interval:30s、interval:3m、interval:2h,由 parse_schedule() 统一分派。

还有一个很贴心的能力:preview_schedule() 可以预览"接下来 N 次触发时间",让你配置完立即验证调度是否符合预期,避免上线后才发现"原来它每天 22:00 才跑"。

交易日历:定时任务触发前先问一句"今天开市吗"

这是 PanWatch 调度体系最有市场味道的部分。trading_calendar.py 回答的问题是"这一天开不开市",与市场定义里的is_trading_time()(回答"当下是否在交易时段内")互补——盘前计划、日终摘要这类任务本身就发生在交易时段之外,只能靠"是不是交易日"来守卫。

它的数据策略非常务实:

  • A 股:使用 akshare 交易日历(tool_trade_date_hist_sina),含法定节假日,权威可靠;结果缓存在内存,启动预热 + 每日凌晨刷新。
  • 港股 / 美股:没有等价的公开日历源,只判断周末(注释里称为"诚实降级,不假装支持节假日")。
  • 降级原则:拿不到日历时退回"只判周末"。作者的注释写得很直白——"少发一条是遗憾,漏发一整天是事故",宁可多发一条通知,也不能把交易日误判为休市。

日历每天凌晨 03:00 由上下文维护调度器自动刷新(context_scheduler.py),特意安排在各类盘前通知之前,保证当天的判断用的都是新日历。交易类定时任务(如模拟盘的盘前计划、日终摘要)在执行开头都会先调用any_market_trading_day()(paper_trading_scheduler.py),CN/HK/US 任一市场开市才继续,否则安静跳过。

Agent 定时触发:从一行 cron 到一次 AI 执行

真正让 AI Agent 跑起来的入口是 AgentScheduler。注册一个 Agent 只需要三样东西:Agent 实例、调度表达式(cron 或 interval)、执行模式(batch整批执行 /single逐只股票执行)。

每次触发时的执行链路(_run_agent()):

  1. 生成唯一trace_id,开启 OTel 追踪 span,把日志、追踪、执行记录串成一条线;
  2. 通过context_builder动态构建上下文——每次执行都拿到最新配置,而不是注册时的快照;
  3. single模式下逐只遍历自选股,遇到所在市场非交易时段直接跳过并计数;
  4. 执行结束后由 record_agent_run() 落库本次运行(状态、耗时、trace_id、触发来源、是否发出通知),失败也记录,便于回溯。

配套的 AI 提示词模板分别放在 prompts/premarket_outlook.txt、prompts/daily_report.txt 和 prompts/intraday_monitor.txt,对应盘前展望、每日报告和盘中监控三类定时任务。除了定时触发,trigger_now() 还支持手动"立即执行",方便调试。

高频扫描:价格提醒与模拟盘的错峰设计

除了低频的 cron 任务,PanWatch 还有两类每 60 秒跑一次的高频扫描:

  • 价格提醒调度器(price_alert_scheduler.py):每 60 秒扫描一次自选股价格是否触及提醒线,触发告警才是 INFO 级业务事件,否则只是 DEBUG 心跳,日志不吵人。
  • 模拟盘调度器(paper_trading_scheduler.py):60 秒扫描建仓/平仓信号,另挂每天 09:00 盘前计划、15:30 日终摘要两个 cron 任务,非交易日自动跳过。

细节上能看到很多工程巧思:

  • jitter 抖动错峰:高频扫描加 20 秒随机抖动,cron 任务加 120 秒抖动,避免多个调度器在同一秒并发写 SQLite;
  • coalesce + max_instances=1:上一轮没跑完时合并丢弃积压、不并发重入,防止任务堆积;
  • 重入保护:_running标志位在扫描开始前拦截重叠执行。

上下文维护调度器还负责机会池的每日三次刷新(09:15 盘前 / 13:30 午盘 / 22:00 晚间)与 04:15 的历史数据清理(context_scheduler.py),时间点按调度器时区(默认 Asia/Shanghai,可用TZ环境变量覆盖)解释,与 Agent 的 cron 语义完全一致。

小结

PanWatch 的 APScheduler 调度体系可以概括为三层分工:

  1. 平台层(src/platform/scheduling/):cron 解析(含星期语义归一化)、交易日历(含节假日与诚实降级)、时区统一、健康注册表;
  2. 触发层:Agent 调度器把分 时 日 月 周变成一次次带追踪、带记录的 AI 执行;
  3. 业务层:价格提醒、模拟盘、上下文维护各挂独立调度器,用 jitter、coalesce、max_instances 保证高频扫描互不打架。

对新手而言,这套体系最值得借鉴的经验是:定时任务上线前先 preview 触发时间、用交易日历而不是"时段判断"守卫盘前/盘后任务,以及降级策略永远偏向"多发一条"而不是"漏掉一天"。

【免费下载链接】PanWatchPanWatch — AI stock monitoring for A-shares, HK & US markets, powered by TradingAgents. Portfolio insights, real-time alerts & automated reports.|盯盘侠:覆盖 A股/港股/美股的 AI 盯盘、持仓分析、实时提醒与自动报告。项目地址: https://gitcode.com/GitHub_Trending/pa/PanWatch

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询