一段完整的FAST数据
模板

前面介绍了字段的解析,解析完了F61FA14D303330B131303030303931B106B61BCA811C72BC7F7F7F7FFC00F47F7F7F7FFC00F40124BD这一段数据。

sequence解析

sequence表示接下来会出现多个重复组,重复组的个数通过接下来的第一个字段表示,也就是[91]这个字节,按照整形解析即可。
sequence个数无需自减一,因此接下来有0x11即17个sequence。
·sequence PMAP
前面说过,每个sequence还有各自的PMAP,同样的也是出现在每个sequence流的头部,对于第一个sequence,即[80]这个字节。解析出来为0
在这里,首先来分析一下sequence下的字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<sequence name="MDFullGrp">
<length id="268" name="NoMDEntries">
<copy/>
</length>
<string id="269" name="MDEntryType"></string>
<decimal id="270" name="MDEntryPx" presence="optional">
<delta/>
</decimal>
<uInt64 id="271" name="MDEntrySize" presence="optional">
<delta/>
</uInt64>
<string id="273" name="MDEntryTime" presence="optional">
<tail/>
</string>
<uInt32 id="290" name="MDEntryPositionNo" presence="optional"></uInt32>
</sequence>

根据第一篇介绍的内容,可以发现只有MDEntryTime的操作符为tail,需要在PMAP中占位。由于第一个sequence的PMAP为0,所以可以得知MDEntryTime并不会出现在这个sequence的数据流中。

·NoMDEntries
这个字段的类型为length,实际上就是用来表示sequence个数的,只会在一开始出现,sequence字段内实际不会出现,已经解析出该字段值为17

·MDEntryType
[B0] -> “0”
类型为string,操作符为空,解析很简单[B0] -> [30] -> ASCII码对应字符"0"

·MDEntryPx
[7F 7F 7F 7F FD] [8C] -> 0.012
类型decimal,操作符delta,指数部分符号位为1,参照PrevClosePx解析得到:
指数:[FD] -> 自减一 -> [FC] -> 取反 -> [3] 值为-3    这个值在下一个sequence解析时会用到,这里记做MDEntryPx指数前值
尾数:[8C] -> [0C] 值为12    同样的,记做MDEntryPx尾数前值
结合指数尾数得到字段值为:12 * 10-3 = 0.012

·MDEntrySize
[95] -> 20
uInt64类型,解析很简单,操作符为delta,所以在这里将20作为MDEntrySize的前值

·MDEntryTime
根据PMAP知道这个字段不出现,所以值为空

·MDEntryPositionNo
[81] -> 0
uInt32类型,和uInt64一样解析即可,注意值为非负且optional需要自减一即可。

到这里,第一个sequence的内容就解析出来了,对应数据流为80B07F7F7F7FFD8C9581,接下来解析下一个sequence

·sequence PMAP
[80]
同样的,首先解析这个sequence的PMAP,PMAP为0

·MDEntryType
[B0] -> "0"

·MDEntryPx
[7F 7F 7F 7F FF] [00 EB] -> 0.0119
用同样的方法解析出指数和尾数两个部分:
指数:[FF] -> 自减一 -> [FE] -> 取反 -> [1] 值为-1
尾数:[EB] -> [6B] 值为107
这里就需要用到delta操作符了,MDEntryPx是存在前值的,delta操作符需要将该值与前值相加,然后分别得到新的指数和尾数:
实际指数:指数 + MDEntryPx指数前值 -> -1 + -3 = -4 ,-4才是该字段指数部分的真实值,此时需要把-4作为新的MDEntryPx指数前值
实际尾数:尾数 + MDEntryPx尾数前值 -> 107 + 12 = 119 , 将119作为新的MDEntryPx尾数前值
该sequence下字段MDEntryPx的实际值:119 * 10-4 = 0.0119

·MDEntrySize
[81] -> 20
解析出来值为0,但操作符为delta,所以实际值为:
0 + MDEntrySize前值 -> 0 + 20 = 20 , 20才是该字段的实际值,然后同样将20作为MDEntrySize的新前值。

·MDEntryTime
不出现

·MDEntryPositionNo
[82] -> 1

delta操作符

第二个sequence解析MDEntryPx时用到了delta操作符,之前其它delta操作符解析时没用到时因为前值均为0,但对于一系列sequence来说,前值就有可能不为0,此时就需要用解析出来的字段值再加上前值,才能得到实际的值。

上面详细介绍了前两个sequence的解析过程,接下来先把每个sequence的数据流单独截取出来:
3      80B081FFF683
4      80B081FF8B84
5      80B081FF8185
6      80B181858181
7      80B18182F682
8      80B181818B83
9      80B181828184
10    80B18181F685
11    C0B281FAFB31303334333231B480
12    C0B481FB808080
13    80B5808080
14    80B67F7F7F7FFF7F8C8080
15    80B782019C8080
16    80B8827EEF8080
17    C0F87F7F7F7FFF00E9FB30393235303031B780
正好17个sequence,后面的sequence解析没什么好说的,按照前两个的样子依次去解析即可,这里只给出解析结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{"MDEntryType":"0","MDEntryPx":0.0118,"MDEntrySize":10,"MDEntryPositionNo":2}
{"MDEntryType":"0","MDEntryPx":0.0117,"MDEntrySize":20,"MDEntryPositionNo":3}
{"MDEntryType":"0","MDEntryPx":0.0116,"MDEntrySize":20,"MDEntryPositionNo":4}
{"MDEntryType":"1","MDEntryPx":0.0121,"MDEntrySize":20,"MDEntryPositionNo":0}
{"MDEntryType":"1","MDEntryPx":0.0123,"MDEntrySize":10,"MDEntryPositionNo":1}
{"MDEntryType":"1","MDEntryPx":0.0124,"MDEntrySize":20,"MDEntryPositionNo":2}
{"MDEntryType":"1","MDEntryPx":0.0126,"MDEntrySize":20,"MDEntryPositionNo":3}
{"MDEntryType":"1","MDEntryPx":0.0127,"MDEntrySize":10,"MDEntryPositionNo":4}
{"MDEntryType":"2","MDEntryPx":0.0121,"MDEntrySize":5,"MDEntryTime":"10343214"}
{"MDEntryType":"4","MDEntryPx":0.0116}
{"MDEntryType":"5"}
{"MDEntryType":"6","MDEntryPx":0.00000}
{"MDEntryType":"7","MDEntryPx":0.0156}
{"MDEntryType":"8","MDEntryPx":0.011}
{"MDEntryType":"x","MDEntryPx":0.0116,"MDEntrySize":0,"MDEntryTime":"09250017"}

另外还有一点,对于optional的字段来说,字节流为80就代表这个字段不存在,而不是该字段值为0。

·TradingPhaseCode
[54 20 30 B1] -> "T 01"
string类型,去除停止位解析ASCII码就可以。

这样,模板上的字段都已经依次过了一遍,第一条消息就已经解析了出来。