FIX Engine Thread Safety | Table of Content | FIX Sessions |
FIX Repeating Groups |
Sometimes fields of the same tag number can appear multiple times in the same message within a so-called repeating group.
The following diagram depicts the general structure of a repeating group in a FIX message:
Each repeating group starts from the field which identifies the number of repeating entries within the repeating group. Such a leading field must immediately precede the repeating group entries. In the referenced example, the leading field is defined by the NoRoutingIDs tag.
Each entry of a repeating group has a selected field which in turn identifies the beginning of a group new entry. This field must occur in a raw message before any other tag from a single repeating group entry. In other words, these fields separate repeating group entries from each other. RoutingType field is an example of such a separator.
Important aspects of FIX repeating groups structure:
OnixS .NET Framework FIX Engine exposes Group class to encapsulate all aspects related to handling FIX repeating groups.
Since a repeating group is identified by the leading field, which defines the number of repeating instances, OnixS .NET Framework FIX Engine follows this approach in handling repeating groups. In particular, the Group object is accessed using its leading (number of instances) field. Changing the value of this field affects the length of a repeating group. Removing this field from a message or other repeating group removes all entries of the repeating group.
To create a new repeating group or modify the number of instances, the SetGroup(Int32, Int32) method is available.
Note |
---|
Setting non-zero integer value for a field, which defines a number of instances of a repeating group, implicitly creates and/or changes the length of the repeating group object. |
To obtain a reference to the Group object that represents an existing repeating group of the message, the GetGroup(Int32) method is available.
The Group class works with fields, as well as with embedded repeating groups in the same manner as the Message class. The only difference in accessing field values is the availability of an additional parameter, which defines the index of the repeating group entry whose field is being accessed. Entries indexing starts from zero. Additionally, the Group class supports the IEnumerable interface, therefore you can use a Group object in the foreach operator to enumerate group entries of a repeating group.
To remove an entire repeating group together with its leading tag, the Remove(Int32) method is exposed by the FieldSet class.
Due to the design of the FIX protocol, the FIX repeating group cannot be parsed properly without the additional information that describes its structure. This is a well-known feature/flaw of the FIX protocol - and is applicable to any software that parses FIX repeating groups. If the FIX destination you work with uses non-standard (custom) fields in the repeating group, then the FIX Engine needs the corresponding XML-based FIX Dialect description file.
In a well-formed repeating group, the declared number of repeated instances (defined by the number of instances field) should be equal to the actual number of instances. By default, the FIX Engine reports an error if the incoming message does not meet this requirement. This behavior could be changed via the ValidateRepeatingGroupEntryCount setting.
By default, FIX Engine does not check that each entry of a repeating group starts from a selected field which identifies the beginning of a group new entry.
Note |
---|
It is not recommended to set the ValidateRepeatingGroupEntryCount setting to false because this can lead to data loss during the message parsing without any notification about an error. |
By default, the FIX Engine does not check that each repeating group instance starts with the correct leading field. This behavior could be changed via the ValidateRepeatingGroupLeadingTag setting. It is also possible to detect the ill-formed repeating group using the Validate() method.
// Forms 'Market Data Request' message. Message request = new Message( MsgType.MarketDataRequest, ProtocolVersion.FIX44); // Sets up regular fields. request.Set(Tags.MDReqID, "ABSD"); request.Set(Tags.SubscriptionRequestType, 1); request.Set(Tags.MarketDepth, 1); request.Set(Tags.MDUpdateType, 1); request.Set(Tags.AggregatedBook, "N"); // Creates a repeating group NoMDEntryTypes with two instances. Group groupMDEntryTypes = request.SetGroup(Tags.NoMDEntryTypes, 2); // Defines fields in the first instance/entry of repeating group. groupMDEntryTypes.Set(Tags.MDEntryType, 0, "EntryType_0"); // . and the same but for the second instance. groupMDEntryTypes.Set(Tags.MDEntryType, 1, "EntryType_1"); // Create a repeating group NoRelatedSym with two instances. // (another way of creating and accessing repeating group). request.Set(Tags.NoRelatedSym, 2); Group groupRelatedSym = request.GetGroup(Tags.NoRelatedSym); groupRelatedSym.Set(Tags.Symbol, 0, "EURUSD_0"); groupRelatedSym.Set(Tags.Symbol, 1, "EURUSD_1"); // Create embedded repeating group which belongs to first entry of // groupRelatedSym repeating group Group groupSecAltID = groupRelatedSym.SetGroup(Tags.NoSecurityAltID, 0, 1); groupSecAltID.Set(Tags.SecurityAltID, 0, "EURUSD_Alt_0"); request.Validate(); // Get data from group string symbol1 = groupRelatedSym.Get(Tags.Symbol, 0); string symbol2 = groupRelatedSym.Get(Tags.Symbol, 1); string altID = groupSecAltID.Get(Tags.SecurityAltID, 0); Console.WriteLine(request.ToString());
' Forms Market Data Request message. Dim request As Message = New Message( _ MsgType.MarketDataRequest, FIXForge.NET.FIX.ProtocolVersion.FIX44) ' Sets up regular fields. request.Set(Tags.MDReqID, "ABSD") request.Set(Tags.SubscriptionRequestType, 1) request.Set(Tags.MarketDepth, 1) request.Set(Tags.MDUpdateType, 1) request.Set(Tags.AggregatedBook, "N") ' Creates a repeating group NoMDEntryTypes with two instances. Dim groupMDEntryTypes As Group = request.SetGroup(Tags.NoMDEntryTypes, 2) ' Defines fields in the first instance/entry of repeating group. groupMDEntryTypes.Set(Tags.MDEntryType, 0, "EntryType_0") ' . and the same but for the second instance. groupMDEntryTypes.Set(Tags.MDEntryType, 1, "EntryType_1") ' Creates a repeating group NoRelatedSym with two instances. ' (another way of creating and accessing repeating group). request.Set(Tags.NoRelatedSym, 2) Dim groupRelatedSym As Group = request.GetGroup(Tags.NoRelatedSym) groupRelatedSym.Set(Tags.Symbol, 0, "EURUSD_0") groupRelatedSym.Set(Tags.Symbol, 1, "EURUSD_1") ' Creates embedded repeating group which belongs to first entry of ' groupRelatedSym repeating group Dim groupSecAltID as Group = groupRelatedSym.SetGroup(Tags.NoSecurityAltID, 0, 1) groupSecAltID.Set(Tags.SecurityAltID, 0, "EURUSD_Alt_0") request.Validate() ' Gets data from group Dim symbol1 As String = groupRelatedSym.Get(Tags.Symbol, 0); Dim symbol2 As String = groupRelatedSym.Get(Tags.Symbol, 1); Dim altID As String = groupSecAltID.Get(Tags.SecurityAltID, 0); Console.WriteLine(request.ToString())