第四章:交易数据接口与协议

各位同学,今天我们来聊聊交易系统里最基础、也最容易被忽视的一环——数据接口与协议。说实话,我在高频交易这行干了十几年,见过太多团队把精力全砸在策略算法上,结果数据接收这块出了岔子,整个系统直接崩盘。嗯,咱们今天就把这块硬骨头啃下来。

4.1 网络协议栈基础:UDP vs TCP

先问大家一个问题:交易所给你发数据,到底用UDP还是TCP?

我个人习惯,先看延迟要求。高频交易场景下,UDP是绝对的主流。为什么?因为TCP那套三次握手、重传机制,在微秒级的竞争中根本玩不转。你想想看,一个TCP包丢了,要等超时重传,这功夫黄花菜都凉了。

但UDP也有坑。我在项目中遇到过,某次行情数据偶尔丢包,策略直接跑偏,亏了不少钱。后来怎么解决的?我们在FPGA里做了两层校验:第一层是硬件CRC校验,第二层是序列号连续性检查。说白了,UDP虽然不保证可靠,但我们可以自己补上可靠性。

核心结论:

  • UDP:延迟低,适合行情数据(丢包可容忍)
  • TCP:可靠但慢,适合订单管理(不能丢)
  • FPGA实现时,UDP协议栈可以做到<1微秒的解析延迟

这里我给大家一个简单的UDP协议栈结构图,看看FPGA里是怎么拆包的。

FPGA UDP协议栈解析流程 物理层 (PHY) GMII/RGMII接口 MAC层 CRC校验/帧解析 IP层 IP头解析/校验 UDP层 端口匹配 数据流方向 → 典型FPGA处理延迟:PHY(50ns) + MAC(100ns) + IP(80ns) + UDP(60ns) = 约290ns 关键优化点: 1. 流水线处理:每级之间用FIFO缓冲,不阻塞 2. 并行校验:CRC计算与数据接收同时进行 3. 预解析:在接收过程中提前提取关键字段

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消息进来,要经过:

  1. 帧头解析(MAC地址、IP地址、UDP端口)
  2. 应用层消息类型判断
  3. 字段提取与格式转换
  4. 数据分发到不同处理模块

这些步骤全部要流水线化,每级只做一件事,延迟固定。

低延迟数据接收的黄金法则:

  • 能不缓存就不缓存——数据流式处理
  • 能不等待就不等待——并行处理所有校验
  • 能不复制就不复制——指针传递而非数据拷贝
  • 能不中断就不中断——硬件状态机连续运行

4.5 实战经验分享

最后,跟大家分享一个真实案例。某次我为一家做市商搭建交易系统,他们原来的软件方案延迟是5微秒。我们用FPGA重写了数据接收部分,延迟降到了800纳秒。但问题来了——系统太快了,导致策略模块跟不上数据速度。

怎么解决的?我们在FPGA里加了一个速率匹配FIFO,深度设成1024。当策略忙时,数据先缓存起来。但要注意,FIFO不能满,满了就丢数据。所以我们还加了一个背压信号,告诉上游「慢点发」。嗯,这个设计后来成了我们团队的标配。

好了,这一章的内容就到这里。数据接口和协议是交易系统的地基,地基不稳,上层建筑再漂亮也没用。下一章我们会深入讲解订单簿的硬件实现,到时候会用到今天讲的这些知识。

本章核心要点回顾:

知识点 关键结论 延迟指标
UDP vs TCP 行情用UDP,订单用TCP UDP解析<1μs
ITCH协议 固定长度,适合硬件解析 解码<500ns
OUCH协议 订单生命周期管理 状态机<200ns
低延迟接收 流水线+并行校验 总延迟<2μs

公众号:蓝海资料掘金营,微信deep3321