系列文章第 8 篇:个人开发者怎样搭一条只读行情监控工作流?
作者: TickDB Research · 发布: 2026/6/4 · 阅读: 2
标签: S06, 知乎, 行情监控
这是 TickDB 实时行情接入系列的第 8 篇。前一篇解决“WebSocket 订阅”,本文解决“只读行情监控工作流”。
很多行情监控 Demo 的第一步都很顺:连上 WebSocket,订阅一个品种,控制台开始打印价格。
真正的问题通常在第二天出现:连接断过,脚本还在跑但已经没有有效更新;阈值被重复触发,消息刷屏;通知通道失败了,日志里却看不出原因;重启后继续收到了数据,但你已经不知道当前状态基准还准不准。
所以,只读行情监控的复杂度不在“能不能连上”,而在于把失败路径拆开处理。
我更建议把它拆成五层:
| 层级 | 负责什么 | 典型失败 |
|---|---|---|
| 数据接入 | 从 REST 或 WebSocket 读取行情 | 连接断开、订阅失败、响应异常 |
| 状态基准 | 维护最新状态、基准值、校准点 | 重连后状态失真、旧数据被当成新状态 |
| 规则判断 | 判断是否需要触发提醒 | 误报、重复触发、异常值导致刷屏 |
| 通知通道 | 把提醒发到外部渠道 | 通知失败、超时、第三方通道不可用 |
| 自监控 | 观察脚本自身是否健康 | 进程仍在但无有效数据、异常被吞掉 |
这篇文章只讨论只读监控的工程结构。TickDB 可以放在“数据接入层”作为行情数据来源,但它不会替你解决状态维护、规则设计、通知可靠性和脚本运行监控这些工程问题。
1. 先分清 REST 和 WebSocket 的职责
做行情监控时,不要把“行情 API”当成一种东西。
更稳的拆法是:
| 接入方式 | 更适合做什么 | 不适合直接承担什么 |
|---|---|---|
| REST | 一次性查询、启动时校准、异常后补一次当前快照 | 持续推送、长期连接状态管理 |
| WebSocket | 持续接收订阅更新 | 证明断线期间所有消息都被补齐 |
| MCP / Skill / CLI | 特定工具环境或自动化入口 | 不能和 REST 地址、WebSocket 频道混写 |
个人开发者最容易犯的错,是把 WebSocket 连通当成“监控系统完成”。
更合理的做法是:WebSocket 负责持续接入,REST 负责在启动、重启、异常恢复时提供一次可核对的状态基准。两者的职责不同,不要把 REST endpoint、WebSocket 频道和工具调用名写成同一套配置。
2. 五层工作流长什么样?
可以先用一张非常朴素的架构表来约束实现:
| 层级 | 输入 | 输出 | 最小状态 |
|---|---|---|---|
| 数据接入 | REST 响应 / WebSocket 消息 | 标准化行情事件 | 最近一次成功读取时间、错误原因 |
| 状态基准 | 行情事件、校准快照 | 当前可判断状态 | 最新价、基准价、更新时间 |
| 规则判断 | 当前状态、规则配置 | 是否触发提醒 | 上次触发时间、冷却期、去重键 |
| 通知通道 | 提醒事件 | 发送结果 | 成功 / 失败 / 待重试 |
| 自监控 | 各层运行状态 | 健康状态 | 心跳、异常计数、最近有效事件 |
如果你只写了第一层,脚本当然可以跑。但只要发生一次断线、一次误报或一次通知失败,就很难判断问题到底在哪。
3. “模块 / 失败路径 / 最小处理方式”清单
真正能让个人项目变可靠的,往往不是把脚本写长,而是每层至少处理一个失败路径。
| 模块 | 失败路径 | 最小处理方式 |
|---|---|---|
| 数据接入 | WebSocket 断开或订阅失败 | 记录错误、退避重试、恢复后重新校准状态 |
| 数据接入 | REST 查询失败 | 保留失败原因,不用空值覆盖当前状态 |
| 状态基准 | 重连后基准失真 | 恢复后重新读取一次当前状态,标记校准时间 |
| 状态基准 | 收到旧事件或异常事件 | 丢弃无法判断的新旧状态,不强行触发提醒 |
| 规则判断 | 阈值附近反复触发 | 加冷却期、去重键和最小变化幅度 |
| 规则判断 | 单次异常值导致误触发 | 增加简单异常过滤,必要时要求连续确认 |
| 通知通道 | 第三方通知失败 | 记录发送结果,允许有限重试,保留本地日志 |
| 通知通道 | 通知发送太频繁 | 按规则维度限流,不把每个 tick 都发出去 |
| 自监控 | 脚本进程退出 | 使用外部守护或定时检查,但不把它写成稳定性承诺 |
| 自监控 | 脚本还活着但没有有效数据 | 记录最近有效事件时间,超过阈值触发自检提醒 |
这张表比一段完整脚本更适合作为第一版设计文档。因为它会逼你回答:每层失败时,系统应该降级、重试、跳过,还是停止判断?
4. 一个最小目录结构
如果用 Python 写,目录可以先保持很小:
market-watch/
app.py
config.example.yaml
adapters/
rest_client.py
ws_client.py
core/
state_store.py
rule_engine.py
event_model.py
notify/
sender.py
runtime/
healthcheck.py
logger.py
每个模块只做一件事:
ws_client:
持续接收行情消息
失败时抛出明确错误,不直接发通知
rest_client:
做一次性查询
用于启动、重启、异常后的状态校准
state_store:
保存最新状态和基准状态
记录最近一次有效更新时间
rule_engine:
接收状态
判断是否需要生成提醒事件
处理冷却期和去重
sender:
发送提醒
返回发送成功或失败原因
healthcheck:
检查最近有效事件时间
检查异常计数
输出脚本自身健康状态
注意这里没有把通知 SDK、部署工具、WebSocket 频道、REST 路径写死。发布文章时如果没有逐项核验,就应该停在这个抽象层,避免给读者一份看似可复制、实际不可靠的配置。
5. 状态基准比“重连成功”更重要
WebSocket 重连成功,只说明你从恢复后的某个时刻继续接收数据。它不能自动证明断线期间的所有变化都已补齐。
所以恢复后最好做一件事:重新建立状态基准。
常见方式包括:
| 场景 | 可选做法 |
|---|---|
| 脚本首次启动 | 用 REST 做一次当前状态校准,再进入持续订阅 |
| WebSocket 断线恢复 | 标记恢复时间,重新读取一次当前状态 |
| 长时间没有有效事件 | 暂停规则判断,先做接入层和状态层自检 |
| 规则触发前状态不可信 | 不发送提醒,先记录“状态待校准” |
这类处理会让系统少一点“看起来很实时”的错觉,多一点可排查性。
6. 规则判断不要写成交易判断
只读行情监控里的规则判断,建议只做工程提醒,例如:
| 规则类型 | 可以做 | 不要扩写成 |
|---|---|---|
| 价格变化提醒 | 达到自定义阈值后提示用户查看 | 交易动作建议 |
| 波动提醒 | 提醒某个品种变化较大 | 盈亏结论 |
| 数据异常提醒 | 提醒数据长时间未更新或状态待校准 | 数据源绝对可用判断 |
| 系统异常提醒 | 提醒脚本、连接或通知通道异常 | 稳定运行承诺 |
规则层至少要有三个小东西:
- 冷却期:同一规则不要连续刷屏。
- 去重键:同一个状态不要重复提醒。
- 异常处理:状态不可信时先停止判断,而不是硬发提醒。
这也是我不建议把第一版写成“大而全脚本”的原因。脚本越长,越容易把接入、判断和通知混在一起,最后任何一层失败都会表现成“监控坏了”。
7. 通知通道也要按失败来设计
通知通道很容易被低估。
邮件、聊天工具、Webhook、企业通知服务都可能失败。它们失败时,行情接入层可能完全正常,规则判断层也可能完全正常,只是最后一步没有送达。
最小处理方式是:
| 处理点 | 建议 |
|---|---|
| 发送结果 | 必须记录成功或失败 |
| 重试 | 有限重试,不无限循环 |
| 降级 | 失败时至少写入本地日志 |
| 限流 | 避免高频触发导致通道被限制 |
| 可观察 | 通知失败本身也应该进入自监控 |
不要在文章或代码里暗示通知一定送达。个人项目尤其应该承认这一点:通知只是一个外部通道,不是系统的最终保证。
8. 脚本自己也要被监控
只读行情监控还有一个很现实的问题:脚本可能看起来还在跑,但已经没有有效数据。
自监控层至少记录这些信息:
| 指标 | 用途 |
|---|---|
| 最近一次有效行情事件时间 | 判断是否长时间无有效数据 |
| 最近一次 REST 校准时间 | 判断状态基准是否过旧 |
| WebSocket 最近连接状态 | 区分连接异常和规则无触发 |
| 通知最近发送结果 | 判断提醒是否卡在通道层 |
| 异常计数 | 判断是否进入频繁失败状态 |
这里可以接入你熟悉的日志、定时任务或守护工具。但如果没有核验具体工具的命令和配置,就不要把它写成教程级部署步骤。
9. TickDB 在这个工作流里的位置
在这条工作流里,TickDB 的位置很清楚:它是数据接入层的一种行情数据来源。
你可以把它用于:
| 场景 | 更自然的入口 |
|---|---|
| 启动时读取当前状态 | REST |
| 异常恢复后做状态校准 | REST |
| 持续接收行情更新 | WebSocket |
| 在 AI 工具环境中查询行情 | 对应工具入口,但要和 REST / WebSocket 分清 |
但它不替代下面这些事情:
| 不替代 | 原因 |
|---|---|
| 状态基准设计 | 这是你的业务状态管理 |
| 规则判断 | 阈值、冷却期、去重都由你定义 |
| 通知通道 | 第三方通道成功与否需要你处理 |
| 自监控 | 脚本是否健康运行是工程运行问题 |
也就是说,接入 TickDB 之后,监控系统还没有完成。你只是把“数据从哪里来”这件事确定了。
10. 本文不能保证什么
这篇文章刻意只讨论只读行情监控的工程拆分,因此不能保证:
| 不能保证 | 说明 |
|---|---|
| 断线期间的所有推送都被补齐 | 重连后应重新校准状态,不应假设历史变化自动完整恢复 |
| 通知一定送达 | 第三方通知通道会失败,需要日志、重试和降级 |
| 脚本长期稳定运行 | 进程、网络、配置和外部服务都可能出问题 |
| 适用于高频场景 | 本文不做延迟、吞吐或性能排名判断 |
| 可用于交易执行 | 本文只讨论只读监控和工程提醒 |
| 能替代风控或验证系统 | 规则提醒不是业务结论,也不是收益证明 |
如果你要把它推进到真实长期运行,下一步不是继续加功能,而是先把每一层的失败日志和恢复动作补齐。
系列导航
| 系列 | 主题 | 建议阅读场景 |
|---|---|---|
| S00 | TickDB 产品总入口与首次验证路线图 | 第一次了解 TickDB,先判断入口怎么选 |
| S01 | REST 完成一次行情查询 | 想做启动校准、一次性查询或接口验证 |
| S02 | WebSocket 订阅、心跳与恢复边界 | 想做持续订阅,先理解连接生命周期 |
| S05 | symbol、字段与 timestamp 的数据语义 | 已经拿到数据,但担心字段和时间理解错误 |
| S08 | 接入 FAQ:鉴权、空数据、字段与时间单位 | 遇到鉴权、空数据、时间单位等常见问题时排查 |
只读行情监控不是一个“连上就完事”的脚本题。它更像一个小型工程系统:数据怎么来,状态怎么算,规则怎么触发,通知怎么失败,脚本怎么自证还活着。把这五层拆开,第一版就已经比大多数 Demo 更接近可维护。
通过 TickDB API 获取实时行情数据
一个 API 接入外汇、加密货币、美股、港股、A股、贵金属和全球指数的实时行情。支持 WebSocket 低延迟推送,免费开始使用。
免费领取 API Key查看 API 文档