Message Validation | Table of Content | Typed FIX messages |
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 |
---|
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. |
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:
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);
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);
// 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.
// 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. // ..
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:
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 |
---|
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. |
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 |
---|
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. |
// 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"); }
To add a field, use Add(Int32, String) methods. These methods add the given tag/value pair at the end of the message instance:
message.Add(FIX.FIX44.Tags.ClOrdID, "ClOrdID value");
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:
message.Insert(FIX.FIX44.Tags.PossDupFlag, "Y", FIX.FIX44.Tags.MsgSeqNum, InsertMode.Before);
To remove a field, use the Remove(Int32) method.
// 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"); }