2、FIX协议基础概念:会话层与应用层分离、域(Tag)与消息结构、标准消息头与消息尾
好,咱们正式开始啃FIX协议的核心概念。这一章我打算把三个最基础、也最容易混淆的东西讲透:会话层与应用层为什么分开、Tag到底是个什么玩意儿、以及消息头尾为什么是强制标配。你把这些搞明白了,后面看任何FIX报文都不会发怵。
2.1 会话层 vs 应用层:为什么非要拆开?
我第一次接触FIX协议时,有个很大的困惑:为什么一个交易协议要分成两层?直接发订单、收成交不就行了?后来在对接一家做市商的时候,我踩了个坑才真正理解。
说白了,会话层管的是“怎么传”,应用层管的是“传什么”。你想想看,交易所和券商之间每天要传几百万条消息,如果每条消息都要重新建立TCP连接、重新登录认证,那效率得多低?会话层就是干这个的——它维护一条长连接,负责登录、心跳、序列号校验、重传这些脏活累活。
而应用层呢?它只关心业务:订单是买还是卖?价格是多少?数量是多少?成交了没有?这些业务数据完全不用操心底层怎么传。
核心要点:会话层保证“消息能可靠到达”,应用层保证“消息内容能被正确理解”。两者解耦后,你可以单独升级业务逻辑,而不影响底层通信机制。
我在项目中遇到过一家交易所,他们升级了订单类型,但会话层协议完全没动。这就是分层设计的好处——改一层,不影响另一层。
2.2 域(Tag)与消息结构:FIX的“积木”哲学
FIX协议里没有XML那种嵌套标签,也没有JSON那种花括号。它的结构极其简单:Tag=Value,用SOH字符(0x01)分隔。就这么一个模式,组合出了所有交易消息。
举个例子,一个最简单的订单消息长这样:
8=FIX.4.4|9=78|35=D|49=MY_FIRM|56=EXCHANGE|34=1|52=20240101-12:00:00|11=ORD001|21=1|55=600519.SH|54=1|38=1000|40=2|44=150.50|10=123|
(注:这里的|实际是SOH字符,为了显示方便我用竖线代替)
每个Tag都有固定的含义。比如:
- Tag 35:消息类型(D=新订单)
- Tag 55:证券代码
- Tag 54:买卖方向(1=买,2=卖)
- Tag 44:价格
FIX协议定义了上千个Tag,但实际常用的也就一两百个。我个人习惯是把常用Tag记在脑子里,不常用的查规范文档。你不需要背所有Tag,但必须理解Tag的编号体系:
| Tag范围 | 用途 | 举例 |
|---|---|---|
| 1-99 | 管理类(会话层) | 8=BeginString, 9=BodyLength, 35=MsgType |
| 100-999 | 应用层(订单、成交) | 11=ClOrdID, 55=Symbol, 54=Side |
| 1000-9999 | 扩展字段 | 各交易所自定义 |
嗯,这里要注意:Tag的顺序不是随意的。标准消息头(Tag 8, 9, 35等)必须出现在最前面,消息尾(Tag 10)必须在最后。中间的应用层字段可以按任意顺序排列——但大多数实现会按规范推荐的顺序来。
避坑指南:我曾经在解析报文时,发现某家券商的实现把Tag 35(消息类型)放在了Tag 49(发送方)后面。虽然FIX规范允许应用层字段乱序,但消息头字段必须按顺序出现。如果你遇到解析失败,先检查头字段的顺序对不对。
2.3 标准消息头与消息尾:每一条消息的“身份证”
每一条FIX消息,无论多简单,都必须包含三部分:消息头 + 消息体 + 消息尾。消息体是业务数据,头尾是元数据。
标准消息头包含的Tag:
- Tag 8 (BeginString):协议版本号,比如FIX.4.4
- Tag 9 (BodyLength):消息体长度(不包括头尾)
- Tag 35 (MsgType):消息类型
- Tag 49 (SenderCompID):发送方ID
- Tag 56 (TargetCompID):接收方ID
- Tag 34 (MsgSeqNum):消息序列号
- Tag 52 (SendingTime):发送时间
标准消息尾只有一个Tag:
- Tag 10 (CheckSum):校验和,用于验证消息完整性
为什么消息头这么重要?我举个例子。有一次我在调试时发现,某条订单消息的序列号(Tag 34)跳过了几个数字。按照FIX协议,接收方应该检测到序列号不连续,然后发起重传请求。但因为我当时没正确解析消息头,导致序列号校验逻辑没跑起来——结果丢了几笔订单都没发现。
警告:消息头中的Tag 9 (BodyLength) 和 Tag 10 (CheckSum) 是强制校验的。如果BodyLength与实际消息体长度不符,或者CheckSum计算错误,接收方必须拒绝整条消息。这是FIX协议最底层的防错机制,千万别跳过。
2.4 一张图看懂FIX消息结构
下面我用一张SVG图把整个结构串起来。你看了这张图,应该能直观理解“会话层 vs 应用层”和“头-体-尾”的关系。
你看,消息头里的Tag 8、9、35、34、52这些,本质上都是会话层在管。消息体里的Tag 11、55、54这些,才是应用层关心的业务数据。消息尾的Tag 10则是会话层用来做完整性校验的。
这种设计的好处很明显:会话层可以独立于业务逻辑运行。比如心跳消息(MsgType=0),它只有消息头和尾,没有消息体——因为不需要任何业务数据。如果会话层和应用层混在一起,心跳消息也得带一堆业务字段,那得多浪费带宽?
个人经验:我在实现FIX引擎时,会把会话层状态机(登录、心跳、序列号管理)和应用层处理器(订单路由、成交回报)拆成两个独立的模块。这样如果交易所改了业务逻辑,我只需要改应用层模块,会话层完全不用动。这个架构让我在几次紧急升级中省了大把时间。
好了,这一章的核心就这些。你记住三句话:会话层管连接,应用层管业务;Tag=Value是基本单元;头尾是强制标配。下一章我们会深入消息类型,看看FIX协议到底定义了哪些消息,以及它们怎么协同工作。