一篇搞懂FIX协议

在这里插入图片描述

FIX简介

FIX(Financial Information eXchange, 金融信息交换协议)于1992年由多个金融机构和经纪商共同发起。是一个不受单一实体控制的开放消息标准,是一个能够被调整组建适用于任何一个企业的商务需求的协议。

FIX会话协议与选择用于电子数据传递的物理介质(铜缆,光纤,卫星传输等)及传输协议规范(X.25,同步,TCP/IP等)无关。它提供了一个消息传递的可靠数据流。直到2006年10月,FIX会话协议与FIX应用协议一道,为用户提供了一个可靠的传输FIX应用消息的传输机制。

FIX协议包含2个层次:会话层和应用层。会话层与数据的通信相关;而应用层定义了商务相关数据内容。

FIX5.0引入TI(the transport independence )传输无关框架。TI将FIX会话层从应用层协议中分离出来。在TI框架下,应用层协议消息可以通过任意合适的传输技术进行传送,在这里,FIX会话层协议是FIX应用层消息的可选传输传输协议之一。两个协议层的版本标注将会有所不同,FIX X.Y为FIX应用层协议版本;FIXT X.Y 为FIX会话层协议版本编号,第一个版本为FIXT 1.1

FIX消息

消息格式

FIX消息的标准结构图如下:
在这里插入图片描述

FIX协议消息的格式存在着两种结构:tag=value结构和 FIXML 结构。其中FIXML可读性更强,但占用更多的带宽资源。

tag=value:
协议每个消息由必选、可选和条件必选(根据其他域的不同)数据域构成。FIX消息的一些要求如下:

1.FIX消息的一般格式为:一个标准头+消息体+一个标准的尾部;
2.消息头的前三个域为 BeginString(tag#8)+BodyLenth(tag#9)+MsgType(tag#35)
3.标准消息尾的最后一个域为CheckSum(tag#10)
4.一个特定的tag 数应当是唯一的。如果重复,将被认为是一个违反规范的错误;
5. 所有消息由8=FIX.x.y<SOH>标记开始,最后由10=nnn<SOH>标记结束。
6.某些数据类型如MultipleValueStringMultipleCharValue的数据域,可以包含多个由空格隔开,由一个<SOH>结束的部分。(例如18=2 9 C<SOH>代表三个独立的值’2’,‘9’,和’C’)
7. 所有的TAG标记都要有明确的值,没有值的信息单元在FⅨ消息中应当不被列出。消息中还有空值的TAG会被拒绝接收。

一条FIX消息的例子:

8=FIX.4.2^A9=69^A35=A^A34=1^A49=91000^A52=20160918-04:33:23.961^A56=CAO^A98=0^A108=20^A141=Y^A10=006^A

9=69表示消息体的长度为69个字符,从9=69^A开始到141=Y^A结束,如图所示,蓝色部分代表消息体长度。
![image_1at32v1hp9ul1a1j12adeqs1jqd9.png-6kB][3]
注意这里的^A表示一个字符,即<SOH>字符,十六进制为0x01
35号域表示消息类型,49号域表示SenderCompID,56号域表示TargetCompID…这些域对应的关系在FIX的字典文件中都有。

FIXML:
FIX支持传输FIXML及其它基于XML的数据。FIXML及其它XML数据被夹在FIX标准头与FIX标准尾部中间,并通过标准头的XmlDataLen域指定其内容长度,XmlData域包含其具体的数据。这样,FIX引擎可以通过多年使用的,可靠的,实时地异步传输机制传送FIXML及其它XML数据。当MsgType域值为’n’时,代表传输的数据为FIX未在MsgType中定义的XML数据。

FIXML用的比较少,了解就好,由于不同的协议版本FIXML也有不同,所以这里不做介绍。

SBE结构:
SBE(FIX Simple Binary Encoding)是FIX协议的二进制编码结构,适合在高性能交易系统中使用。它针对编码和解码的延迟进行了优化,同时保持带宽占用率相当小。为了兼容性,它可以表示所有FIX语义。

数据类型和域

数据类型和域可以在官网查询:http://www.fixtradingcommunity.org
如果觉得官网查询不方便,推荐这个网站:http://www.onixs.biz/fix-dictionary.html
一般采用FIX协议的经纪商也会提供数据类型和域的参考文档。

组件

应用消息中有很多共用的数据域集合——组件。 比如说, 大多数应用消息都会用到一系列定义债券品种的域:Symbol, SecurityID,SecurityIDSource等, 为避免重复,协议中定义了一些关键组件,在应用消息定义中直接用名称引用这些组件。实际的消息定义和使用中,则应该将组件扩展开成为相应的数据域集合。

在FIX协议中,组件是一个逻辑概念,它用来表示一组彼此之间有一定关系的消息域的组合。这些组件在FIX协议中都赋以相应的名称,用来更好的理解消息结构以及所应用的场景。在实际消息传送过程中,这些组件名称并不会作为信息在消息中出现,可以这么说,组件的出现是起到更好让人能够理解FIX消息结构的作用。

通常在FIX的字典XML文件中使用<component/>标签表示组件。

重复组(循环组)

重复组的特点是允许一个组内出现重复的数据域,如:

384=2<SOH>372=6<SOH>385=R<SOH>372=7<SOH>385=R<SOH>

384=2表示这个重复组有两条记录,它们以372号域做分隔(372号域是重复组记录里的第一个字段)。

  • 诸如Noxxx这种形式的字段一般表示重复组。
  • 如果使用重复组,重复组记录的第一个域是需要的,作为新重复组记录的一个分界。该域紧跟在NoXXX后面,然后,当NoXXX值大于0时,变成当条件必选。
  • NoXXX域(比如,NoTradingSessions,NoAllocs)定义了重复组实例的数量,比如上述例子的384=2,该域在一个重复组中出现一次,且必须在重复组内容之前。
  • 如果在一个重复组中的一个域是必选的,则NoXXX是必选的。如果所有重复组中的成员是可选的,则NoXXX域也应该是可选的。
  • 如果一个重复组域被列为必选,则它必须出现在该重复组的每一个实例中。
  • 重复组在消息中被设计成通过缩排,和à(![image_1at5l45uc19q2ss1mv01mg61ci71g.png-0.4kB][8])符号进行定义。一些重复组可以在其他重复中级联出现。可大于一层的级联,即重复组中可以嵌套其他重复组。
  • 如果使用嵌套重复组,那么该重复组的外级重复组也必须指定。

一个重复组的例子:

![image_1at5m1ggt1bdb1cv1hn31e87vk11t.png-90.9kB][9]

用户自定义域

FIX为给用户提供最大的灵活性,允许用户自定义域。这些域在认同的参与者之间实现、应用,并且应注意避免冲突。

  • Tag数在5000到9999保留用于用户自定义域。这些tag值用于企业联盟的信息交换。可以通过FIX网站进行注册(目前已经分配完毕)。
  • 10000以上保留用于单一企业内部使用。不用注册。

注意: 自定义域要保证字段名和已有的不冲突,比如自定义一个域 这个域tag是10000以上了 但是字段名和已有的相同,这个就冲突了,数据字典校验会不通过。

序列号

Fix 协议没有定义应答消息,使用序列号不连贯来检测消息丢失,用 checksum ,签名或消息体长度来检测消息错误。所有的FIX消息都有一个唯一的序列号(即消息头中的MsgSeqNum字段)进行标示。序列号在每一个FIX会话开始时被初始化为1(一般),并在整个会话期间递增,但以下情况可能出现倒流:
1)收到的消息是SeqReset-Reset消息。
2)收到消息的PossDupFlag=Y,且此类消息允许PossDupFlag=Y。
3)通过Logon消息进行序列号重置时,收到消息的MsgSeqNum一定为1,因此也可能出现倒流。

每个FIX会话将建立一组互不依赖的接受和发送序列。参与连接的任何一方都维护一套发送消息的序列号(outgoing),同时也维护另一套独立的接收消息序列号(incomming),用以监控消息缺口(乱序或跨越)。监控序列号可以使会话参与者识别和处理丢失的消息, 当一个FIX会话重新连接时能够快速进行应用程序同步。

连接建立后,当FIX协议实现者接收到序列号不等于预期接收序列号(NxtIn)时,需要修正处理:
1)如果接收序列号 < NxtIn,且不属于前文中倒流情况之一时,表明发生了严重的错误,必须立即结束会话,并开始进行人工干预。
2)如果接收序列号 < NxtIn,且属于前文中倒流情况之一时,不属于错误,正常处理。
3)如果接收序列号 > NxtIn,表明有消息被遗漏,需要通过重发请求填补缺口。如果使用TCP作为传输层协议,那么这种情况表示发生了严重异常,应立即终止会话。

数据完整性

消息数据内容的完整性可以参用两种方式来验证:消息长度和效验码检查。

  • 程序通过计算BodyLength域(并包含)到CheckSum标记(“10=”)之前的分界符(并包含)的字符数与在BodyLength中标示的消息长度进行比较来完成完整性效验。

  • ChekSum完整性检查,通过计算从域“8=” 中“8”开始,包括在CheckSum标记域之前的分界符<SOH>每个字符的2进制和,取最后有效的八位同CheckSum进行比较得到。

一个FIX消息校验和通过计算到CheckSum域(但不包括)的消息的每个字节和得到。然后,校验和被转换为模256的数字用于传送和比较。校验和在所有加密操作之后被计算。

数据加密

一个消息的任何一个域可以被加密并放在SecureData域中。然而,一些显示的标志域必须采用明文进行传输。为确保完整性,明文域可以在SecureData域中重复。

当使用加密时,建议但不是必须,所有的消息体都进行加密。如果一个消息中的重复组数据中的部分数据要加密,这个重复组必须全部进行加密。

预先协商好的加密算法在Logon消息中进行声明。

消息重复发送

在响应一个重发请求而重复发送消息时,或者不确定对方是否收到已发消息而重复发送该消息时,消息发送方须在被重发消息内加上可能重复标志(PossDupFlag=Y)。如何处理该消息则由消息接收方处理。注意:当生成有此类可能重复发送的消息时,由于某些信息可能会改变,如原始时间、发送时间、正文长度、可能重复标志等,所以应重新计算校验和。

消息重新发送

消息重新发送,是基于应用层的可能重发消息。如发送的订单在相当长的时间内没有得到确认,或者怀疑其根本未曾被发送过,消息发送方可通过设置可能重新发送标志来重新发送(PossResend=Y)。消息接收方收到该类消息后,应通过查询消息内的域(如订单编号等)来确定此前是否收到过该消息。注意:此类消息应确定包含相同的正文数据,同样,由于某些信息可能会改变,所以应重新计算校验和。

PossResendPossDupFlag 区别就是前者使用了新序列号发送老的消息,可以通过检查消息中的域来确定是否已经收到过该消息,比如 order 的 ID 等;后者是用老的序列号重发消息,可以直接检查序列号来确定是否已经收到过该消息,若已收到过了就丢弃该消息。

混乱消息

当至少出现一下情形之一时,一条消息被称为“混乱消息”:
1.BeginString(tag#8)不是一个消息中的第一个tag或不是8=FIXT.n.m.的格式。
2.BogyLength(tag#9)不是一个消息中的第二个tag或没有包含正确的字节数。
3.MsgType(tag#35)不是一个消息中的第三个tag。
4.Checksum(tag#10)不适最后一个tag或没有包含正确的值。
5.MsgSeqNum(tag#34)丢失,此时,一个Logout消息将被发送以终止FIX连接。因为这种情况意味着一个严重的应用程序错误。

消息确认

FIX协议的消息传输模式是基于消息被完整传送的;并且通过监测消息序号缺口以识别正常传送过程中的错误。协议不支持对单个消息收发的确认,但大量的应用消息须在应用层作出明确的收发确认,如订单的确认。


FIX会话机制

会话定义

一个FIX会话定义为一个在连接双方间的的带有连续序列号的有序消息双向传输流。

单个FIX会话能够跨越多个连续(不是并行的)的物理连接。在一个维持的,单独的FIX会话中,参与方能够多次连接和断开连接。连接的参与方必须根据单个系统及时间区域需求,公共协商会话的开始和结束。无论什么原因,重新设置接收和发送序列号为1,意味着一个新的FIX会话的开始。

建议一个新的FIX会话在每24小时期间建立一次。可以维持24小时的连接和通过设置在Logon消息中的ResetSeqNumFlag建立一套新的序列号。

FIX会话协议基于一个优化模型。普通的数据传送(无单个消息确认)被假设为通过消息序列缺口进行错误识别。

相关术语:

  • Valid FIX Message 有效FIX消息, 是按照协议正确生成,包含有效消息体长度和效验域的消息。
  • Initiator 发起者, 建立通信连路,通过发送初始Logon消息发起会话的参与方。
  • Acceptor 接收方, FIX会话的接收方。负责执行第一层次的认证和通过传输Logon消息的确认正式声明连接请求被接受。
  • FIX Connection FIX连接, 由3部分组成:logon登录,message exchange消息传输,和logout注销。
  • FIX Session FIX 会话, 由一个或多个FIX Connection FIX连接组成。意思是一个FIX会话可以有多次登录。

登录

建立一个FIX连接,分别包含3个操作:创建通信层链路,接收者认证/接受发起者和消息同步(初始化)。连接流程如下:

  • 会话发起者同会话接收者建立通信链路。

  • 发起者发送一个Logon消息。接收者检查Logon消息,认证发起者身份。Logon消息包含支持之前双方协商好的认证方法所必须的数据。如果发起者被成功认证,接收者用一个Logon消息进行响应。如果认证失败,会话接收者将关闭链接,关闭之前可以选择发送一个Logout消息以提示认证失败的原因。这个Logout消息不是必须发送的,因为其占用了一个消息序号,而且在某些情况下可能会引起其他问题。登录成功后,会话发起方可在登录消息之后立即开始发送消息,但此时会话接收方可能并没有作好接收消息的准备;因此会话发起方应在收到接收方的登录消息确认之后,才认为会话连接建立完成。

  • 建议:在登录后或者刚发送完测试请求消息(TestRequest)时延迟等待一段时间,双方再发送新的消息,使得连接双方能有效控制重发请求;否则可能会导致一方会针对对方的每一条新消息发出重发请求。

  • 在发起者认证通过之后,接收者立即响应一个Logon确认消息。依据会话使用的加密方法,这个Logon消息可以,也可以不报还同样的会话密钥。发起者方将把接收方回复的Logon确认消息视为一个FIX会话建立的标志。如果会话接收方选择改变会话加密密钥,会话的发起方必须发送一个Logon消息到对方以确认密钥改变请求。这样,能让会话接收者知道发起者何时开始使用新的会话密钥。双方有责任诊断和避免在此阶段出现无限循环。

  • 认证完成之后,发起方和接收方必须在发送任何新消息之前通过询问MsgSeqNum域来同步其消息。将Logon消息中的MsgSeqNum同内部监控的下一个希望的序列号进行比较可以指出任何的消息间隙。此外,发起方能通过比较确认Logon消息的MsgSeqNum及下一个期望的消息序号来侦测消息的间隙。

  • 建议每24小时重置序列号。

  • 当使用ResetSeqNumFlag来维持24小时连接和建立一套新的序列号时,应该按照下面的方式进行处理。双方应当协商一个复位时间以及此过程的发起方。注意,ResetSeqNum过程的发起方可以与Logon过程的发起方不是同一个。一方通过发送一个TestRequest初始化此过程,并等待一个Heartbeat的响应以确认没有序列号间隙。一旦收到Hearbeat,发起者应当发送一个带有ResetSeqNumFlag值为‘Y’MsgSeqNum1Logon消息。接收方应当发送一个带有ResetSeqNumFlag值为‘Y’MsgSeqNum1Logon消息作为响应。此时,任何一方发送的新的消息可以从MsgSeqNum编号为2开始计数。应当注意,一旦发起方发送设置了ResetSeqNumFlagLogon消息,接收者必须遵守这个请求,并且作为最后一个序列号发送的消息的“yesterday”值不再可用。如果此过程的初始化未被正确执行,链接应当被关闭,可以手动关闭。

  • 在以上初始化完成之后,可以开始进行信息交换。有效消息分为“管理消息(会话层)”和“应用消息(应用层)”。

NextExpectedMsgSeqNum (789)域从FIX4.4开始加入到Logon消息中,用以支持一个FIX会话的重同步。这个新方法是可选的。其使用必须得到参与方的共同同意。

注销

会话的正常结束是通过连接双方互相发送注销消息(Logout)完成的。若结束时没有收到回送的注销消息(Logout),则把对方视作已注销。除此之外的其它方式的会话结束视为非正常,并应按错误来处理。

在发送注销消息(Logout)之前,应发送测试请求消息(TestRequest)以要求对方的心跳信息,这有助于保证不出现消息序号间隙。

在结束会话之前,注销消息(Logout)的发起方应该等待对方回送的注销消息(Logout),这样给注销消息的接收方一个填补间隙的机会。待重发请求的信息全部收到后,注销消息的接收方才可发送应答的注销消息(Logout)。如果注销消息的接收方在一定时间内没有答复,那么会话就可以立即中断。

注意:注销不影响任何订单的状况。所有有效的订单都可在注销(Logout)之后执行。

消息恢复

FIX 消息要按序列号从小到大顺序处理,若收发过程中出现丢包则有两种策略:重传序列号出错的包及以后所有收到得包;另一种是只重传出错的包。比如:接收方丢失了5个消息块中的第二个,程序能忽略第3到第5个消息,产生一个对消息2到消息5的重传请求,或者从消息2到无穷大消息编号的重传请求。另外的方式是暂时存储消息3到消息5,仅要求重传消息2。对于这两种方式,消息3到消息5都不应该先于消息2进行处理。

当接收进来的消息序号与预期的消息序号不相符合时,需进行修正处理。但需要注意的是,如果接收进来的是序号重设消息(SeqReset-Reset),则不需要进行修正处理。因为此类消息的消息序号对随后的消息处理没有任何影响。如果接收的消息的消息序号比预期的消息序号小,而且没有设置可能重复标志(PossDupFlag),那么表明发生了严重的错误。因此建议强制结束会话,并开始进行人工干预。如果接收进来的消息序号比预期的大,那么表明有消息被遗漏,应通过发送重发请求申请填补缺口。

注意:以下段落中的请求人指的是提出重发请求的一方,重发人指的是回应重发请求的一方。当收到重发请求时,重发人可任选以下之一作出回应:

  • 作为正常回应,重发人按顺序发送被请求的消息,这些消息的消息序号仍为原消息序号,并且将可能重复的标志(PossDupFlag)置位为“Y”。

  • 作为正常回应,重发人发送序号重设-缺口填补(SeqReset-GapFill)消息,可能重复标志(PossDupFlag)置位为“Y”,以表示删除过时或多余的消息。

  • 作为非正常回应,重发人发送序号重设-重设(SeqReset-Reset)消息,可能重复的标志(PossDupFlag)置位为“Y”,以强制消息序号同步。

在缺口填补过程中,某些会话管理消息不应被重新发送;取而代之的是一种特殊的序号重设-缺口填补消息(SeqReset-GapFill)。不应被重新发送的会话管理消息包括:登录、注销、重发请求、心跳、测试请求、序号重设-重设消息(SeqReset-Reset )和序号重设-缺口填补消息(SeqReset-GapFill)。由此,会话拒绝消息便成为了唯一可能被重新发送的会话消息。

会话过程中应监视接收到的消息,以便发现由于疏漏而被对方重新发送了的会话消息(设置了可能重复标志(PossDupFlag)的)。当收到这些消息以后,只须确认它们占有一个消息序号空间即可, 可以忽略消息中包含的对业务或应用的处理信息。

如果碰到多个连续的无需重发的会话消息, 建议只发送一个序号重设- 缺口填补消息(SeqReset-GapFill)。该序号重设-缺口填补消息的消息序号是下一个预期的消息序号。序号重设-缺口填补消息(SeqReset-GapFill)的新消息序号(NewSeqNo)为本连续会话消息段中最大消息序号+1。例如,在重新发送操作期间,有7 条连续的会话消息等待发送,他们以消息序号9 开始和以消息序号15 结束,此时只发送一个序号重设-缺口填补消息(SeqReset-GapFill)来代替那7 条消息,那么该序号重设-缺口填补消息(SeqReset-GapFill)的消息序号是9,这是因为要承接上条消息而保持消息序号的连续性;其中新消息序号(NewSeqNo)是16,这样使得对方知道下一消息发送时的消息序号。

建议:在缺口被填补完成之后,交换引擎应将无序的消息暂时保存为有序的排列并按顺序对它们进行处理,以防止出现对n->m,n->m+1,n->m+2,.的重发请求,否则会导致大量的可能重复(PossDupFlag=‘Y’)标记。

序列号检查是FIX会话管理最重要的部分。然而,一些FIX消息的序列号处理存在一些不同,下表列出了接收序列号比期望接收序列号大时的处理方法。

注意:在任何情况下,除了序号重设-重设消息外,如果进来的消息序号比预期的消息序号小,而且可能重复标志(PossDupFlag)没有被设置,那么应立即终止会话过程。并应在结束会话之前,向对方发送带有解释正文的注销(Logout)消息。

消息类型针对消息序号错误所采取的措施
登录永远是连接双方发送的第一条消息,用于认证和确认连接。 如果发现登录消息中有缺口,则应在回送登录确认消息之后 立即发送重发请求
注销如果发现有缺口,应发送重发请求消息以重新接收所有丢失 的消息,然后再发送注销消息作为对注销请求的确认。注意 严禁在有缺口情况下结束会话。并由注销的最初发起人负责 结束会话,因此注销发起人有责任回应所有的重发请求
重发请求首先处理完对方的重发请求,随后发送自己的重发请求以填补 消息序号错误而发现的消息缺口
序号重设-重设可以忽略消息序号错误。因为在序号重设-重设( SeqReset-Reset ) 消息中的新消息序号(NewSeqNo)强制为下一发送消息的消息序号
序号重设-缺口填补应立即向对方发送重发请求。但是,必需确保没有无意间跳过 任何消息,这意味着缺口填补消息应按次序被接收到,如果 次序不对,那么表示出现了非正常的情况
所有其它信息执行正常的缺口填补。

标准消息头

任何管理和应用消息都紧跟在一个标准头部之后。头部标示了消息的类型、长度、目标、序列号,来源及创建时间。

消息路由-点对点:
假设A为卖方,B为买方。
下表展示了两个企业间的一个单一的FIX会话。

SenderCompIDOnBehalfOfCompIDTartgetCompIDDelivrToCompID
A 到B
B 到 A

消息路由-第三方消息路由:
FIX会话协议具备支持一个FIX会话包含多个参与者的能力。包括1对多,多对1,或者1对1的形式。此外,一些第三方可以与其它第三方连接,在消息发起者和最终的接收者间形成一个多跳的链。SenderCompIDTargetCompIDDeliverToCompID,和OnBehalfOfCompID域用于路由消息。

当一个第三方在另一个企业中间发送一个消息时(使用OnBehalfOfCompID),可以选择在NoHops重复组中加入它的细节信息。这个重复组构建了消息在第三方重新发送的的一个历史列表。NoHops重复组不用于协助路由,而是为接收消息方对参与的第三方进行审计时提供痕迹。当一个第三方转发一个消息给下一跳(可能是最终接收者,或另一个第三方)时,此第三方可以将其跳信息加到NoHops重复组中(如,将其SenderCompID作为HopCompID,其SendingTime作为HopSendingTime,将接收消息的MsgSeqNum或其他引用数据作为HopRefID )。

注意: 如果OnBeHalfOfCompIDDeliverToCompID消息源识别/路由方法在一个FIX会话中使用,那么该方法必须在通过此会话传送的所有消息中使用。

下表提供了在单一FIX会话中表名多个企业参与时SenderCompID,TargetCompID,DeliverToCompID和OnBehalfOfCompID的使用方法。假设A=卖方,B和C表示买方,Q=第三方。

![image_1atabcbl2bok1scr11frtihq0o2m.png-36.4kB][10]

注意,由于在一个给定的FIX会话中,一些域(如在一个新Order指令中的ClOrdID)必须是唯一的。因此,当使用OnBehalfOfCompI(或DeliverToCompID)进行寻址时,推荐的做法是在OnBehalfOfCompID(或DeliverToCompID)之后加上源地址。这样,如果A发送消息到Q的ClOrdID为“123”,那么Q将“A-123”作为ClOrdID的值发送到C,以确保唯一性。

标准消息头部如下:
![image_1atacui4sonj6k3kc31nsl1pjh33.png-212.3kB][11]

标准消息尾

每个消息,管理或应用消息,以一个标准尾部结束。该尾部用于分割消息并包含描述Checksum值的3个数字字符。

![image_1atae7ibt4gq4dr2u3p5b1lm3g.png-22.7kB][12]

会话查重

FIX协议适用于不同的传输层协议(如UDP),因此不能根据TCP SOCKET等特定的传输层信息来区分哪些报文隶属于同一个FIX会话,而且FIX会话没有“会话号”的标签,且不是全部报文都会有username一类的标签,因此区分FIX会话的唯一标识只能是SenderCompIDTargetCompID的组合。

FIX协议中,单个FIX引擎不能同时维护相同SenderCompID+TargetCompID的两个会话,。标识推荐的做法是:在已存在一个合法会话时,若一方试图以同样的SenderCompID+TargetCompID发起新的会话,对方将不发送任何Logout消息就直接终止新发起的会话,原先已存在的会话不应受到影响。

FIX协议并未明确不同的FIX引擎是否允许同时保有相同标识的会话。


FIX管理消息(会话层)

Heartbeat 心跳消息

心跳消息监控通信链路的状态,用于识别一连串消息中最后没有收到的消息。

心跳间隔在 initiator 发送 logon 消息时候设置在心跳域上, acceptor 和 initiator 的心跳间隔时间一致。

当如果一个FIX连接的任何一方在超过HeartBtInt规定的时间间隔后没有收到任何数据,将发送一个Hearbeat消息。如果一个FIX连接的任何一方在超过HeartBtInt规定的时间间隔加上一些传输时间后没有收到任何数据,将发送一个Test Request测试请求消息。如果在超过HeartBtInt规定的时间间隔加上一些传输时间后仍然没有收到Heartbeat消息,那么应视为连接断开并应采取纠错处理。

如果HearBtInt设置为0,则不会产生常规的Heartbeat消息。注意,在非HeartBtInt发送时间, 一个测试请求任然能够被发送,用于强制请求一个Heartbeat消息。

Heartbeat消息作为测试请求消息的响应,必须包含请求测试消息中的TestReqID值,用于验证Heartbeat消息是测试请求消息的响应而不是常规超时的响应。

心跳消息会占用序列号。

Heatbeat消息格式如下:

Tag(标记)Field Name(域名)Req’d(必选)备注
StandardHeaderYMsgType=0
112TestReqIDN当Heartbeat消息是Test Request消息的响应时必选
StandardTrailerY

Logon 登陆消息

Logon消息必须是应用程序用于请求初始化一个FIX会话的第一个消息。

HeartBtInt(108)域用于申明产生心跳消息的时间间隔,连接双方使用形同的HeartBtInt值。其值应被双方企业一致同意,由Logon消息发起者初始化,并被Logon接收者回应。

当接收到Logon消息,会话接收者将认证参与者的连接请求,并发出一个Logon消息确认连接请求被接受。这个确认Logon消息也能用于发起者验证连接已经与对端正确建立。

在接收到Logon消息后会话接收者必须立即准备好开始处理消息。会话发起者可以选择在收到Logon确认消息前传输FIX消息,但推荐在收到返回的Logon消息后,完成加密密钥协商后进行正常的消息传输。

确认Logon消息可以用于加密密钥协商。如果一个会话密钥被认为是弱密钥,一个推荐的新的更加强壮的会话密钥将在Logon消息中返回。这仅在加密协议允许密钥协商时有效。

Logon消息能用于确定支持的消息最大长度MaxMessageSize(能用于控制将大消息进行分节的规则)。也能用于确定双方接收和发送所支持的消息的类型MsgType

Logon 阶段,客户端选择了一个加密密钥,但服务器选择了不同的密钥放在返回的 logon 消息中,这时候客户端还得发一个 logon 消息应答服务器端,两个作用: 1). 让服务器知道密钥变更获得了客户端的响应; 2). 下面的消息开始要加密了

logon 阶段完成后必须马上检查序列号,同步收发的消息,比如一端发送了消息但另一端没收到,这时候需要重传。可以通过对比 logon 消息中的序列号和通信一方的期望收到的消息序列号来检测消息漏收发。

logon 消息中有两个字段 RAW Data LengthRAW data 用来存放认证需要的数据;

下表是Logon消息的格式(注意:不同的FIX版本需要的稍微不同,比如FIX4.2不需要DefaultApplVerID,哪个字段在哪个版本中被加入,可以在官网查询):

![image_1atav142o12011qp784qnmu102r9.png-112.7kB][2]

Test Request 测试请求消息

测试请求消息强制对方发送一个Heartbeat消息。测试请求消息检查序列号或验证通信线路状态。对端应用程序响应一个包含TestReqID域的Heartbeat消息。

TestReqID用于检查对端应用是依据测试请求消息产生的Heartbeat消息,而不是通常的超时。对端应用程序将TestReqID包含在响应Heartbeat消息中。任何字符串可以被用于TestReqID(一个建议是使用时间戳字符串)。

测试请求消息格式如下:

Tag(标记)Field Name(域名)Req’d(必选)备注
StandardHeaderYMsgType=1
112TestReqIDY不能加密
StandardTrailerY

Resend Request 重传请求消息

重传请求消息由接收应用程序发送用于开始消息的重传。这个功能在序列号缺口被侦测到时,接受应用程序丢失消息时,或者作为一个初始化处理功能时非常实用。

重传请求消息能用于请求一个单一消息,一定范围内的消息,或者一个特定消息的所有后续消息。

发送应用程序可能希望考虑重传消息的消息类型。如:如果在重传序列中的一个新指令消息在其最初发送后经过一段相当长的时间,那么发送方可能不希望重传该消息,因为市场条件可能已经改变。(Seqence Reset-GapFill消息用于不希望发送方发送而跳过这类消息。)

接收程序必须按照顺序处理消息。如:如果收到消息8和9,消息7丢失,程序应忽略消息8和9,并要求重传消息7到9,或者最好重传消息7到0(0表示序列号无穷大)。后者是作为当序列号出现混乱,双方同时尝试恢复一个缺口时,从当前的某些竞争条件下快速恢复的推荐方法。

  • 请求重发一条消息, BeginSeqNo=EndSeqNo
  • 请求重发某个范围内的消息,BeginSeqNo=请求范围内第一个消息,EndSeqNo=请求范围内最后一个消息。
  • 请求重发特定消息的所有后续消息:BeginSeqNo=请求范围内第一个消息,EndSeqNo=0(代表无穷大)。

重传请求消息格式如下:

Tag(标记)Field Name(域名)Req’d(必选)备注
StandardHeaderYMsgType=2
7BeginSeqNoY
16EndSeqNoY
StandardTrailerY

Reject(session-level)驳回消息

当一个接收消息由于违背会话层规则,不能被正确的处理时,应发送驳回消息。一个例子是:当一个接收消息通过解密,效验和检查,及数据体长度检查后没有有效的基础数据(如,MsgType=&),将产生一个驳回消息。通常,这些消息应传递给交易应用程序,如果需要,将产生业务级的驳回。

驳回消息应记录到日志中,且接收序列号应增加。

注意:接收应用程序应忽略任何干扰的,不能被解析的及未通过数据完整性检查的消息(混乱消息)。这时候处理下一个FIX消息时会检测到一个序列号缺口并产生一个Resend Request消息,从而拿回这条混乱消息。FIX引擎应有避免在这种情况下无限循环的逻辑。

生成和接收到一个驳回消息表明发送和接受应用程序双方存在一个严重的逻辑错误。

如果发送程序选择重传驳回消息,该消息应赋予一个新的序列号值,且PossResend设置为‘Y’。

无论何时,强烈推荐将失败原因描述在Text 域中(如,INVALID DATA(35))。

如果接收到的一个应用级消息满足所有会话级规则,该消息应在业务层被处理。如果在处理过程中检测到规则冲突,将产生发送一个业务级驳回。许多业务级消息都有自己特定的驳回消息。如果没有,则产生一个Business Message Reject消息。

注意,在收到一个业务消息,满足会话级规则,但不能被传送给业务层处理系统时,一个带有BusinessRjectReason=“Application not available at this time”Business Message Reject消息将被发送。

驳回消息格式:

Tag(标记)Field Name(域名)Req’d(必选)备注
StandardHeaderYMsgType=3
45RefSeqNumY被驳回消息的MsgSeqNum
371RefTagIDN被参照的FIX域tag值
372RefMsgTypeN被参照的FIX消息MsgType值
373SessionRejectReasonN会话级驳回消息错误代码
58TextN解释驳回原因的文本信息
354EncodedTextLenN如果使用EncodeText域,必选,且EncodeText必须紧跟在该域之后
355EncodedTextN使用MessageEncoding域制定的编码规则对Text域内容的编码数据(非ASCII码)
StandartTrailerN

会话级驳回消息场景:

SessionRejectReason
0=Invalid tag number 无效的tag编号
1=Required tag missing tag丢失
2=Tag not defined for this message type 这类消息的Tag没有被定义
3=Undefined Tag 未知Tag
4=Tag specified without a value 缺少Tag值
5=Value is incorrect (out of range) for this tag tag值错误(超界)
6=Incorrect data format for value 错误值数据
7=Decryption problem 解密错误
8=Signature problem 签名错误
9=CompID problem 企业ID错
10=SendingTime accuracy problem 发送时间不正确
11=Invalid MsgType 无效的MsgType
12=XML Validation error XML语法验证错误
13=Tag appears more than once Tag重复出现
14=Tag specificed out of required order 指定的Tag顺序错误
15=Repeating group fields out of order 重复组域顺序错误
16=Incorrect NumInGroup count for repeating group 重复组NumInGroup错误
17=Non “data” value includes field delimiter(SOH character) 包含了SOH分界符的错误数据
99=Other 其它错误
注意:其他的会话级规则冲突可能存在,SessionRejectReason值为99(Other),并在Text域中进行详细描述。

序列号重设消息

序列号重设消息由发送方发出,用于告知接收方下一个消息的序列号。

序列号重设消息有两种模式:SeqReset-Gap Fill模式和SeqReset-Reset模式。
SeqReset-Gap Fill 模式:
在下列情况下,SeqReset-Gap Fill模式用于响应当出现一个或多个消息必须被跳过时的重传请求:
1.在常规的重传处理过程中,发送应用程序可以选择不发送消息(如,一个过期的指令)。
2.在常规的重传处理过程中,大量的管理消息将跳过而不重传(如:Heartbeat, TestRequest 消息)。

GapFillFlag(123)域为‘Y’时,为Gap Fill模式。

如果GapFillFlag(123)域设置为‘Y’,MsgSeqNum应同标准消息序列号规则保持一致(如,SeqReset- GapFill模式消息的MsgSeqNum应为SeqReset-GapFill消息的最开始的MsgSeqNum,因为其值为远端程序希望接收的消息序列号)。

SeqReset-Reset 模式:
重设模式包括了指定一个任意的、数值更大的、接收者期望的Reset-Reset消息序列号,并用于在出现不可恢复的应用程序错误时重新建立一个FIX会话。

重设模式由GapFillFlag为‘N’时,或被忽略时被指定。

在序列号的Reset-Reset模式中,在消息头中的MsgSeqNum将被忽略(如,当接受到带有错误的MsgSeqNum序列号的Sequence Reset-Reset模式消息时,不产生重传请求)。序列号重设的Reset消息不应被当作一个重传请求的常规响应(使用SeqReset-Gap Fill模式)。
SeqReset-Reset模式仅在当使用SeqReset-Gap Fill模式无法恢复时进行灾难恢复。注意,使用SeqReset-Reset模式时有可能造成消息丢失。

如果一个序列号重设消息尝试减小期望接收消息的序列号时,应被当作以个严重错误而被拒绝。

序列号重设消息格式:

Tag(标记)Field Name(域名)Req’d(必选)备注
StandardHeaderYMsgType=4
123GapFillFlagN
36NewSeqNoY
StandartTrailerY

Logout注销消息

Logout消息发起或确认一个FIX会话的终止。没有Logout消息交换的连接断开应被视为一个异常情况。

在实际的关闭会话前,Logout发起者应等待对端的Logout确认消息的响应。这样可以给远端在必要时执行一些Gap Fill操作的机会。如果远端在规定的时间间隔后没有响应,会话可以终止。

在发送Logout消息后,注销发起者不应发送任何消息,除非注销的接收者通过ResendRequest消息请求发送消息。

Logout 之前需要发送 testrequest 消息强制心跳,检测消息序列号是否连续, logout 消息发送出去之后,需要等待一段时间接收 logout 回应消息,这段时间让双方来处理序列号不一致的问题,一旦序列号同步之后 logout 接收者马上发送回应的 Logout 消息, Logout 发起方收到回应后负责来关闭会话。

注销消息格式如下:

Tag(标记)Field Name(域名)Req’d(必选)备注
StandardHeaderYMsgType=5
58TextN
354EncodedTextLenN如果使用EncodeText域,必选,且EncodeText必须紧跟在该域之后
355EncodedTextN使用MessageEncoding域制定的编码规则对Text域内容的编码数据(非ASCII码)
StandartTrailerY

校验和计算

一个FIX消息校验和通过计算到ChechSum域(但不包括)的消息的每个字节和得到。然后,校验和被转换为模256的数字用于传送和比较。校验和在所有加密操作之后被计算。
为了便于传输,校验和必须以可打印字符形式进行传输,因此,校验和被转换位3个ASCII数字。

比如:如果消息的校验和为274,则模256后为18(256+18 = 274)。这个值将采用|10=018|进行传输,其中“10=”是校验和域的标签。

产生校验和的代码示列如下:

char *GenerateCheckSum( char *buf, long bufLen )
{
    static char tmpBuf[ 4 ];
    long idx;
    unsigned int cks;
    for( idx = 0L, cks = 0; idx < bufLen; cks = (unsigned int)buf[ idx ] );
    sprintf( tmpBuf, “%03d”, (unsigned int)( cks % 256 ) );
    return( tmpBuf );
}

FIX会话层注意事项

UNICODE注意事项

一般情况下,SOH是分隔符,但是UNICODE编码传输的时候,SOH是有可能会出现在数据中的,这个时候借用EncodedLen来指明真实数据长度,就像二进制那样。

何时发送Logout与仅断开连接

一般情况下,一个Logout消息应在关闭一个连接前发送。如果这个Logout消息是源于一个错误条件,Logout的Text域应提供错误原因的描述,为远端FIX系统提供问题诊断的操作支持。这里有2个例外,推荐不发送Logout消息:

1、在登陆阶段,如果会话发起者的SenderCompID,TargetCompID或IP其中一个无效时,推荐立即终止会话,不发送Logout消息。这个登陆尝试有可能是一个未经授权的破坏系统的未认证尝试,因此,企业不希望泄露其FIX系统的任何信息,如,哪个SenderCompID,TargetCompID是有效的,或所支持的FIX版本。

2、在登陆阶段,当一个有效的FIX会话已经被一个企业使用时,该企业的第2次连接尝试的Logon消息被接受时,推荐会话接收者立即中断该第2次连接尝试,不发送Logout消息。发送一个Logout消息将冒着妨碍和影响当前FIX连接的风险。例如:在一些FIX实现系统中,发送一个Logout消息可能会消耗一个序列号,这样将会导致在一个已经建立的FIX会话中的序列号混乱。

在其他情况下,如果发送一个Logout消息不产生风险和安全冲突,Logout消息应随同描述信息一起发送。

何时发送会话驳回与忽略消息

接收程序应忽略任何文本混乱,不能被解析以及数据完整性检查失败的消息。处理下一个FIX消息时将检测到一个序列号缺口并产生一个重传请求消息Resend Request。这种情况下,FIX引擎应包含识别重传无限循环的逻辑。
FIX协议采取乐观的观点。它假设一个混乱的消息是由于传输中出现的错误,而不是FIX系统的问题。因此,如果发送一个重传请求消息(Resend Request),该混乱消息将被正确得重传。

其他违背会话层规则的消息,推荐发送一个会话级驳回消息。

  • 8
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰雪积木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值