在.NET中解析FIX协议消息的最有效方法是什么?

时间:2011-02-05 15:52:56

标签: .net finance fix-protocol

我遇到this very similar question,但该问题被标记为QuickFIX(与我的问题无关),大部分答案都与QuickFIX相关。

我的问题更广泛。我正在寻找 使用C# 解析FIX Protocol消息的最有效方法。作为背景,FIX消息由一系列由ASCII <SOH>字符(0x01)分隔的标记/值对组成。消息中的字段数是可变的。

示例消息可能如下所示:

8=FIX.4.2<SOH>9=175<SOH>35=D<SOH>49=BUY1<SOH>56=SELL1<SOH>34=2482<SOH>50=frg<SOH>
52=20100702-11:12:42<SOH>11=BS01000354924000<SOH>21=3<SOH>100=J<SOH>55=ILA SJ<SOH>
48=YY77<SOH>22=5<SOH>167=CS<SOH>207=J<SOH>54=1<SOH>60=20100702-11:12:42<SOH>
38=500<SOH>40=1<SOH>15=ZAR<SOH>59=0<SOH>10=230<SOH>

对于每个字段,标记(整数)和值(对于我们的目的,字符串)由'='字符分隔。 (每个标签的精确语义都在协议中定义,但这与这个问题没有特别密切关系。)

通常情况下,在进行基本解析时,您只对FIX标头中的一些特定标记感兴趣,而不是真正对每个可能的字段进行随机访问。我考虑过的策略包括:

  • 使用String.Split,迭代每个元素并将标记放入Hashtable中的索引映射 - 如果需要,可以提供对所有字段的完全随机访问

  • (轻微优化)使用String.Split,扫描数组中感兴趣的标签并将标记放入索引映射到另一个容器(不一定是Hashtable,因为它可能是相当少量的项目,并且在解析之前已知项目数量

  • 使用String.IndexOf按字段扫描消息字段,并将感兴趣的字段的偏移量和长度存储在适当的结构中

关于前两个 - 虽然我的测量表明String.Split非常快,但根据the documentation,该方法为结果数组的每个元素分配一个新的String,如果你生成大量垃圾正在解析很多消息。任何人都可以在.NET中看到更好的方法来解决这个问题吗?

修改

我遗漏的三条重要信息:

  1. 标签在FIX消息中不一定是唯一的,即在某些情况下可能会出现重复的标签。

  2. 某些类型的FIX字段可以在数据中包含“嵌入式<SOH>” - 这些标记被称为“数据”类型 - 字典列出了此类型的标记号。

  3. 最终的要求是能够编辑消息(特别是替换值)。

4 个答案:

答案 0 :(得分:8)

假设您是通过网络获取这些消息,或者是从磁盘加载它们。在任何一种情况下,您都可以将它们作为字节数组访问,并以正向读取方式读取字节数组。如果你想要/需要/需要高性能,那么自己解析字节数组(为了高性能,不要使用标签和值的散列表字典,因为这比较慢)。自己解析字节数组也意味着您可以避免使用您不感兴趣的数据,并且可以优化解析以反映这一点。

您应该能够轻松避免大多数对象分配。您可以非常轻松地解析FIX浮点数据类型,而无需创建对象(您可以在此处使用自己的版本大幅超越double.parse)。您可能需要考虑更多的标签值是字符串,例如FIX中的符号值。为了避免在这里创建字符串,你可以想出一个简单的方法来确定每个符号的唯一int标识符(这是一个值类型),这将再次帮助你避免在堆上进行分配。

正确完成的消息的自定义优化解析应该轻松胜过QuickFix,你可以在.NET或Java中没有垃圾收集的情况下完成所有这些。

答案 1 :(得分:3)

我肯定会开始实施你的第一种方法,因为它听起来很清楚,也很容易。

Dictionary<int,Field>对我来说似乎非常好,可能包含在FixMessage类中,公开了GetFieldHavingTag(int tag)等方法......

我不知道FIX协议,但是看着你的例子似乎消息通常很短并且字段也是如此,因此内存分配压力不应该成为问题。

当然,唯一可以确定方法是否合适的方法是实现并测试它。

如果您注意到在大量消息的情况下该方法很慢,那么对其进行分析并找出问题的原因/位置。

如果你不能轻易解决,那么是的,改变策略,但我想强制你需要先测试它,然后对其进行分析并最终改变它。

所以,让我们想象一下,在你第一次实现之后,你已经注意到很多字符串分配会降低你的性能,以防万一消息。

然后是的,我会采取类似于你的第三种方法,让我们称之为“按需/懒惰方式”。

我会构建一个类FixMessage来获取字符串消息,并且在需要任何消息字段之前不执行任何操作。
在这种情况下,我会使用IndexOf(或类似的东西)来搜索请求的字段,或者在另一个相同请求的情况下缓存结果更快。

答案 2 :(得分:2)

我知道这是一个老问题的答案 - 我刚刚才意识到在SO上有很多与FIX相关的问题,所以我想我会回答这个问题。

您的问题的答案可能取决于您实际解析的特定FIX消息。在某些情况下,是的 - 你可以在字符串上做一个'拆分',或者你有什么,但是如果你打算解析协议中定义的所有消息,你真的没有选择,只能参考一个FIX数据字典,并逐字节地解析消息。这是因为FIX消息中存在长度编码字段 - 根据规范,可能包含会干扰您可能想要采取的任何“拆分”方法的数据。

最简单的方法是引用字典并根据您收到的消息的类型(标记35)检索消息定义。然后,您需要一个接一个地提取标记,引用消息定义中的相应标记定义,以便了解如何解析与标记关联的数据。这也可以帮助您处理消息中可能存在的“重复组” - 如果您从字典中获得消息定义,您将只能理解标记表示重复组的开始。

我希望这会有所帮助。如果您想要一个参考示例,我为.NET编写了VersaFix开源FIX引擎,其中包含一个基于字典的消息解析器。您可以通过将SVN客户端指向:

直接从我们的Subversion服务器下载源代码
svn://assimilate.com/VfxEngine/Trunk

干杯。

答案 3 :(得分:1)

您可能最好诚实地使用QuickFix并为其构建托管C ++包装器。如果您完全关注延迟,那么您不能在解析过程中执行分配,因为这会导致GC运行,从而暂停您的FIX引擎。暂停时,您无法发送或接收消息,因为我确信您知道这些消息非常糟糕。

几年前,微软曾向一家公司强调,完全用c#构建FIX引擎。他们会建立一个在交易日使用的对象池,并在白天不进行任何分配。

我不知道你的延迟要求是什么,但对于我正在做的事情,我们使用了codegen,不同类型的多线程堆来获得性能并减少延迟。我们使用c ++和haskell的混合。

根据您的要求,可以将解析器实现为内核模式驱动程序,以允许在线路接收消息时构造消息。

@Hans:10微秒是很长的一段时间。纳斯达克在98微秒内完成订单,新加坡证券交易所宣布今年推出新平台需要90微秒。