forwardFIX Engine Thread Safety   Table of ContentFIX Sessionsforward
FIX Repeating Groups
Structure of 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:

Repeating Group Structure

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:

  • Well-defined FIX messages assume all fields of a repeating group that follow one another. The appearance of an arbitrary field, which doesn't belong to the repeating group (according to the FIX specification), automatically indicates the end of the repeating group. Therefore, the further appearance of fields from the repeating group is disallowed by the FIX Standard.
  • It is possible for repeating groups to appear inside of another repeating group. In such a case, all entries of the inner repeating group belong to the single entry of the outer repeating group.
  • The number of entries or instances, which are defined by the value of the leading field (tag), must correspond to the number of instances/entries, which actually appear in the message. In particular, number of tags-separators must equal to value of the leading field.

Group class

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.

Adding Group into Message

To create a new repeating group or modify the number of instances, the SetGroup(Int32, Int32) method is available.

Note 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.
Accessing Repeating Group Entries

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.

Removing Repeating Group from Message

To remove an entire repeating group together with its leading tag, the Remove(Int32) method is exposed by the FieldSet class.

Detecting Ill-Formed Repeating Group

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 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.

Example
C#
// 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());
VB
' 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())
See Also