源码级核验:agent_catalog.py + price_alert_engine.py + notifications/

PanWatch 什么时候会提醒你:Agent 剧本、六道门槛与推送去重

在 PanWatch 里,「我设了提醒但没收到消息」是最常见的问题,而答案往往不是「规则没命中」。本页按执行顺序拆开三件事:谁在什么时候跑(三个 Agent 的默认剧本)、命中了还要过哪几道门(触发门槛的判定顺序)、推送本身会不会被吞(去重与静默时段)。

workflow Agent:3 个(盘前 / 盘中 / 收盘)默认开启的:只有收盘复盘提醒扫描:默认每 60 秒一轮(含 20 秒抖动)依据:agent_catalog.py + price_alert_engine.py(固定 commit)
启用
未过期
交易时段
日上限
冷却
去重与静默
推送
依据 price_alert_engine.py 的 _can_trigger 与通知去重逻辑整理的门槛顺序示意图;非官方架构图。
Agent playbook

PanWatch 三个 workflow Agent 的默认剧本:谁在什么时候跑、默认开不开

PanWatch 在 agent_catalog.py 里把 Agent 分成两类:workflow(用户可见、可调度)与 capability(内部/手动、不独立调度)。下面这张表是完整名单与默认值。

Agent类型默认 cron默认开关执行模式它做什么
盘前分析 premarket_outlookworkflow0 9 * * 1-5关闭batch综合昨日分析与隔夜信息,展望今日走势
盘中监测 intraday_monitorworkflow*/5 9-15 * * 1-5关闭single交易时段实时监控,判断是否有值得关注的信号
收盘复盘 daily_reportworkflow30 15 * * 1-5开启batch生成复盘报告:市场回顾、个股复盘与次日关注
图像技术分析 chart_analystcapability无(不调度)关闭且不可见single已弃用:详情页按需触发的图像分析,lifecycle_status=deprecated,被另外三个替代
TradingAgents 深度分析 tradingagentsworkflow无(手动触发)关闭single多 Agent 投资决策链,单次 3–5 分钟、约 0.05 美元
两个容易误判的点。①「默认关闭」不代表不可用——盘前与盘中需要你手动启用,否则到点也不会有任何输出。② chart_analyst 虽然还在代码里,但被显式标为 deprecated(弃用)并写明由另外三个 Agent 替代,因此你不需要在界面上找它。
盘中监测的默认参数(agent_catalog.py)config={
    "event_only": True,              # 只对有事件的情况做分析
    "price_alert_threshold": 3.0,    # 涨跌幅阈值(%)
    "volume_alert_ratio": 2.0,       # 量比阈值
    "stop_loss_warning": -5.0,       # 止损提醒(%)
    "take_profit_warning": 10.0,     # 止盈提醒(%)
    "throttle_minutes": 30,          # 同一标的的抑制窗口(分钟)
}
为什么盘中监测默认是「有事件才分析」:event_only=True 加上 30 分钟的抑制窗口,是成本控制设计——每 5 分钟叫一次模型,一整天下来账单会很难看。这也解释了「为什么盘中不一定每次都推」:没达到阈值就没有事件,没有事件就不产出。
Alert conditions

PanWatch 的价格提醒能配什么:五类条件、八种运算符、两种组合逻辑

PanWatch 提醒规则的条件结构是「条件组 + 条件项」。条件项类型与运算符支持范围来自源码,不是界面截图猜测。

条件类型取值来源可用的运算符注意点
price 价格报价的 current_price> >= < <= = == != <> 与 between(闭区间)最常见;整数写法即可
change_pct 涨跌幅报价的 change_pct同上注意与市场涨跌停规则配合,避免在涨停板上反复触发
turnover 成交额报价的 turnover同上单位与量级以数据源为准,建议先用一个宽松值试跑
volume 成交量报价的 volume同上停牌或半日市时数值会明显偏小
volume_ratio 量比优先取报价字段(腾讯源提供),缺失时回退拉 K 线摘要同上美股等源可能没有量比字段,会多一次 K 线请求
组合方式字段取值判定规则适用场景
AND(默认)op: "and"全部条件都命中才算命中「跌破均线 且 放量」这类共振信号
ORop: "or"任一条件命中即算命中「涨 5% 或 跌 5%」这类双向关注
非法或空条件组条件项为空 / 类型不支持判定为不命中(empty_items / unsupported_type)排查时先确认条件项真的存在且类型拼写正确
关于区间条件:between(也接受 in)要求取值是一个二元数组,判定为闭区间——[10, 20] 表示 10 与 20 都算命中。另外条件项不支持嵌套:只能是「一组扁平条件 + and/or」,想做「(A 且 B) 或 C」需要拆成两条规则。
Trigger gates

命中了为什么 PanWatch 还不推:六道门槛与它们的判定顺序

这条顺序是排查 PanWatch 漏推的关键。它写在 _can_trigger() 里,按顺序短路返回——所以「哪个原因被拦」取决于它排在第几道。

顺序门槛不通过时的原因码怎么调整
①规则是否启用disabled界面上的启用开关;repeat_mode=once 命中后会被自动关闭
②是否已过到期时间expired规则可设到期时间;留空表示永不过期
③是否在允许的时段内non_trading仅当规则设为「只在交易时段生效」时拦截;手动触发可绕过
④当日触发次数是否超上限daily_limit注意“当日”按 UTC 分界(北京 08:00 重置)
⑤冷却时间是否已过cooldowncooldown_minutes;按真实时间差计算,不受日界影响
⑥重复模式是否为「只触发一次」且已触发过once_triggered改成重复触发,或新建一条规则
src/modules/market/price_alert_engine.py(_can_trigger 节选)if not rule.enabled:                        return False, "disabled"
if rule.expire_at and now > exp:            return False, "expired"
if rule.market_hours_mode == "trading_only"
        and not _is_trading_time(market):   return False, "non_trading"
if max_per_day > 0 and count >= max_per_day: return False, "daily_limit"
if rule.repeat_mode == "once" and rule.last_trigger_at:
                                            return False, "once_triggered"
if delta_sec < cooldown:                    return False, "cooldown"
return True, "ok"
这张表配合扫描节奏看才有意义:常驻调度默认每 60 秒扫一次(最小 15 秒),带 20 秒抖动,并且 max_instances=1——上一轮没跑完时本轮直接跳过。所以在「取数慢 + 规则多」的情况下,实际扫描间隔可能超过 60 秒。
Notify pipeline

PanWatch 推送这一环怎么工作?命中记录、分钟去重、内容去重与静默时段

在 PanWatch 里,命中不等于推送成功。系统把这两件事分开记录,这也是「没收到消息」排查的抓手。

环节行为可观察的结果
命中落库写入 PriceAlertHit,含触发快照与通知结果字段即使推送失败,命中记录仍在
分钟去重以 UTC 分钟桶作为去重键;同分钟重复写入会回滚并记为 duplicated同一分钟内不会重复产生命中记录
渠道解析规则指定了渠道就用指定渠道(且仅限已启用);未指定则用系统默认渠道改渠道后要确认该渠道仍是启用状态
推送内容标题为「【价格提醒】名称 (代码)」,正文含规则名、现价、涨跌幅,以及最多 4 条命中条件明细条件多的时候正文不会无限长
通知去重(批量 Agent)按 SHA1(Agent 名 + 标题 + 正文前 1200 字符) 做 TTL 窗口去重重启或手动补跑不会重复轰炸
静默时段quiet_hours="HH:MM-HH:MM",支持跨午夜;start == end 视为全天静默;策略默认时区是 UTC夜间静默需要按 UTC 填,或显式改成应用时区
推送失败不会回滚命中。系统会把失败原因写进命中记录(notify_success / notify_error),但规则计数照常增加。因此「没收到消息」有两种完全不同的成因:规则没命中(去看门槛顺序),或命中了但渠道发失败(去看命中记录里的失败原因)。另一个细节:去重逻辑出错时系统倾向「发送」而不是丢弃——这是为了避免因为去重模块故障导致漏报。
Not receiving alerts

PanWatch 没收到提醒怎么办?排查决策表

按这个顺序走,能在几分钟内定位到 PanWatch 的问题是出在规则、门槛还是渠道。

先确认怎么看结论与下一步
规则本身是否启用、是否已过期提醒列表页的开关与到期时间若被 once 自动关闭,需要重新启用或改重复模式
是否被时段门槛挡住规则的「仅交易时段生效」设置 + 该标的所属市场当前是否开市港股/美股节假日会被判为交易日;A 股休市日会被正确拦截
是否达到日上限或仍在冷却命中历史里的触发时间分布日上限按 UTC 日算(北京 08:00 重置);冷却按真实时间差
条件是否真的命中用宽松阈值(如涨跌幅 0.1%)做一次验证若宽松值也不动,问题在数据而不是规则:去查数据源健康度
渠道是否收到渠道列表里该渠道是否启用;是否配了系统默认渠道规则指定了渠道时,只会走指定渠道
是否被静默时段吞掉通知策略里的 quiet_hours 与策略时区默认时区是 UTC,填错时区会让静默窗口整体偏移
扫描是否在正常进行日志里是否有每轮扫描记录;max_instances=1 时上一轮未结束会跳过本轮取数慢会导致扫描变稀;可减少规则数或降低数据源压力
一个常被忽略的验证手段:手动触发扫描时可以绕过交易时段门槛(bypass_market_hours),因此「手动触发有、自动触发没有」几乎总是指向时段门槛或扫描节奏,而不是数据或渠道问题。
FAQ

PanWatch 自动化 Agent 与提醒常见问题

答案基于固定 commit 的源码与官方文档;具体默认值可能随版本调整,以你所用版本的配置为准。

相关页面:TradingAgents 研究链 · 多市场时区与交易日历

三个 Agent 默认都开着吗?

不是。三个 workflow Agent 里只有收盘复盘默认开启(cron 30 15 * * 1-5);盘前分析与盘中监测默认关闭,需要你在界面上手动启用。这就是「装完一天什么都没发生」最常见的原因。

盘中监测为什么每 5 分钟跑一次却不一定推消息?

默认配置是 event_only=True:只有出现达到阈值的事件(涨跌幅 3%、量比 2 等)才做分析;同一标的还有 30 分钟的抑制窗口(throttle_minutes)。这套设计的目的是控制模型调用成本,不是「每次都给你一段话」。

提醒支持哪些条件?能不能做「价格且放量」这种组合?

支持五类条件:价格、涨跌幅、成交额、成交量、量比;运算符含大于/小于/等于/不等与闭区间。组合方式有 AND(默认)与 OR 两种,可以做「跌破某价 且 量比 > 2」这类共振条件。但条件项不支持嵌套,「(A 且 B) 或 C」需要拆成两条规则。

为什么我设了「每天最多 3 次」,感觉不到中午就重置了?

因为日计数的「一天」是按 UTC 算的,重置点对应北京时间 08:00。如果你更在意频率而不是次数,建议用冷却时间(cooldown_minutes)——它按真实时间差计算,语义更稳。

支持哪些通知渠道?

官方 README 列出 Telegram、企业微信、钉钉、飞书、Bark 与自定义 Webhook,底层由 apprise 承担。渠道可以给单条规则指定,也可以设系统默认渠道。国内平台通常不需要代理,Telegram 一般需要自行配代理。

通知能不能去重?会不会重复轰炸?

有两层去重:① 价格提醒按 UTC 分钟桶去重,同一分钟内不重复产生命中;② 批量 Agent 的通知按「Agent 名 + 标题 + 正文前 1200 字符」的哈希做 TTL 窗口去重,所以重启或手动补跑不会重复发同样的内容。此外还有静默时段可用。

手动触发和自动触发的行为一样吗?

不完全一样。手动触发可以绕过交易时段门槛(用于验证规则本身是否正确),而自动触发会按完整的六道门槛判定。因此「手动有、自动没有」通常指向时段门槛或扫描节奏问题。

提醒只是入口,真正花时间的是 AI 分析链

TradingAgents 深度分析一次会跑四类分析师、多空辩论、风控与 PM 决策;它锁定在上游 v0.5.0,节点清单可以从源码数出来。