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 | 字段名 | 含义 | 典型值 |
|---|---|---|---|
| 35 | MsgType | 消息类型 | V / W / X / 0 / A |
| 34 | MsgSeqNum | 消息序列号 | 递增整数 |
| 49 | SenderCompID | 发送方标识 | BROKER |
| 56 | TargetCompID | 接收方标识 | CLIENT |
| 55 | Symbol | 交易对/代码 | EUR/USD |
| 268 | NoMDEntries | 行情条目数 | 2 |
| 269 | MDEntryType | 条目类型 | 0=买价 1=卖价 |
| 270 | MDEntryPx | 价格 | 1.0850 |
| 271 | MDEntrySize | 数量 | 1000000 |
行情接入最常用的三类消息:35=V 用于订阅,35=W 用于全量快照,35=X 用于增量更新。增量消息中,279=0 表示新增、279=1 表示修改、279=2 表示删除,解析时必须结合 269 判断是买盘还是卖盘。
四、案例场景:一条增量行情消息的解析
假设客户端订阅 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 顺序读错,就会把买卖方向或更新动作弄反,导致盘口错乱。
实战建议:解析器应把“会话层字段”和“应用层字段”分开存储。会话层字段用于序列号管理和重传判断,应用层字段用于行情组装。两者混在一起,后续排查断连与行情错乱会非常困难。
五、常见误区与复盘
- 忽略 BodyLength 与 CheckSum 校验:部分网关不校验也能收,但生产环境一旦开启严格校验,消息会被静默丢弃。
- 用等号分割所有字段:Value 中可能含等号,必须只按第一个等号拆分。
- 把 35=V 当成行情数据:V 是订阅请求,真正的行情在 W 和 X 中。
- 不处理序列号缺口:发现 34 不连续时应发送 ResendRequest,否则行情会永久缺失。
- 忽略 279 更新动作:增量消息必须结合 279 与 269 才能正确维护盘口。
复盘结论:FIX 行情接入的稳定性,70% 取决于会话层序列号与心跳处理,30% 取决于应用层字段解析。先把会话层跑通,再打磨应用层解析,是最高效的接入路径。