QuickFIX/J Messages

QuickFIX/J Messages

By Brian Coyner, OCI Senior Software Engineer

July 2006


Introduction

QuickFIX/J is an open-source implementation of the Financial Information eXchange (FIX) protocol. FIX is a messaging standard for real-time electronic security exchange transactions. FIX defines application level messages for creating, canceling, and replacing orders for stocks, options, futures, etc., as well as messages for reporting the status of an order request. FIX also defines session level messages for maintaining connectivity with a counterparty (e.g. NASDAQ, CME, NYSE).

FIX messages are composed of name/ value pairs called fields. The protocol defines the meaning of each field and the messages that use them. A FIX message is comprised of a standard header and standard trailer, as well as a body containing fields specific to a particular message. Fields are delimited by the ASCII control character SOH (0x01), which unfortunately, does not show up in many editors. Fields are identified by arbitrary tag numbers defined by the FIX protocol, and the values of many fields are enumerated rather than being obvious (35=D) means, "submit a new order". This makes it difficult to read and understand raw FIX messages. A tool like Log4FIX can help.

Here is an example message to purchase 100 shares of Apple (AAPL) at market price. The order is submitted to the "fake" BCE exchange:

8=FIX.4.29=11735=D34=249=CoyTrade52=20060516-22:35:40.76356=BCE11=121=338=10040=154=155=AAPL60=20060516-22:35:4010=145

FIX messages are composed of many fields. Knowing which fields are required, conditionally required, or optional, requires an understanding of the FIX protocol and how the counterparty interprets the protocol. Delving into the FIX protocol is beyond the scope of this article.

User Defined Fields

User defined fields are allowed by the FIX protocol to provide maximum flexibility for its users. Field tag values 5000 through 9999 are reserved for user-defined fields, and it is recommended that all user-defined fields be registered with the FIX protocol to avoid conflicts. Field numbers greater than or equal to 10000 are reserved for internal use within an institution and must not be used for external communication.

Your counterparty will provide documentation on how to properly construct and interpret FIX messages for their system.

Creating Messages With User Defined Fields

This article focuses on generating FIX 4.2 New Order - Single messages, which are used to electronically submit orders to a broker for execution. Submitting a new order message requires a symbol (tag 55), whether the trader wishes to buy or sell (tag 54), if the order type is a limit, market, stop limit, etc. (tag 40), as well as a handful of other required, optional, and conditionally required fields. In addition to the standard FIX fields, an institution may require user-defined fields. Our counterparty requires the CorrelationClOrdID user-defined field (tag 9717) for all New Order - Single messages.

All message generation code is encapsulated in an implementation of SubmitOrder. The SubmitOrder interface is a domain-specific interface that accepts a domain-specific Order. These classes are not part of QuickFIX/J. Your application will have similar classes.

  1. public interface SubmitOrder {
  2. void submitOrder(Order order);
  3. }

We will journey through a handful of techniques describing the "right" and "wrong" way to create QuickFIX/J messages. We start by looking at the you-really-should-not-do-it-this-way approach, and we end by looking at how to customize QuickFIX/J to provide an extra layer of compile-time safety.

Magic Numbers Are Evil

FIX fields are specified by the FIX protocol. Thus a FIX message could be created like this:

  1. import quickfix.Message;
  2. import quickfix.field.MsgType;
  3.  
  4. public class DoNotUseMagicValuesSubmitOrder implements SubmitOrder {
  5.  
  6. public void submitOrder(Order order) {
  7.  
  8. Message message = new Message();
  9.  
  10. // 35 is the message type field. "D" means 'new order'
  11. message.getHeader().setString(35, "D");
  12.  
  13. // required FIX 4.2 fields
  14. message.setString(11, order.getClientOrderId());
  15. message.setChar(21, order.getHandlingInstruction().getValue());
  16. message.setString(55, order.getSymbol());
  17. message.setChar(54, order.getSide().getValue());
  18. message.setChar(40, order.getOrderType().getValue());
  19. message.setUtcTimeStamp(60, order.getTransactionTime());
  20.  
  21. // required user-defined field (CME)
  22. message.setString(9717, order.getClientOrderId());
  23.  
  24. // market order fields
  25. message.setDouble(38, order.getQuantity());
  26. message.setDouble(44, order.getPrice());
  27.  
  28. // submit the order...
  29. }
  30. }

Yikes! The name of the class says it all. Using "magic" values is considered a bad practice and should be avoided at all costs.

Step In The Right Direction

Let's examine a solution that fixes some of the problems in the previous example.

  1. import quickfix.Message;
  2. import quickfix.field.ClOrdID;
  3. import quickfix.field.HandlInst;
  4. import quickfix.field.OrdType;
  5. import quickfix.field.Side;
  6. import quickfix.field.OrderQty;
  7. import quickfix.field.Symbol;
  8. import quickfix.field.TransactTime;
  9. import quickfix.field.MsgType;
  10.  
  11. public class StepInTheRightDirectionSubmitOrder implements SubmitOrder {
  12.  
  13. public void submitOrder(Order order) {
  14. Message message = new Message();
  15. message.getHeader().setString(MsgType.FIELD, "D")
  16.  
  17. // required fields
  18. message.setString(ClOrdID.FIELD, order.getClientOrderId());
  19. message.setChar(HandlInst.FIELD, order.getHandlingInstruction().getValue());
  20. message.setString(Symbol.FIELD, order.getSymbol());
  21. message.setChar(Side.FIELD, order.getSide().getValue());
  22. message.setChar(OrdType.FIELD, order.getOrderType().getValue());
  23. message.setUtcTimeStamp(TransactTime.FIELD, order.getTransactionTime());
  24.  
  25. // required user-defined field (CME)
  26. message.setString(9717, order.getClientOrderId());
  27.  
  28. // market order fields
  29. message.setDouble(OrderQty.FIELD, order.getQuantity());
  30. message.setDouble(Price.FIELD, order.getPrice());
  31.  
  32. // submit the order...
  33. }
  34. }
  35.  

This example is definitely a step in the right direction because most of the "magic" values have been replaced with QuickFIX/J constants. QuickFIX/J goes out of its way to provide standard FIX protocol-specific versions of all messages and fields wrapped in Java objects. These objects are generated when building QuickFIX/J by transforming the QuickFIX/J FIX data dictionary files into Java code via XSLT. In fact, instead of using the constants we should instantiate instances of the field object, which provides an extra level of type-safety. More on this in a bit.

There are a few problems to address in the previous example. First, the message type is still a magic string. Second, we have to know the types of the various fields. For example, we have to know that the ClOrdID is a string value. Lastly, the user-defined CorrelationClOrdID field (tag 9717) is still a magic value. The QuickFIX/J API does not provide classes representing user-defined, so we have to create a type-safe quickfix.Field class to represent user-defined fields. The next example fixes all these problems.

Manually Creating Custom Field Classes

All QuickFIX/J field objects are of type quickfix.Field. There are six direct subclasses of Field:

All standard fields extend from one of the six field classes. For example, quickfix.ClOrdID extends quickfix.StringField. To create a custom field class we simply need to know the type of the field and extend the appropriate class. We know that the CorrelationClOrdID is a string value, so we extend quickfix.StringField

  1. package org.opentradingsolutions.field;
  2.  
  3. import quickfix.StringField;
  4.  
  5. public class CorrelationClOrdID extends StringField {
  6.  
  7. public static final int FIELD = 9717;
  8.  
  9. public CorrelationClOrdID(String value) {
  10. super(FIELD, value);
  11. }
  12. }

Type-Safe Message Generation

Now that we have our custom CorrelationClOrdID field class let's see how we can fix the problems in the previous example:

  1. import quickfix.fix42.NewOrderSingle;
  2. import quickfix.field.ClOrdID;
  3. import quickfix.field.HandlInst;
  4. import quickfix.field.OrdType;
  5. import quickfix.field.OrderQty;
  6. import quickfix.field.Symbol;
  7. import quickfix.field.TransactTime;
  8. import org.opentradingsolutions.field.CorrelationClOrdID;
  9.  
  10. public class BetterSubmitOrder implements SubmitOrder {
  11.  
  12. public void submitOrder(Order order) {
  13.  
  14. // type-safe QuickFIX/J message object
  15. // the message type (MsgType "D") is automatically set
  16. NewOrderSingle message = new NewOrderSingle();
  17.  
  18. // required fields
  19. message.set(new ClOrdID(order.getClientOrderId()));
  20. message.set(new HandlInst(order.getHandlingInstruction().getValue()));
  21. message.set(new Symbol(order.getSymbol()));
  22. message.set(new Side(order.getSide().getValue()));
  23. message.set(new OrdType(order.getOrderType().getValue()));
  24. message.set(new TransactTime(order.getTransactionTime()));
  25.  
  26.  
  27. // this line generates a compiler error because the CorrelationClOrdID is not
  28. // part of the standard list of fields on a FIX 4.2 NewOrderSingle.
  29. // message.set(new new CorrelationClOrdID(order.getClientOrderId()));
  30.  
  31. // required user-defined field (CME)
  32. message.setField(new CorrelationClOrdID(order.getClientOrderId()));
  33.  
  34. // market order fields
  35. message.set(new OrderQty(order.getQuantity()));
  36. message.set(new Price(order.getPrice()));
  37.  
  38. // submit the order...
  39. }
  40. }

The BetterSubmitOrder replaces the generic quickfix.Message with a FIX version-specific quickfix.fix42.NewOrderSingle. This example also uses the message object's set methods. There are set methods for each required, optional, and conditionally required field on each QuickFIX/J message object. Thus, the compiler complains when setting a field that is not part of the standard field list for that message (e.g. the CorrelationClOrdID).

Here is a short list of overloaded set methods:

The Best Way To Generate A Message

  1. import quickfix.fix42.NewOrderSingle;
  2. import quickfix.field.ClOrdID;
  3. import quickfix.field.HandlInst;
  4. import quickfix.field.OrdType;
  5. import quickfix.field.OrderQty;
  6. import quickfix.field.Symbol;
  7. import quickfix.field.TransactTime;
  8. import org.opentradingsolutions.field.CorrelationClOrdID;
  9.  
  10. public class BestSubmitOrder implements SubmitOrder {
  11. public void submitOrder(Order order) {
  12.  
  13. // the constructor includes ALL required fields.
  14. NewOrderSingle message = new NewOrderSingle(
  15. new ClOrdID(order.getClientOrderId()),
  16. new HandlInst(order.getHandlingInstruction().getValue()),
  17. new Symbol(order.getSymbol()),
  18. new Side(order.getSide().getValue()),
  19. new TransactTime(order.getTransactionTime()),
  20. new OrdType(order.getOrderType().getValue()));
  21.  
  22. // required user-defined field (CME)
  23. message.setField(new CorrelationClOrdID(order.getClientOrderId()));
  24.  
  25. // market order fields
  26. message.set(new OrderQty(order.getQuantity()));
  27. message.set(new Price(order.getPrice()));
  28.  
  29. // submit the order...
  30. }
  31. }

All QuickFIX/J message objects provide a default constructor and a constructor that accepts all required fields. This makes it drop-dead simple to quickly know the standard required fields for a particular FIX message. In most cases, the BestSubmitOrder is the direction you want to take when writing your QuickFIX/J application.

But What About... ?

What About Unit Tests?

Some readers may say, "unit tests will catch any problems in my code, so who cares about type-safety". Yes, that is a reasonable question. However, most projects fail to write tests. A combination of type-safety and unit tests goes a long way to ensure your code works as expected.

What About Field Object Allocation?

Some readers may ask, "why go through the trouble of creating instances of field objects? The API accepting constant tag values must be faster than creating an entire object, right?". The current implementation of QuickFIX/J (version 1.0) stores all fields as an instance of a quickfix.Field. Thus QuickFIX/J creates the field object if you don't. Here is an example:

message.setString(ClOrdID.FIELD, order.getClientOrderId());

which translates to:

  1. public void setString(int field, String value) {
  2. setField(new StringField(field, value));
  3. }

Thus you might as well create the object yourself and obtain the extra level of type-safety.

What About Code Generating User-Defined Fields?

Earlier in this article we mentioned that QuickFIX/J generates all message and field classes using the data dictionary XML file. You could modify the data dictionary file and rebuild QuickFIX/J. This might work well if your counterparty requires a lot of user-defined fields and you do not want to hand-code the field subclasses.

In addition to code generation via XSLT, the data dictionary XML file is read at runtime and used to validate incoming messages. Thus there is a huge advantage to creating a custom dictionary file, even if there is only one custom field or message, because QuickFIX/J performs message validation in the session layer keeping invalid messages out of your application.

Summary

QuickFIX/J provides a great foundation for creating FIX messages. Out-of-the-box, QuickFIX/J provides simple wrappers for all standard FIX messages and fields. Working with user-defined fields simply requires extending one of six core field base classes or writing a custom data dictionary file and code generating the classes. Happy Trading!

References

secret