第四章:交易数据接口与协议
各位同学,今天我们来聊聊交易系统里最基础、也最容易被忽视的一环——数据接口与协议。说实话,我在高频交易这行干了十几年,见过太多团队把精力全砸在策略算法上,结果数据接收这块出了岔子,整个系统直接崩盘。嗯,咱们今天就把这块硬骨头啃下来。
4.1 网络协议栈基础:UDP vs TCP
先问大家一个问题:交易所给你发数据,到底用UDP还是TCP?
我个人习惯,先看延迟要求。高频交易场景下,UDP是绝对的主流。为什么?因为TCP那套三次握手、重传机制,在微秒级的竞争中根本玩不转。你想想看,一个TCP包丢了,要等超时重传,这功夫黄花菜都凉了。
但UDP也有坑。我在项目中遇到过,某次行情数据偶尔丢包,策略直接跑偏,亏了不少钱。后来怎么解决的?我们在FPGA里做了两层校验:第一层是硬件CRC校验,第二层是序列号连续性检查。说白了,UDP虽然不保证可靠,但我们可以自己补上可靠性。
核心结论:
- UDP:延迟低,适合行情数据(丢包可容忍)
- TCP:可靠但慢,适合订单管理(不能丢)
- FPGA实现时,UDP协议栈可以做到<1微秒的解析延迟
这里我给大家一个简单的UDP协议栈结构图,看看FPGA里是怎么拆包的。
4.2 市场数据格式:ITCH协议
讲完底层协议,咱们看看上层数据格式。纳斯达克的ITCH协议,可以说是高频交易领域的通用语言。这个协议设计得很有意思——它用二进制格式,每个字段都是固定长度,解析起来特别快。
我记得第一次在FPGA里实现ITCH解析器时,发现一个有趣的现象:ITCH的消息头只有2个字节的消息类型 + 2个字节的消息长度。就这么简单。但正是这种简单,让硬件实现变得异常高效。
ITCH消息结构示例:
// 订单簿增量更新消息 (类型 'A')
struct ITCH_AddOrder {
uint16_t msg_length; // 消息总长度
char msg_type; // 'A' = 新增订单
uint64_t order_id; // 订单编号
char side; // 'B'=买, 'S'=卖
uint32_t shares; // 数量
char stock[8]; // 股票代码
uint32_t price; // 价格 (4字节整数)
// ... 后续字段
};
为什么ITCH适合FPGA?说白了,它的设计哲学就是「让硬件好干活」。固定长度、无变长字段、无依赖关系,这些特性让FPGA可以流水线式地处理每条消息。我在一个项目中,用FPGA实现了ITCH解码器,从网口到应用层,总延迟控制在500纳秒以内。
4.3 订单管理协议:OUCH协议
ITCH是看行情,OUCH是下订单。这两个协议经常配对使用。OUCH协议比ITCH更简单,因为它只处理订单生命周期管理。
这里有个坑,我曾经踩过。OUCH协议虽然简单,但它的确认机制很关键。交易所发回来的确认消息,必须和原始订单请求一一对应。如果对应错了,后果很严重——你可能以为订单成交了,实际上根本没进去。
OUCH实现注意事项:
- 订单ID必须唯一,建议用时间戳+计数器生成
- 确认消息的序列号要严格递增,否则说明丢包
- FPGA里要维护一个订单状态机:NEW → ACK → FILL/CANCEL
- 超时处理:如果3秒没收到确认,自动重发
4.4 低延迟数据接收的硬件实现
好,终于到了最核心的部分——怎么在FPGA里实现低延迟数据接收。我给大家总结几个关键点:
4.4.1 时钟域处理
网口过来的数据是125MHz的GMII时钟,内部逻辑可能是200MHz或更高。跨时钟域处理是第一个坎。我个人习惯用异步FIFO,深度设成16就够了,因为数据是流式的,不需要缓存太多。
4.4.2 数据对齐与校验
以太网帧有前导码和帧起始定界符,这些都要在硬件里剥离。CRC校验要并行计算,不能串行算,否则延迟受不了。我一般用查表法,一个时钟周期就能出结果。
4.4.3 消息解析流水线
这是最体现功力的地方。一条ITCH消息进来,要经过:
- 帧头解析(MAC地址、IP地址、UDP端口)
- 应用层消息类型判断
- 字段提取与格式转换
- 数据分发到不同处理模块
这些步骤全部要流水线化,每级只做一件事,延迟固定。
低延迟数据接收的黄金法则:
- 能不缓存就不缓存——数据流式处理
- 能不等待就不等待——并行处理所有校验
- 能不复制就不复制——指针传递而非数据拷贝
- 能不中断就不中断——硬件状态机连续运行
4.5 实战经验分享
最后,跟大家分享一个真实案例。某次我为一家做市商搭建交易系统,他们原来的软件方案延迟是5微秒。我们用FPGA重写了数据接收部分,延迟降到了800纳秒。但问题来了——系统太快了,导致策略模块跟不上数据速度。
怎么解决的?我们在FPGA里加了一个速率匹配FIFO,深度设成1024。当策略忙时,数据先缓存起来。但要注意,FIFO不能满,满了就丢数据。所以我们还加了一个背压信号,告诉上游「慢点发」。嗯,这个设计后来成了我们团队的标配。
好了,这一章的内容就到这里。数据接口和协议是交易系统的地基,地基不稳,上层建筑再漂亮也没用。下一章我们会深入讲解订单簿的硬件实现,到时候会用到今天讲的这些知识。
本章核心要点回顾:
| 知识点 | 关键结论 | 延迟指标 |
|---|---|---|
| UDP vs TCP | 行情用UDP,订单用TCP | UDP解析<1μs |
| ITCH协议 | 固定长度,适合硬件解析 | 解码<500ns |
| OUCH协议 | 订单生命周期管理 | 状态机<200ns |
| 低延迟接收 | 流水线+并行校验 | 总延迟<2μs |
公众号:蓝海资料掘金营,微信deep3321