本文从交易所产生市场事件开始,沿着行情发布系统、交易所接入网络和券商行情网关,一直讲到券商收到原始行情。重点不是行情程序如何解码或构建订单簿,而是先回答一个更基础的问题:量化机构最终使用的行情,在进入券商内部网络之前经历了哪些系统,以及这些系统如何保证数据来源、完整性和可恢复性。
本篇范围:交易所撮合结果成为行情消息,直到券商行情接入节点收到数据。券商内部 UDP 组播、Colo 网络和服务器网卡在下一篇讨论;网卡之后的行情程序处理放在后续系列。
1. 为什么先研究交易所到券商
行情程序出现跳号、断流或延迟突增时,问题不一定发生在行情程序内部。数据可能在更早的位置已经缺失:
- 交易所行情会话异常;
- 券商接入链路中断;
- 券商行情接入节点积压;
- 主备节点共享同一个上游故障点;
- 券商收到的数据本身已经不完整。
如果不了解上游链路,系统只能看到“本地少了一条消息”,却无法判断消息究竟是交易所未发布、链路未送达,还是券商未接收。
因此,行情可靠性不是从订单簿程序开始,而是从行情源、接入权限、通信链路和接收节点开始。
2. 本篇的系统边界
本文涉及四类角色:
| 角色 | 主要职责 | 本文关注点 |
|---|---|---|
| 交易所撮合系统 | 接收申报并形成成交结果 | 产生委托、撤单、成交等市场事件 |
| 交易所行情发布系统 | 把市场事件转换为行情产品 | 消息类型、频道、序号、状态和发布会话 |
| 交易所接入网络 | 把行情送到市场参与者 | 链路、权限、会话和主备路径 |
| 券商行情接入节点 | 接收并验证交易所行情 | 会话维护、完整性检查、恢复和原始记录 |
本文不讨论:
- 券商如何向 Colo 客户发送 UDP 组播;
- 量化服务器网卡如何收包;
- A/B 消息如何去重合并;
- Channel 和 Seq 如何驱动订单簿;
- 行情解码、标准化和订单簿构建。
这些内容需要建立在“上游数据已经可靠到达”的前提上,因此放在后续文章。
3. 撮合系统和行情发布系统不是同一个程序
初学者容易把交易所理解成一台服务器:投资者订单进入交易所,交易所立刻把行情发出来。真实系统通常会明确分离交易处理和行情发布职责。
3.1 撮合系统负责什么
撮合系统负责处理交易申报,例如:
- 接收买卖订单;
- 检查申报是否符合交易规则;
- 按价格和时间优先等规则撮合;
- 形成成交;
- 处理撤单;
- 更新交易状态。
它的核心输出不是给量化机构直接使用的网络包,而是一系列有明确先后关系的市场事件。
3.2 行情发布系统负责什么
行情发布系统把市场事件整理成不同的行情产品,并通过规定的接口对外发布。它通常需要处理:
- 市场状态;
- 证券状态;
- 行情快照;
- 逐笔委托;
- 逐笔成交;
- 频道心跳;
- 会话心跳;
- 可恢复数据的重传。
行情发布系统存在的原因是,交易处理和数据分发面对的目标不同。撮合系统强调交易规则与状态正确;行情系统强调大量市场参与者能够连续、及时地收到数据。
4. 券商接入的不是一个模糊的“Level-2”
“Level-2 行情”只是一个宽泛称呼,不能据此判断具体能收到什么数据。实际接入前需要明确行情产品、市场范围和接口版本。
4.1 常见行情类型
| 行情类型 | 表达的内容 | 是否能还原订单级变化 |
|---|---|---|
| 快照行情 | 某个时刻的盘口和累计统计 | 通常不能 |
| 逐笔委托 | 新增、撤销等订单事件 | 取决于协议字段 |
| 逐笔成交 | 每笔成交及关联信息 | 取决于协议字段 |
| 市场状态 | 集合竞价、连续竞价、休市、闭市等 | 不直接构建盘口,但决定消息语义 |
| 证券状态 | 停牌、复牌、风险警示等 | 不直接构建盘口,但影响可交易性 |
如果只有十档快照,接收端可以看到每个价格档位的聚合数量,但无法知道这些数量由哪些具体订单组成。要构建更精细的本地订单簿,通常需要逐笔委托、逐笔成交以及足够完整的订单标识和事件语义。
4.2 接入前必须确认的清单
- 行情产品名称;
- 覆盖的交易所和证券类型;
- 是否包含逐笔委托、逐笔成交和撤单;
- 是否包含市场状态和证券状态;
- 协议版本及生效日期;
- 价格和数量的单位;
- 频道划分方式;
- 序号重置规则;
- 快照和逐笔分别是否支持恢复;
- 盘中重新接入时如何同步。
这里最危险的问题不是完全收不到行情,而是只收到部分产品或字段,程序仍然运行,却误以为数据完整。
5. 交易所行情网关是什么
行情网关可以理解为交易所对市场参与者提供的标准化接入边界。券商的用户行情系统与行情网关建立会话,接收规定格式的实时行情。
以上海证券交易所公开的 BINARY 行情网关规范为例,用户行情系统通过 TCP 与行情网关建立会话,登录成功后接收市场状态、快照、逐笔行情和频道心跳;会话中还包含消息序号、心跳和重传机制。该公开接口只是一个具体例子,不能据此推断所有交易所、所有行情产品和所有券商接入方式完全相同。
5.1 会话层解决什么问题
会话层主要负责:
- 登录与身份确认;
- 协议版本协商;
- 判断连接是否仍然存活;
- 维护会话消息序号;
- 发现连接异常并重建会话;
- 对可恢复数据发起请求。
它解决的是“双方是否在正常通信”,而不是完整代替业务层的逐笔连续性检查。
5.2 为什么不能把 TCP 等同于绝不丢数据
TCP 可以保证一个正常连接内的字节流按序到达,但不能解决全部问题:
- 上游应用可能根本没有生成某条业务消息;
- 接收程序可能处理过慢,导致上游主动断开;
- 连接中断后需要重新建立会话和恢复状态;
- 业务频道仍需用自己的业务序号判断是否完整;
- 券商内部重新封装后,后续链路可能改用 UDP。
因此,传输协议可靠不等于整条行情业务链路天然可靠。
6. 交易所到券商之间的网络
交易所行情不会经过普通互联网随意传输。市场参与者通常通过受控的接入网络、专用线路或交易所认可的技术服务体系连接行情网关。
从系统设计角度,需要关注的不是线路名称,而是以下属性:
- 是否存在 A/B 两条物理路径;
- 两条路径是否经过独立设备;
- 是否共享同一运营商、机房或光缆;
- 链路带宽和峰值包速率是否足够;
- 链路错误、抖动和中断是否可监控;
- 主备切换后行情会话如何恢复;
- 网络安全策略是否可能阻断会话或重传。
6.1 “两条线”不一定是真冗余
下面的结构看起来有两条链路,但仍有明显单点:
如果单一上游节点故障,两条链路会同时失效。真正的冗余需要分析完整故障域:
实际拓扑是否达到这种独立程度,需要以交易所和券商提供的正式设计为准,不能只根据服务器上有两个接口进行推断。
7. 券商行情接入节点负责什么
券商行情接入节点是交易所接口和券商内部行情系统之间的边界。它通常接收交易所原始行情,然后把数据交给内部标准化、分发或录制系统。
7.1 输入
- 交易所实时行情会话;
- 行情账户和权限;
- 协议版本配置;
- 交易日和证券基础信息;
- 重传或恢复响应;
- 时间同步信号。
7.2 输出
- 已接收的原始行情消息;
- 会话状态;
- 频道和业务连续性状态;
- 缺口与恢复状态;
- 原始行情记录;
- 供内部系统使用的行情流。
7.3 它负责什么
- 建立并维护行情会话;
- 检查消息格式和基础校验;
- 跟踪连接、心跳和序号;
- 发现缺口并执行协议允许的恢复;
- 保存足够的原始证据;
- 把健康状态传递给下游。
7.4 它不负责什么
券商行情接入节点不一定负责:
- 为每个 Colo 客户直接发包;
- 给量化机构构建订单簿;
- 保证下游交换网络绝不丢包;
- 保证所有供应商标准化后的字段仍与交易所原始字段一一对应。
这些职责可能属于后续的行情分发、标准化或客户接入系统。
8. 券商接入节点常见的故障
| 问题 | 直接表现 | 风险 | 解决方向 |
|---|---|---|---|
| 行情会话未登录 | 完全没有某类行情 | 盘前即不可用 | 权限、地址、版本和登录时点检查 |
| 心跳超时或连接断开 | 行情突然停止 | 下游使用陈旧数据 | 自动重连、状态降级、主备切换 |
| 接入程序处理过慢 | 延迟上升或被上游断开 | 数据积压和缺失 | 容量测试、进程隔离、队列监控 |
| 协议版本不匹配 | 解码异常或字段错位 | 静默数据错误 | 版本绑定、灰度验证、原始包留存 |
| 权限不完整 | 部分市场或产品缺失 | 系统误判数据完整 | 盘前产品清单比对 |
| 主备共享单点 | A/B 同时异常 | 冗余失效 | 绘制真实故障域并拆除共同依赖 |
| 重传不可用 | 缺口无法恢复 | 下游状态长期不可信 | 独立备用源、缓存和重同步方案 |
8.1 最危险的是静默错误
完全断流通常很容易发现。更危险的是:
- 价格倍率错误;
- 某种消息类型被过滤;
- 新协议字段没有被识别;
- 部分频道没有订阅;
- A/B 两个接入节点使用不同配置;
- 时间戳来源被错误理解。
这类问题可能不会导致进程崩溃,却会把错误数据持续交给下游。
9. 时间同步从上游就必须开始
在券商接入层,至少可能出现以下时间:
- 交易所消息中的时间;
- 券商网络接口接收时间;
- 券商接入程序读取时间;
- 券商向内部系统发布时间。
如果时间定义不清或设备未同步,就无法可靠分析:
- 交易所到券商的传播时间;
- A/B 哪一路更快;
- 延迟来自网络还是程序;
- 主备切换前后的时间变化;
- 某条异常消息究竟先发生还是后发生。
需要为每个时间戳记录:
时间戳名称
生成设备
生成位置
使用的时钟源
精度与分辨率
是否可能回跳
是否与其他设备可比较延迟计算还应使用单调时钟,避免墙上时间调整造成负延迟或超时判断错误。
10. 上游链路应该监控什么
10.1 行情产品层
- 当前收到哪些市场和产品;
- 每类消息的数量;
- 是否收到市场状态和频道心跳;
- 盘前预期产品与实际产品是否一致。
10.2 会话层
- 登录状态;
- 会话建立和断开次数;
- 心跳超时;
- 会话消息序号;
- 上游主动注销原因;
- 重传请求和结果。
10.3 业务层
- 各频道最新业务序号;
- 缺口、重复和回退;
- 快照与逐笔活跃状态;
- 交易阶段是否合理;
- A/B 节点消息数量差异。
10.4 基础设施层
- 链路状态;
- 端口错误;
- 峰值流量和包速率;
- CPU、内存和接收队列压力;
- 时间同步状态;
- 原始记录是否持续写入。
11. 如何验证交易所到券商链路
11.1 盘前验证
- 验证交易日和协议版本;
- 验证行情账户和产品权限;
- 验证 A/B 节点都能建立会话;
- 验证市场状态和频道心跳;
- 对比两个节点的消息数量和关键字段;
- 检查时间同步;
- 确认原始行情录制已启动;
- 行情健康状态通过后才允许下游进入就绪状态。
11.2 故障注入
- 主动断开一条接入链路;
- 重启一个接入节点;
- 模拟会话心跳超时;
- 模拟协议版本不匹配;
- 模拟某个频道短暂缺口;
- 验证重传、切换和状态上报;
- 验证异常期间不会把“连接仍在”误报为“行情完整”。
11.3 盘后对账
- 对比 A/B 原始消息数量;
- 统计每个频道缺口和重传;
- 检查会话中断时间;
- 分析延迟分布而不只看平均值;
- 保存协议、配置和节点版本;
- 对异常时间段执行原始消息回放。
12. 关键设计取舍
12.1 低延迟和可恢复性
为了降低延迟,可以减少缓存和处理层次;但缓存过少会降低突发吸收和恢复能力。接入层不能只追求最快转发,还要保留足够的原始数据和状态,才能在下游发现问题时追溯原因。
12.2 主备热运行和资源成本
冷备节点成本低,但故障后需要建立会话、同步状态和追赶数据。高频场景通常更需要主备节点持续热运行,使备用源始终知道自己是否完整,而不是故障发生后才启动。
12.3 原始协议和内部统一协议
保留原始协议有利于审计和精确追溯,但会增加下游适配复杂度。转换成统一协议便于内部使用,却引入字段丢失、语义转换和版本管理风险。后续文章会单独讨论券商内部如何选择透传、标准化或重建后分发。
13. 仍需向交易所或券商确认的问题
以下信息不能通过通用架构推断,必须以正式接口文档和现场拓扑为准:
- 实际行情产品及协议版本;
- A/B 接入节点是否对应独立上游发布节点;
- 两条线路是否真正物理独立;
- 逐笔和快照的恢复机制;
- 可恢复历史长度;
- 券商接入节点是否重新编号或过滤消息;
- 券商内部是否保留交易所原始 Channel 和业务 Seq;
- 时间戳的生成位置;
- 市场参与者可获得哪些上游监控信息。
未获得正式资料前,这些内容都应标记为“未确认”,不能写成既定事实。
14. 下一篇:券商如何把行情送入 Colo
券商收到交易所行情后,通常还要经过内部行情总线、分发节点、UDP 组播、A/B 交换网络和 Colo 接入交换机,最终到达量化服务器网卡。
下一篇将讨论:
- 券商原始透传、标准化和订单簿输出的区别;
- UDP 组播为什么适合一对多行情分发;
- A/B 双路、双节点和双源如何区分;
- VLAN、IGMP、交换机缓存和微突发;
- 光纤、光模块和服务器网卡前的故障定位。
参考资料
本文仅为个人学习笔记和系统架构设计整理,不构成任何投资建议或交易建议。高频量化交易系统涉及市场风险、技术风险、合规风险和运维风险,任何实盘部署都应经过充分测试、独立验证和风险评估。