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响应后,序列号继续递增
但实际中,序列号管理有很多细节。
序列号不连续 = 会话断开
如果你发的消息序列号跳过了某个值,对方会认为消息丢失,直接断开会话。所以,序列号必须严格递增,不能有空洞。
那如果序列号真的丢了怎么办?有两种方式:
- 发送ResendRequest(35=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交互流程
咱们用一张图来总结整个会话建立过程:
整个流程其实就三步:
- 客户端发Logon,带上CompID、Password、序列号、心跳间隔
- 服务端验证通过后,回复Logon,确认心跳间隔
- 双方开始互发心跳,会话建立完成
如果Logon被拒绝,服务端会回复一个Logout消息(35=5),里面带一个58(Text)字段说明原因。常见的拒绝原因有:
- CompID不匹配
- 密码错误
- 序列号不连续
- 心跳间隔不在允许范围内
注意:Logon被拒后,不要立即重试。先检查日志,确认原因。我曾经见过一个系统因为密码错误,每秒重试一次,结果被交易所的防火墙直接封了IP。
4.6 实战建议
最后,给几个实战中的小建议:
- 序列号持久化:每次发送消息后,把当前序列号存到本地文件或数据库。程序重启时,从持久化存储读取序列号,而不是从1开始。否则会触发序列号不连续错误。
- 心跳超时处理:如果超过2倍心跳间隔没收到任何消息(包括心跳),应该主动断开会话并重连。不要傻等。
- Logon重试策略:重试间隔至少5秒,最多重试3次。如果还不行,报警人工介入。
嗯,关于Logon消息的核心内容就这些。记住一句话:会话建立是FIX通信的基石,Logon消息里的每一个字段都值得你认真对待。
我的习惯:每次对接新交易所,我都会先写一个Logon测试脚本,只发Logon和心跳,确认会话能稳定建立后,再开始发订单。这样能快速定位问题出在登录阶段还是业务阶段。
公众号:蓝海资料掘金营,微信deep3321