4. 常见行情协议与数据格式
在Tick增量行情与订单簿重建的工程链路中,协议与数据格式决定了“数据长什么样、以什么节奏到达、解析成本有多高”。同一份市场深度,可能以JSON文本、紧凑二进制、FIX/FAST编码或组播报文的形式出现。理解这些差异,是后续做增量合并、序列号校验和低延迟优化的前提。
核心原理:行情协议的三层结构
任何行情接口都可以拆成三层:传输层(TCP、UDP组播、WebSocket)、编码层(JSON、CSV、二进制、FIX/FAST)、语义层(快照、增量、成交、心跳、重传请求)。传输层决定延迟与可靠性,编码层决定解析开销,语义层决定订单簿如何重建。三者组合出交易所常见的接口形态。
关键判断:增量行情必须能识别“序号”与“更新类型”。没有序列号或更新类型的协议,无法可靠重建订单簿,只能做展示级行情。
方法流程:从接口到订单簿的解析路径
以典型交易所增量深度接口为例,处理流程如下:
- 建立连接:WebSocket订阅depth频道,或加入UDP组播组并监听端口。
- 获取快照:通过REST或快照频道拉取当前订单簿全量,记录快照序号。
- 接收增量:持续接收增量消息,每条包含序号、买卖方向、价格、数量、更新类型。
- 序号校验:若增量序号与本地序号不连续,触发重连或重新拉取快照。
- 合并更新:按价格档位更新数量,数量为0则删除该档。
- 输出订单簿:维护买卖两侧有序结构,供策略或风控消费。
不同编码格式的解析差异很大。JSON需要字段名匹配与浮点解析;二进制协议按固定偏移读取;FIX/FAST需要先加载模板再按字段ID解码。下面是一个二进制增量消息的伪代码示例:
// 二进制增量消息:序号(8B) + 方向(1B) + 价格(8B) + 数量(8B)
struct DepthDelta {
uint64_t seq;
uint8_t side; // 0=bid, 1=ask
double price;
double qty; // qty=0 表示删除该档
};
// 解析时按偏移读取,避免逐字段字符串匹配
DepthDelta d;
memcpy(&d.seq, buf + 0, 8);
d.side = buf[8];
memcpy(&d.price, buf + 9, 8);
memcpy(&d.qty, buf + 17, 8);
案例/场景:不同协议在实战中的取舍
| 协议/格式 | 典型场景 | 优点 | 风险与代价 |
|---|---|---|---|
| JSON over WebSocket | 零售交易所、快速接入 | 可读、调试方便、生态成熟 | 体积大、解析慢、GC压力高 |
| CSV快照 | 历史回放、批量导入 | 简单、易存储 | 无增量语义、需自行对齐序号 |
| 二进制协议 | 期货、专业行情源 | 紧凑、低延迟、高吞吐 | 需schema、版本兼容复杂 |
| FIX/FAST | 机构级交易与行情 | 标准化、模板压缩 | 学习曲线陡、模板维护成本高 |
| UDP组播 | 交易所直连、低延迟场景 | 一对多、延迟极低 | 丢包需重传、顺序需自保 |
实战建议:先用JSON/WebSocket打通订单簿重建逻辑,再逐步替换为二进制或组播通道。协议可以换,但序号校验、快照对齐、增量合并这三步不能省。
误区/复盘:协议选择中的常见坑
- 误区一:只看延迟不看可靠性。UDP组播延迟低,但丢包后若无重传或快照恢复机制,订单簿会持续错位。
- 误区二:忽略序号回绕。部分协议序号为32位,长时间运行会回绕,比较时需用无符号差值而非简单大于。
- 误区三:快照与增量时间窗不匹配。先拉快照再订阅增量,中间可能丢失更新;正确做法是“先订阅增量、缓存、再拉快照、按序号对齐”。
- 误区四:JSON浮点直接比较价格。文本解析出的浮点可能存在精度误差,价格档位应使用定点整数或字符串键。
- 误区五:FIX/FAST模板版本不一致。模板变更后未同步更新,会导致字段错位或解析失败,必须做版本校验。
复盘要点:订单簿重建的稳定性,80%取决于协议语义理解是否准确,而不是代码写得多快。先确认“序号、更新类型、快照对齐方式”三件事,再动手写解析器。