This article shows the basics of CoralFIX API when it comes to adding/retrieving values from FixMessages, creating new FIX tags and working with repeating groups. You can also get started quickly by using our SimpleFixApplicationServer
and SimpleFixApplicationClient
as described here.
Working with FixMessages
package com.coralblocks.coralfix.sample; import static com.coralblocks.coralfix.FixTags.*; import java.nio.ByteBuffer; import com.coralblocks.coralbits.util.ByteBufferUtils; import com.coralblocks.coralfix.FixConstants.FixVersions; import com.coralblocks.coralfix.FixConstants.MsgTypes; import com.coralblocks.coralfix.FixMessage; import com.coralblocks.coralfix.FixParser; public class Sample { public static void main(String[] args) { FixMessage fixOutMsg = new FixMessage(FixVersions.VERSION_42); // or // FixMessage fixOutMsg = new FixMessage(); // defaults to VERSION_44 (you can change the default with -DfixDefaultVersion=50) fixOutMsg.add(MsgType, MsgTypes.Logon); // or // fixOutMsg.add(MsgType, 'A'); // same thing as above fixOutMsg.add(SenderCompID, "TTTTTTT6"). add(TargetCompID, "TAL").add(5555, 3.14).add(34, "1"); // fluent API // you can add by tag name (enum) and tag id (integer) fixOutMsg.addTimestamp(SendingTime, System.currentTimeMillis()); // UTC time zone by default... // timestamps are automatically converted to the FIX format YYYYMMdd HH:mm:ss.SSS // or if you need a different time zone: // fixOutMsg.addTimestamp(SendingTime, System.currentTimeMillis(), TimeZone.getTimeZone("EST")); fixOutMsg.add(7777, 'Y').add(TargetSubID, "ARCA").add(108, 60).add(98, 0); // you can print the full message for debugging purposes: System.out.println(fixOutMsg); // prints BeginString(8)=FIX.4.2 BodyLength(9)=97 MsgType(35)=Logon("A") SenderCompID(49)=TTTTTTT6 TargetCompID(56)=TAL Unknown(5555)=3.14000000 MsgSeqNum(34)=1 SendingTime(52)=20140707-19:37:11.429 Unknown(7777)=Y TargetSubID(57)=ARCA HeartBtInt(108)=60 EncryptMethod(98)=0 ByteBuffer bb = ByteBuffer.allocate(1024); fixOutMsg.writeTo(bb); // write complete fix message to the ByteBuffer... bb.flip(); // you can also print the ByteBuffer for debugging purposes: ByteBufferUtils.println(bb); // ByteBufferUtils.println does not change the ByteBuffer position... // prints [8=FIX.4.29=9735=A49=TTTTTTT656=TAL5555=3.1400000034=152=20140707-19:37:11.4297777=Y57=ARCA108=6098=010=160] // note: SOH character which separates tags is a non-ascii character so you don't see it... FixParser parser = new FixParser(); FixMessage fixMsg = parser.parse(bb); // passing the tag name as an enum System.out.println(fixMsg.getInt(BodyLength)); // prints 80 // BodyLength = tag 9 // you can also pass the tag name as a String System.out.println(fixMsg.getLong("HeartBtInt")); // prints 60 // HeartBtInt = tag 108 // you can also pass the tag id System.out.println(fixMsg.getDouble(5555)); // prints 3.14 // gets timestamp as epoch UTC long System.out.println(fixMsg.getTimestamp(SendingTime)); // prints 1104411600000 // gets the timestamp as a CharSequence System.out.println(fixMsg.getCharSequence(SendingTime)); // prints 20140707-19:42:57.002 // gets a single char System.out.println(fixMsg.getChar(7777)); // prints Y // gets value as a CharSequence System.out.println(fixMsg.getCharSequence(BeginString)); // prints FIX.4.2 // BeginString = tag 8 // gets a ByteBuffer with the value System.out.println(fixMsg.getByteBuffer(BeginString)); // prints java.nio.HeapByteBuffer[pos=2 lim=9 cap=109] // prints the whole message for debugging purposes System.out.println(fixMsg); // prints BeginString(8)=FIX.4.2 BodyLength(9)=109 BeginString(8)=FIX.4.2 BodyLength(9)=87 MsgType(35)=Logon("A") SenderCompID(49)=TTTTTTT6 TargetCompID(56)=TAL Unknown(5555)=3.14 MsgSeqNum(34)=1 SendingTime(52)=20041230-13:00:00 Unknown(7777)=Y TargetSubID(57)=ARCA HeartBtInt(108)=60 EncryptMethod(98)=0 CheckSum(10)=009 } }
Notice above that you can add fix tag values to a FixMessage
by passing the tag directly (as a Java enum) or the tag id (as an int). The tag values can be passed in a variety of formats from primitives to CharSequence
s. You can also chain many add
methods in the same line (fluent API).
In the other hand, when getting the fix tag values from the FixMessage
, you can fetch them in a variety of formats, from primitive values (no garbage is created when parsing primitives) to String
and ByteBuffer
objects. To get the values you can pass the tag directly (as a Java enum), the tag name (as a String) or the tag id (as an int).
The whole FixMessage
can also be printed for debugging purposes through its toString
method.
Working with FIX tags and MsgTypes
The class FixTags
defines most of the FIX tags by id as specified by the standard FIX dictionary. As we did in our first example above, you can statically import FixTags.*
to use fix tags straight in your code by their names (i.e. java enums). Of course you can also add new tags. Below some examples:
import static com.coralblocks.coralfix.FixTags.*; // the flexibility and convenience of Java enumerations: System.out.println(AllocAccount); // => AllocAccount(79) // you can get a FixTag by its id: System.out.println(fromId(79)); // => AllocAccount(79) // you can get a FixTag by its name: System.out.println(fromName("AllocAccount")); // => AllocAccount(79) // you can define new FixTags easily: System.out.println(fromName("SuperTag")); // => null addTag("SuperTag", 6767); System.out.println(fromName("SuperTag")); // => SuperTag(6767) // now instead of using the string "SuperTag" everywhere, // you can create a variable to use instead private final static FixTag SuperTag = addTag("SuperTag", 6767); // then use everywhere the variable instead of the string fixMsg.add(SuperTag, "aValue"); // instead of fixMsg.add("SuperTag", "aValue"); // same thing when getting: fixMsg.getCharSequence(SuperTag); // instead of fixMsg.getCharSequence("SuperTag"); // you can check if a tag is defined by name and id: System.out.println(isDefined("BeginString")); // => true System.out.println(isDefined(79)); // => true System.out.println(isDefined("blahblah")); // => false System.out.println(isDefined(8888)); // => false // and you can print all tags if you want to: printAll();
By statically importing FixConstants.*
, the same can be done for MsgTypes in case you need to define any new one that is not already defined:
import static com.coralblocks.coralfix.FixConstants.*; System.out.println(MsgTypes.NewOrderSingle); // => NewOrderSingle("D") // but you can also add new ones: MsgTypes.add("MyMessageType", "t"); MsgTypes.add("SomeOtherType", "tx"); System.out.println(MsgTypes.fromValue("t")); // => MyMessageType("t") System.out.println(MsgTypes.fromValue("tx")); // => SomeOtherType("tx") System.out.println(MsgTypes.fromName("MyMessageType")); // => MyMessageType("t") System.out.println(MsgTypes.fromName("SomeOtherType")); // => SomeOtherType("tx") System.out.println(MsgTypes.isValueDefined("t")); // => true System.out.println(MsgTypes.isNameDefined("SomeOtherType")); // => true
Working with repeating groups
CoralFIX makes it very easy and straightforward to work with FIX repeating groups, even in the situation where you have repeating groups inside repeating groups. See the examples below:
package com.coralblocks.coralfix; import static com.coralblocks.coralfix.FixConstants.MsgTypes.*; import static com.coralblocks.coralfix.FixTags.*; import java.nio.ByteBuffer; import java.util.Iterator; public class Sample3 { public static void main(String[] args) { FixMessage fixOutMsg = new FixMessage(); fixOutMsg.add(MsgType, QuoteStatusRequest); fixOutMsg.add(SenderCompID, "TTTTTTT6"). add(TargetCompID, "TAL").add(5555, 3.14).add(34, 1); fixOutMsg.addTimestamp(SendingTime, System.currentTimeMillis()); fixOutMsg.add(7777, 'Y').add(TargetSubID, "ARCA").add(108, 60).add(98, 0); FixGroup fixGroup = fixOutMsg.createGroup(NoRelatedSym); // group element 1: fixGroup.nextElement().add(Symbol, "AAPL").add(SettlDate, 1).add(SecurityDesc, "blah1"); // group element 2: FixGroupElement fixGroupElem = fixGroup.nextElement(); fixGroupElem.add(Symbol, "IBM").add(SettlDate, 2).add(SecurityDesc, "blah2"); // group element 3: fixGroupElem = fixGroup.nextElement(); fixGroupElem.add(Symbol, "LDK"); fixGroupElem.add(SettlDate, 3).add(SecurityDesc, "blah3"); // group element 4: fixGroup.nextElement().add(Symbol, "FB").add(SettlDate, 4).add(SecurityDesc, "blah4"); System.out.println(fixOutMsg); // for debugging purposes... ByteBuffer bb = ByteBuffer.allocate(1024); fixOutMsg.writeTo(bb); // write complete fix message to the ByteBuffer... bb.flip(); FixParser parser = new FixParser(); // define a repeating group for a message type: parser.addGroupTemplate(QuoteStatusRequest, NoRelatedSym, Symbol, SettlDate, SecurityDesc); /* Explanation about addGroupTemplate above: * * QuoteStatusRequest is the message type containing the repeating group * * NoRelatedSym is the main repeating group tag, meaning the repeating groups will * start after that tag. This tag contains the number (i.e. an integer) of repeating groups that follow. * * Symbol is the very first tag that every repeating group will have. That's important * to correctly denote the starting of a new repeating group and is enforced by the * FIX spec (i.e. you can't start a new repeating group with another tag) * * SettlDate, SecurityDesc, etc. are all the other tags (not included the very first * one above) that this repeating group can contain. They can be specified in any order * and can appear in the repeating group in any order. They are also all optional, in other words, * they do not need to appear in the FIX message but they do have to be specified here. */ FixMessage fixMsg = parser.parse(bb); fixGroup = fixMsg.getGroup(NoRelatedSym); System.out.println(fixGroup.getNumberOfElements()); // => 4 // you can also print the whole fix group for debugging purposes: System.out.println(fixGroup); // Symbol(55)=AAPL SettlDate(64)=1 SecurityDesc(107)=blah1 | Symbol(55)=IBM SettlDate(64)=2 SecurityDesc(107)=blah2 | Symbol(55)=LDK SettlDate(64)=3 SecurityDesc(107)=blah3 | Symbol(55)=FB SettlDate(64)=4 SecurityDesc(107)=blah4 System.out.println(); Iterator<FixGroupElement> iter = fixGroup.iterator(); while(iter.hasNext()) { FixGroupElement elem = iter.next(); // fetch fix tag values as usual: System.out.println(elem.getCharSequence(Symbol)); System.out.println(elem.getInt("SettlDate")); System.out.println(elem.getCharSequence(107)); // you can also print the whole element for debugging purposes: System.out.println(elem); System.out.println(); } } }
When it comes to building a FixMessage
with a repeating group, you just create a FixGroup
in the message and then call nextElement()
on the FixGroup
to create a new FixGroupElement
with as many tags as you want. Each FixGroupElement
will have the repeating tags of the group and you don’t need to specify the number of repeating groups (i.e. the value of tag NoRelatedSym
above) because this is done automatically by counting the number of FixGroupElement
s created.
When it comes to parsing, the most important part of the code above is where the fix repeating group is specified. The line means: message type QuoteStatusRequest
has a repeating group defined by tag NoRelatedSym
(specifies the number of repeating group elements) with the following possible tags: Symbol
(first and mandatory for all elements), SettlDate
and SecurityDesc
.
Groups inside groups
A FIX message can contain repeating groups inside repeating groups. CoralFIX makes it very easy to deal with that situation as well. See the examples below:
package com.coralblocks.coralfix; import static com.coralblocks.coralfix.FixConstants.MsgTypes.*; import static com.coralblocks.coralfix.FixTags.*; import java.nio.ByteBuffer; import java.util.Iterator; public class Sample4 { public static void main(String[] args) { FixMessage fixOutMsg = new FixMessage(); fixOutMsg.add(MsgType, QuoteStatusRequest); fixOutMsg.add(SenderCompID, "TTTTTTT6"). add(TargetCompID, "TAL").add(5555, 3.14).add(34, 1); fixOutMsg.addTimestamp(SendingTime, System.currentTimeMillis()); fixOutMsg.add(7777, 'Y').add(TargetSubID, "ARCA").add(108, 60).add(98, 0); FixGroup fixGroup = fixOutMsg.createGroup(NoRelatedSym); FixGroupElement elem; FixGroup subgroup; // group element 1: elem = fixGroup.nextElement(); elem.add(Symbol, "AAPL").add(SettlDate, 1).add(SecurityDesc, "blah1"); // subgroup with 2 elements: subgroup = elem.createGroup(NoTestSubgroup); subgroup.nextElement().add(TestTag1, "foo111").add(TestTag2, "foo112"); subgroup.nextElement().add(TestTag1, "foo121").add(TestTag2, "foo122"); // group element 2: elem = fixGroup.nextElement(); elem.add(Symbol, "IBM").add(SettlDate, 2).add(SecurityDesc, "blah2"); // subgroup with 3 elements: subgroup = elem.createGroup(NoTestSubgroup); subgroup.nextElement().add(TestTag1, "foo211").add(TestTag2, "foo212"); subgroup.nextElement().add(TestTag1, "foo221").add(TestTag2, "foo222"); subgroup.nextElement().add(TestTag1, "foo231").add(TestTag2, "foo232"); // group element 3: elem = fixGroup.nextElement(); elem.add(Symbol, "LDK").add(SettlDate, 3).add(SecurityDesc, "blah3"); // subgroup with 1 element: subgroup = elem.createGroup(NoTestSubgroup); subgroup.nextElement().add(TestTag1, "foo311").add(TestTag2, "foo312"); // group element 4: elem = fixGroup.nextElement(); elem.add(Symbol, "FB").add(SettlDate, 4).add(SecurityDesc, "blah4"); // subgroup with 2 elements: subgroup = elem.createGroup(NoTestSubgroup); subgroup.nextElement().add(TestTag1, "foo411").add(TestTag2, "foo412"); subgroup.nextElement().add(TestTag1, "foo421").add(TestTag2, "foo422"); System.out.println(fixOutMsg); // for debugging purposes... ByteBuffer bb = ByteBuffer.allocate(1024); fixOutMsg.writeTo(bb); // write complete fix message to the ByteBuffer... bb.flip(); FixParser parser = new FixParser(); // define a repeating group for a message type: parser.addGroupTemplate(QuoteStatusRequest, NoRelatedSym, Symbol, SettlDate, SecurityDesc, NoTestSubgroup); parser.addSubgroupTemplate(NoRelatedSym, NoTestSubgroup, TestTag1, TestTag2, TestTag3, TestTag10, TestTag8); /* * Explanation about the addSubgroupTemplate above: * * NoRelatedSym is the parent repeating group, in other words, the repeating group that will * contain another repeating group. * It will most likely have been specified by a previous addGroupTemplate method. * * NoTestSubgroup is the main repeating group tag, meaning the repeating groups will * start after that tag. This tag contains the number (i.e. an integer) of repeating groups that follow. * * TestTag1 is the very first tag that every repeating group will have. That's important * to correctly denote the starting of a new repeating group and is enforced by the * FIX spec (i.e. you can't start a new repeating group with another tag) * * TestTag2, TestTag3, TestTag10, TestTag8 are all the other tags (not included the very first * one above) that this repeating group can contain. They can be specified in any order * and can appear in the repeating group in any order. They are also all optional, in other words, * they do not need to appear in the FIX message but they do have to be specified here. */ FixMessage fixMsg = parser.parse(bb); fixGroup = fixMsg.getGroup(NoRelatedSym); Iterator<FixGroupElement> iter = fixGroup.iterator(); while(iter.hasNext()) { elem = iter.next(); // fetch fix tag values as usual: System.out.println(elem.getCharSequence(Symbol)); System.out.println(elem.getInt("SettlDate")); System.out.println(elem.getCharSequence(107)); // you can also fetch a group as usual from the group subgroup = elem.getGroup(NoTestSubgroup); Iterator<FixGroupElement> iter2 = subgroup.iterator(); while(iter2.hasNext()) { FixGroupElement e = iter2.next(); // and you can fetch the fix tag values as usual: System.out.println(e.getCharSequence(TestTag1)); System.out.println(e.getCharSequence(TestTag2)); } System.out.println(); } } }
When it comes to building a FixMessage
, you can add a subgroup by calling createGroup
on a FixGroupElement
. Then you just call nextElement()
and add the values as usual. When it comes to parsing, the most important part of the code above is where the fix repeating subgroup is specified. This line means: the group NoRelatedSym
can contain a subgroup defined by tag NoTestSubgroup
(specifies the number of repeating subgroup elements) with the following possible tags: TestTag1
(first and mandatory for all elements) and TestTag2
. Also note that we must also include the new tag NoTestSubgroup
in the group template list for the group NoRelatedSym
.
Conclusion
CoralFIX makes it very easy to parse fix messages. The API comes with the most common fix tags and you can easily define new ones as needed. Working with fix tags is very easy because they are all Java enumerations that you can use directly inside your code. CoralFix also provides a simple and fast API to fetch fix tag values from fix messages, fix repeating groups and even from groups inside groups. The library is an ultra-low-latency Coral Blocks component that has minimal variance and produces zero garbage.