4. FIX协议会话建立:Logon消息详解、CompID与Password验证、序列号(MsgSeqNum)管理、心跳间隔协商

好,咱们今天聊一个非常核心的话题——FIX会话怎么建立起来的。

很多人刚开始接触FIX协议,上来就发订单,结果被拒了。为什么?因为会话还没建立。FIX协议里,所有业务消息的交换,都得先过「登录」这一关。说白了,Logon消息就是你在交易所门口的「刷卡入场」动作。

4.1 Logon消息结构

Logon消息的MsgType是"A"(35=A)。它看起来像这样:

8=FIX.4.4|9=123|35=A|49=CLIENT1|56=BROKER1|34=1|52=20240101-00:00:00|98=0|108=30|141=Y|553=USER123|554=PASS456|10=234|

这里面有几个关键字段,我一个个说。

标签 字段名 说明
35 MsgType 固定为"A"
49 SenderCompID 发送方标识
56 TargetCompID 目标方标识
98 EncryptMethod 加密方式,0表示不加密
108 HeartBtInt 心跳间隔(秒)
141 ResetSeqNumFlag 是否重置序列号
553 Username 用户名
554 Password 密码

嗯,这里要注意:EncryptMethod 虽然叫加密方式,但国内很多交易所实际用的是 553/554 来做用户名密码验证。98字段通常填0,表示不额外加密。

4.2 CompID与Password验证

CompID是FIX会话的身份标识。SenderCompID(49)和TargetCompID(56)必须配对正确。我见过有人把这两个填反了,结果Logon直接被拒,查了半天日志才发现。

核心原则:你发的Logon里,49填你自己的ID,56填对方的ID。对方回复的Logon里,49和56是互换的。

Password验证这块,不同交易所实现不太一样。有的用553/554,有的用96/95(SecureData)。我个人习惯用553/554,因为更直观。

我曾经遇到过一个坑:某家交易所的密码字段要求Base64编码,但文档里没写。结果我传了明文密码,Logon一直返回"5"(拒绝)。后来问了他们的技术支持才搞定。所以,一定要仔细看交易所的对接文档,别想当然。

4.3 序列号(MsgSeqNum)管理

MsgSeqNum(34)是FIX协议里最容易被忽视、但最容易出问题的字段。

它的规则很简单:

  • 每个会话方向独立维护序列号
  • 从1开始,每次发送新消息递增1
  • 收到Logon响应后,序列号继续递增

但实际中,序列号管理有很多细节。

序列号不连续 = 会话断开

如果你发的消息序列号跳过了某个值,对方会认为消息丢失,直接断开会话。所以,序列号必须严格递增,不能有空洞。

那如果序列号真的丢了怎么办?有两种方式:

  1. 发送ResendRequest(35=2):请求对方重发丢失的消息
  2. 设置ResetSeqNumFlag=Y:在Logon时重置序列号为1

我个人建议:生产环境不要轻易重置序列号。重置意味着丢失了所有消息历史,审计时会有麻烦。只有在测试环境或者确认无未处理消息时,才用重置。

4.4 心跳间隔协商

HeartBtInt(108)是Logon消息里必须填的字段。它表示你希望的心跳间隔,单位是秒。

心跳机制是这样的:

  • 你发Logon时带上108=30,表示你希望30秒发一次心跳
  • 对方回复Logon时,也会带一个108值
  • 最终采用两者中较小的值

为什么会这样?你想想看,如果一方设30秒,另一方设60秒,那30秒的一方会先超时。所以协议规定取小值,保证双方都能接受。

经验值:国内交易所通常要求30秒。国外有些用10秒或15秒。我个人习惯设30秒,既不会太频繁占用带宽,也不会超时太久。

心跳消息本身很简单:

8=FIX.4.4|9=56|35=0|49=CLIENT1|56=BROKER1|34=2|52=20240101-00:00:05|10=123|

MsgType=0,没有其他业务字段。收到心跳不需要回复,但需要重置本地的超时计时器。

4.5 完整的Logon交互流程

咱们用一张图来总结整个会话建立过程:

FIX会话建立流程 客户端 服务端(交易所) ① Logon (35=A) 49=CLIENT1, 56=BROKER1 34=1, 108=30, 553=USER, 554=PASS 验证CompID & Password 检查序列号是否连续 ② Logon响应 (35=A) 49=BROKER1, 56=CLIENT1 34=1, 108=30 ③ 心跳 (35=0) 每30秒 ④ 心跳 (35=0) 每30秒 会话就绪 ✅ 会话就绪 ✅

整个流程其实就三步:

  1. 客户端发Logon,带上CompID、Password、序列号、心跳间隔
  2. 服务端验证通过后,回复Logon,确认心跳间隔
  3. 双方开始互发心跳,会话建立完成

如果Logon被拒绝,服务端会回复一个Logout消息(35=5),里面带一个58(Text)字段说明原因。常见的拒绝原因有:

  • CompID不匹配
  • 密码错误
  • 序列号不连续
  • 心跳间隔不在允许范围内

注意:Logon被拒后,不要立即重试。先检查日志,确认原因。我曾经见过一个系统因为密码错误,每秒重试一次,结果被交易所的防火墙直接封了IP。

4.6 实战建议

最后,给几个实战中的小建议:

  • 序列号持久化:每次发送消息后,把当前序列号存到本地文件或数据库。程序重启时,从持久化存储读取序列号,而不是从1开始。否则会触发序列号不连续错误。
  • 心跳超时处理:如果超过2倍心跳间隔没收到任何消息(包括心跳),应该主动断开会话并重连。不要傻等。
  • Logon重试策略:重试间隔至少5秒,最多重试3次。如果还不行,报警人工介入。

嗯,关于Logon消息的核心内容就这些。记住一句话:会话建立是FIX通信的基石,Logon消息里的每一个字段都值得你认真对待

我的习惯:每次对接新交易所,我都会先写一个Logon测试脚本,只发Logon和心跳,确认会话能稳定建立后,再开始发订单。这样能快速定位问题出在登录阶段还是业务阶段。


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