1. 概述
FAST (FIX Adapted for Streaming: FIX适配流)由FIX协议组织开发,为市场数据带来更大的标准化的好处,并为电子金融信息交换提供优化的性能。它基于数据压缩算法构建,显著降低了发送方和接收方之间的带宽需求和延迟。在消息速率峰值期间,FAST在提高性能方面工作得特别好。虽然FAST是从行情数据需求发展而来,但它可以与所有FIX消息一起使用,以提供用于传输的FIX数据格式的灵活性。
FAST使用了几种技术来减少带宽。本FAST教程在本页简要介绍了这些技术,并在后面的章节中详细介绍。
1.1 FAST 模板
FAST模板定义消息的字段布局,因此消息本身不会描述单个字段名或标记(tag)。相反,字段是根据模板所描述的字段在消息中的位置来推断的。该模板由发送方和接收方(即编码器和解码器)共享,通常保存在XML文件中(还有一种简洁的格式)。
1.2. FAST Presence Map (PMap)
Presence Map(或PMap)是一个变长的位域字段,用于指示消息中是否存在特定的字段。
这允许编码器在某些情况下从消息中删除字段,例如:
- 字段值与前一条消息相同(通常在交易日期、结算日期等字段中)或
- 比最后一个消息大一个(序列号的常用情况)。
模板定义当消息中没有字段时要使用的规则。
1.3. 变长字段
FAST中的字段没有固定的大小,也不使用字段分隔符。相反,这里有一个停止位(消息的每个字节上的最高位充当停止位)的概念,表示字段的结束。
以上所有的概念一起使用可以让发送方压缩消息(有时多达90%),并能使接收方从编码的字节恢复原始消息内容。
下一节将介绍一个小的消息示例,以演示实际中的编码和解码。
2. Hello World Example
为了介绍编码和解码过程,我们描述了一个只有一个字段的普通消息如何被FAST编码和解码。
2.1 输入消息
下面是我们的消息:
58=HelloWorld<SOH>
SOH (ASCII 1)是FIX分隔符字节。
2.2 模板
这条消息需要一个非常简单的模板(用XML表示,后面会详细介绍):
<templates xmlns="http://www.fixprotocol.org/ns/fast/td/1.1" xmlns:scp="http://www.fixprotocol.org/ns/fast/scp/1.1">
<template name="HelloWorld" id="1">
<string name="Text" id="58" presence="optional">
<default value=" "></default>
</string>
</template>
</templates>
2.3 停止位 (Stop Bits)
消息的每个字节的最高位被保留为字段结束的标志。
因此,下面描述的每个字段将只使用7位字节,第8位(停止位)将设置在字段的最后一个字节上。
2.4 编码消息
为了对消息进行编码,我们需要生成一个Presence Map (PMap),它位于压缩的FAST消息的前面,后面跟着编码的字段。
PMap将在3.1节中详细描述,但是每个字段只有1位,表示该字段是否包含在后续字节中,或被省略。
注意: 在我们的例子中,如果Text字段被省略,它将默认为一个空字符串。(因为上面模板中的xml元素:
<default value=" "></default>
。)
当对消息进行编码时,模板ID通常放在PMap之后的消息中。(我们将在后面进一步讨论这个问题。)这也需要一个PMap位。
所以对于我们简单的单字段消息,我们需要一个具有2位的PMap:
- 说明模板ID在消息中
- 表示文本字段在消息中
编码步骤:
- 这些是高阶位,其余的都是零:
110 0000
。
这是一个1字节的PMap,因此它的第8位设置为1,以表示它是PMap的最后一个字节:11100000 = 0xE0
。 - 下一个字段是模板字段(用于模板1):
000 0001
。
同样,这是一个1字节的字段,所以我们设置第8位来表示结束:10000001 = 0x81
。 - 下一个字段是文本字段内容:“HelloWorld”。
十六进制格式为:H=0x48, e=0x65, l=0x6C, l=0x6C, o=0x6F, W=0x57, o=0x6F, r=0x72, l=0x6C, d=0x64
。
最后一个字节的最高位设置为“1”。使用这个方法,我们得到了文本字段的以下二进制表示形式:
01001000 0100101 0101100 0101100 0101111 01010111 0101111 01110010 0111100 11100100
2.5. FAST 编码消息 “HelloWorld”
串在一起的字段如下所示:
2.6 解码消息
只看上面的二进制数据和模板文件,我们可以通过反转编码过程重构原始消息内容。
我们的输入(编码)FAST消息是:
HEX format: 0xE0 0x81 0x48 0x65 0x6C 0x6C 0x6F 0x57 0x6F 0x72 0x6C 0xE4
Binary format: 11100000 10000001 01001000 01100101 01101100 01101100 01101111 01010111 01101111 01110010 01101100 11100100
让我们一步一步解码:
-
提取消息PMap。消息PMap必须在每个编码的消息之前出现,因此解码过程的第一步必须是定义PMap。
我们从流中获取第一个字节:" 11100000 ",检查它的停止位(最高位或第一个位)。
它被设置为“1”,因此我们编码的PMap由1个字节组成:11100000。我们删除停止位,它产生解码的消息PMap: 1100000 -
解码模板ID。我们从PMap中获得第一个位“1”,它表示输入消息中存在模板ID值。
使用与PMap解码相同的方法,我们解码模板ID:- 我们从流中获得PMap后的下一个字节。它是第二个字节:“10000001”,该字节的停止位为“1”。我们的模板ID是1字节的值。
- 在从模板ID编码值中去除停止位后,我们收到:“0000001” = “1”,这是模板ID的实际值。
模板ID用于定义FAST消息模板,包含字段解码的引用。
-
“HelloWorld”字段解码。来自PMap的下一个位(本例中的第二个位)被设置为“1”,它表示“HelloWorld”字段也出现在输入消息中。
由于文本字段由多个字节组成,我们必须逐个获取下一个输入字节(在模板ID之后)。这是找到停止位设置为“1”并指示“HelloWorld”编码字段结束的字节所必需的。
最高位(停止位)设置为“1”的字节是输入流中的最后一个字节,因此我们的编码文本字段为:
01001000 0100101 0101100 0101100 0101111 01010111 0101111 01110010 0111100 11100100
此文本字段的停止位解码如下。我们必须将文本字段的最后一个字节的停止位从“1”替换为“0”。
之后,我们会收到文本字段的实际值:
Binary format: 01001000 01100101 01101100 01101100 01101111 01010111 01101111 01110010 01101100 01100100
HEX format: 0x48 0x65 0x6C 0x6C 0x6F 0x57 0x6F 0x72 0x6C 0x64
Character format: HelloWorld
我们合并解码的输出字段并接收消息: 58=HelloWorld<SOH>
下图展示了所有这些步骤:
下一节将更详细地描述不同的FAST元素(例如FAST模板和PMap),并介绍更复杂的解码示例。