forwardMessage Validation   Table of ContentTyped FIX messagesforward
Flat FIX Message

Although Message class is designed for high-performance duty, each concept has its bounds and bottlenecks. The serialization/deserialization operation, that is done by the Session each time when an instance of Message is sent/received to/from counterparty, is quite a heavy-weight operation, thus it has a negative influence on general performance. To satisfy the needs of low latency trading, OnixS FIX Engine offers the new concept of editable flat FIX message, exposed as the FlatMessage class. This class provides similar to the Message functionality. It allows accessing and updating FIX fields to be available in the message. However, being pre-serialized, it eliminates the necessity of converting the structured memory presentation into a 'tag=value' form, when the message is actually sent. In such a way, it increases overall performance.

Note Note
All session events are invoked for the regular Message class objects only. Therefore, when FlatMessage object is sent by the Send(FlatMessage) method, then outbound session events are not invoked.

Constructing FlatMessage

FlatMessage instance can be constructed either from a 'tag=value' form or a regular Message class instance. The following code shows the creation of a flat order (MsgType=D) from 'tag=value' form:

C#
string RawOrder = "8=FIX.4.2\u00019=00\u000135=D\u000149=Sender\u000156=Target\u000134=0\u000152=99990909-17:17:17.777\u000154=1\u000155=A001\u000111=BUY000000001\
    u000138=1000\u000140=2\u000144=1001.000\u000159=3\u0001117=A001\u000146=A001\u000110=000\u0001";

// Constructs the flat message from 'tag=value' form
FlatMessage flatOrder = new FlatMessage(RawOrder);
Also FlatMessage instance can be constructed from 'tag=value' form without session-level details, in this case required fields will be added during the construction:
C#
string RawOrderWithoutSessionDetails = "54=1\u000155=A001\u000111=BUY000000001\u000138=1000\u000140=2\u000144=1001.000\u000159=3\u0001117=A001\u000146=A001\u0001";

// Constructs the flat message from 'tag=value' form without session-level details
FlatMessage flatOrder = new FlatMessage(ProtocolVersion.FIX42, "D", "Sender", "Target", RawOrderWithoutSessionDetails);
The following code shows the creation of a flat order (MsgType=D) from the previously filled Message instance:
C#
// Order as an in-memory structured FIX message.
Message msg = new Message(MsgType.NewOrderSingle, ProtocolVersion.FIX44);

// Fills the order in a regular way.
msg.Set(FIX44.Tags.ClOrdID, "ClientOrderID");

msg.Set(FIX44.Tags.OrderQty, 1000);
// Constructs the flat message from the structured instance.
FlatMessage flatOrder = new FlatMessage(order);
// Now the structured instance is not needed any more.
Also, the FlatMessage instance can be constructed as a blank instance or with required message header fields only. In this case, one can add all additional fields by Add(Int32, String) methods:
C#
// Create the blank message.
FlatMessage blankMsg = new FlatMessage();

// You can add all additional fields by 'FlatMessage.Add' methods.

// ..

// Create a message with empty required message header fields.
FlatMessage msg = new FlatMessage(ProtocolVersion.FIX44, MsgType.NewOrderSingle);

// You can add all additional fields by 'FlatMessage.Add' methods.

// ..

Accessing FIX Fields

Once the instance of FlatMessage class is constructed, its fields can be manipulated in a similar way, as in the case of Message. FlatMessage class interface exposes two ways of accessing fields, using temporary references and permanent keys. Temporary references, represented by FlatFieldRef class and permanent keys, are of the FlatFieldKey type. Whatever way is used to access a field, a temporary reference to the field must be obtained first. The FlatMessage class exposes the Find(Int32) method for that purposes. If lookup succeeds, it returns a valid reference instance for a further use:

C#
FlatFieldRef clOrdIdRef = flatOrder.Find(FIX42.Tags.ClOrdID);

// Ensures whether the instance refers to a field.
if(!clOrdIdRef.Valid) throw new Exception("Cannot find ClOrdID field in given Order.");

// Once the reference is obtained, it can be used to update the field value:
flatOrder.Set(ref clOrdIdRef, "NewClientOrderID");
Note Note
An important aspect of a reference is that it remains valid only while manipulating its field value. If another field is updated, the reference may become invalid. References also are invalidated when the instance of FlatMessage class is sent to the counterparty via Send(FlatMessage). For this reason, do not use multiple references at the same time.
For a continuous and non-destructive modification of a FIX field value, the concept of a flat field key is exposed. In contrast to temporary field references, keys remain constant for the entire life of a FlatMessage instance. Changing field values does not invalidate keys, thus multiple fields can be updated without affecting keys. Keys are unique in bounds of a single flat message. The following code demonstrates how a key can be obtained from a temporary reference:
C#
FlatFieldRef clOrdIdRef = flatOrder.Find(FIX42.Tags.ClOrdID);

if(!clOrdIdRef.Valid) throw new Exception("Cannot find ClOrdID field in given Order.");

FlatFieldKey clOrdIdKey = flatOrder.AllocateKey(clOrdIdRef);

// Once the key is obtained, the field value can be accessed and modified:
flatOrder.Set(clOrdIdKey, "YetAnotherCliendOrderID");
Note Note
Keys are similar to the field tags with only one difference. Keys are constant in bounds of a single instance of the FlatMessage class. However, keys may differ for the same field for different instances of the FlatMessage class. Also, tags are statically defined, whereas keys are dynamically allocated by each particular instance of the FlatMessage class.
Also, the FlatMessage class provides the ability to access fields with the same tag from different entries of a flat repeating group. It can be performed with the overloaded Find(Int32, FlatFieldRef) method. The second parameter indicates the FlatFieldRef value after which the search will be performed. Accordingly, you can find all field values with the same tag and allocate keys for further access. The following code demonstrates the access to fields with the same tag:
C#
// Constructs the flat message from the structured instance which has the repeating group.
FlatMessage massQuoteFlatMsg = new FlatMessage(massQuoteMsg);
List<FlatFieldKey> partyIdFieldKeys = new List<FlatFieldKey>();
FlatFieldRef partyIdFieldRef = new FlatFieldRef();

//Finds all PartyID fields
while((partyIdFieldRef = massQuoteFlatMsg.Find(FIXForge.NET.FIX.FIX44.Tags.PartyID, partyIdFieldRef)).Valid)
{
    //Allocates and saves the key for the found PartyID field
    partyIdFieldKeys.Add(massQuoteFlatMsg.AllocateKey(partyIdFieldRef));
}

Console.Write("Found " + partyIdFieldKeys.Count + " party identifiers in flat mass quote:\n");

int partyIdCount = 0;
foreach (FlatFieldKey key in partyIdFieldKeys)
{
    Console.Write("Entry #" + (++partyIdCount) + " has PartyID=" + massQuoteFlatMsg.Get(key) + "\n");
}

Adding FIX Fields

To add a field, use Add(Int32, String) methods. These methods add the given tag/value pair at the end of the message instance:

C#
message.Add(FIX.FIX44.Tags.ClOrdID, "ClOrdID value");

Inserting FIX Fields

To insert a field, you can use Insert(Int32, String, Int32, InsertMode) methods. These methods insert the given tag/value pair to the message instance. The position is specified by the 'posTag' parameter. The InsertMode is used to specify where the new field will be inserted - before or after the position tag:

C#
message.Insert(FIX.FIX44.Tags.PossDupFlag, "Y", FIX.FIX44.Tags.MsgSeqNum, InsertMode.Before);

Removing FIX Fields

To remove a field, use the Remove(Int32) method.

Example

C#
// Order as an in-memory structured FIX message.
Message order = new Message(FIX42.MsgType.Order_Single, ProtocolVersion.FIX42);

// Fills the order in a regular way.
order.Set(FIX42.Tags.ClOrdID, "ClientOrderID");
order.Set(FIX42.Tags.OrderQty, 1000);

// ..

// Constructs a flat message from the structured instance.
// Since this moment, the structured instance is not used any more.
FlatMessage flatOrder = new FlatMessage(order);

FlatFieldRef clOrdIdRef = flatOrder.Find(FIX42.Tags.ClOrdID);

FlatFieldRef qtyRef = flatOrder.Find(FIX42.Tags.OrderQty);

// Ensures whether both fields are found.
if (!clOrdIdRef.Valid || !qtyRef.Valid)
{
    throw new Exception("Cannot find required fields in the Order.");
}

// Once the reference is obtained, it's time to allocate the field key to secure the fast access.
// The key remains constant for the entire message instance life-time.
// However, it refers to a particular instance ONLY.
FlatFieldKey clOrdIdKey = flatOrder.AllocateKey(clOrdIdRef);

FlatFieldKey qtyKey = flatOrder.AllocateKey(qtyRef);

int iteration = 1000;

int qty = Int32.Parse(flatOrder.Get(qtyKey));

while (iteration-- > 0)
{
    // Assigns a new value to the ClOrdID field.
    flatOrder.Set(clOrdIdKey1, "20120522-16:48:38.707");

    // Assigns a new order quantity.
    flatOrder.Set(qtyKey, qty += 1000);

    // Sends the updated order to the counterparty.
    session.Send(flatOrder);

    // Extracts the sequence number assigned to the sent message.
    string seqNumberStr = flatOrder.Get(KnownFlatFieldKeys.SeqNumber());

    Console.Write("Order sent under #" + seqNumberStr + ".\n");
}