2. FIX协议基础

在行情接入场景中,FIX协议之所以能成为跨机构、跨系统的事实标准,核心在于它把“通信可靠性”和“业务语义”拆成了两个清晰层次:会话层负责消息不丢、不重、不乱序,应用层负责表达行情订阅、快照、增量等业务含义。理解这两层结构,是后续解析行情、排查断连与乱序问题的前提。

一、核心原理:会话层与应用层的分工

FIX消息在网络上传输时,物理上是一条条字节流;逻辑上,每条消息由标准头(Standard Header)、消息体(Body)和标准尾(Trailer)组成。标准头中的 BeginString、MsgType、MsgSeqNum、SenderCompID、TargetCompID 等字段,既服务于会话层,也服务于应用层。

  • 会话层:管理登录、心跳、序列号、重传请求、登出。典型消息有 Logon(35=A)、Heartbeat(35=0)、TestRequest(35=1)、ResendRequest(35=2)、Logout(35=5)。
  • 应用层:承载具体业务,如行情订阅、快照、增量刷新。典型消息有 MarketDataRequest(35=V)、MarketDataSnapshotFullRefresh(35=W)、MarketDataIncrementalRefresh(35=X)。

会话层保证“管道”可靠,应用层保证“内容”可理解。行情接入中常见的“收到消息但解析失败”,往往不是网络问题,而是应用层字段缺失或 Tag 值不符合预期。

二、消息格式与 Tag=Value 编码

FIX 采用 Tag=Value 的键值对编码,字段之间用 SOH(ASCII 0x01)分隔。每个 Tag 是数字,Value 是字符串或数字。例如:

8=FIX.4.2|9=112|35=W|34=25|49=BROKER|56=CLIENT|55=EUR/USD|268=2|269=0|270=1.0850|271=1000000|269=1|270=1.0852|271=1500000|10=128|

其中 | 代表 SOH。解析时必须先按 SOH 切分,再按第一个等号拆 Tag 与 Value。注意:Value 内部可能包含等号,因此只能按第一个等号分割。

校验要点:BodyLength(9) 是从 MsgType 开始到 CheckSum 前一个 SOH 的字节数;CheckSum(10) 是整条消息(不含 10 字段本身)所有字节和对 256 取模后格式化为三位数字。行情网关常因校验失败直接丢弃消息。

三、常用字段与消息类型清单

Tag字段名含义典型值
35MsgType消息类型V / W / X / 0 / A
34MsgSeqNum消息序列号递增整数
49SenderCompID发送方标识BROKER
56TargetCompID接收方标识CLIENT
55Symbol交易对/代码EUR/USD
268NoMDEntries行情条目数2
269MDEntryType条目类型0=买价 1=卖价
270MDEntryPx价格1.0850
271MDEntrySize数量1000000

行情接入最常用的三类消息:35=V 用于订阅,35=W 用于全量快照,35=X 用于增量更新。增量消息中,279=0 表示新增、279=1 表示修改、279=2 表示删除,解析时必须结合 269 判断是买盘还是卖盘。

FIX 消息结构与会话/应用分层 标准头 Standard Header 8=BeginString | 9=BodyLength | 35=MsgType | 34=MsgSeqNum | 49=SenderCompID | 56=TargetCompID 消息体 Body(应用层业务字段) 55=Symbol | 268=NoMDEntries | 269=MDEntryType | 270=MDEntryPx | 271=MDEntrySize 279=MDUpdateAction(0新增 1修改 2删除) 行情订阅:35=V;快照:35=W;增量:35=X 标准尾 Trailer 10=CheckSum(三位数字,整条消息字节和对256取模) 会话层:Logon/Heartbeat/ResendRequest/Logout 应用层:MarketDataRequest/Snapshot/Incremental

四、案例场景:一条增量行情消息的解析

假设客户端订阅 EUR/USD 后收到如下增量消息(SOH 用 | 表示):

8=FIX.4.2|9=145|35=X|34=102|49=BROKER|56=CLIENT|55=EUR/USD|268=2|279=0|269=0|270=1.0850|271=1000000|279=1|269=1|270=1.0853|271=800000|10=076|

解析步骤:先校验 9 与 10;再读取 35=X 确认是增量;然后按 268=2 循环读取两组条目。第一组 279=0、269=0 表示新增买价 1.0850、数量 1000000;第二组 279=1、269=1 表示修改卖价 1.0853、数量 800000。若把 269 与 279 顺序读错,就会把买卖方向或更新动作弄反,导致盘口错乱。

实战建议:解析器应把“会话层字段”和“应用层字段”分开存储。会话层字段用于序列号管理和重传判断,应用层字段用于行情组装。两者混在一起,后续排查断连与行情错乱会非常困难。

五、常见误区与复盘

  1. 忽略 BodyLength 与 CheckSum 校验:部分网关不校验也能收,但生产环境一旦开启严格校验,消息会被静默丢弃。
  2. 用等号分割所有字段:Value 中可能含等号,必须只按第一个等号拆分。
  3. 把 35=V 当成行情数据:V 是订阅请求,真正的行情在 W 和 X 中。
  4. 不处理序列号缺口:发现 34 不连续时应发送 ResendRequest,否则行情会永久缺失。
  5. 忽略 279 更新动作:增量消息必须结合 279 与 269 才能正确维护盘口。

复盘结论:FIX 行情接入的稳定性,70% 取决于会话层序列号与心跳处理,30% 取决于应用层字段解析。先把会话层跑通,再打磨应用层解析,是最高效的接入路径。