Version 1.9.6
Onix Solutions Java FIX Engine is a simple fully Java compliant tool that will FIX-enable applications written in Java.
The Engine provides the following services:

| 3rd Party JAR | Notes |
|---|---|
| onixs-fix-engine-x.x.x.jar | This jar contains core FIX/FAST functionality. |
| slf4j-api-1.5.11.jar | The SLF4J logging facility facade. |
| logback-classic-0.9.18.jar, logback-core-0.9.18.jar | The logging facility implementation. This can be replaced with any supported implementation. |
| dom4j-1.6.1.jar | XML processing library . |
| commons-io-1.4.jar | Commons IO is a library of utilities to assist with developing IO functionality. |
| joda-time-1.6.jar | Date and time processing library. |
| 3rd Party JAR | Licensor | License Terms | Credit File |
|---|---|---|---|
| commons-io-1.4.jar | Apache | Apache License Version 2.0 | license/commons-io-license.txt |
| dom4j-1.6.1.jar | MetaStuff | Berkeley Software Distribution (BSD) Style License | license/dom4j-license.txt |
| slf4j-api-1.5.11.jar | QOS.ch | Massachusetts Institute of Technology (MIT) X11 License | license/slf4j-license.txt |
| logback-classic-0.9.18.jar, logback-core-0.9.18.jar | QOS.ch | LGPL v2.1 | license/logback-license.txt |
| joda-time-1.6.jar | Joda.org | Apache License Version 2.0 | license/joda-time-license.txt |
All Engine classes have a well formed API and could be easy extended for customer requirements.
The typical way of using the Engine is as follows:
Exception handling is used as a fundamental error-reporting mechanism. In
the event of any errors arising then the biz.onixs.fix.engine.EngineException is
thrown.
To initialize the FIX Engine class library the biz.onixs.fix.engine.Engine.init(..) method
is used. This method must be called before all other methods.
The engine configuration is set during initializtion phase. See Configuration → Engine Initialization for details.
To shutdown the Engine the biz.onixs.fix.engine.Engine.shutdown() method
is used. No other Engine methods must be called after this method.
Example:
import biz.onixs.fix.engine.Engine; public class SimpleEngine { public static void main(String[] args) { try { final Engine engine = Engine.init(); // Session-related logic... engine.shutdown(); } catch (Exception ex) System.out.println("Exception: " + ex); } } }
See also: Configuration → Engine Initialization.
As the FIX protocol evolves its new versions will be released to you to extend the current functionality.
Supported FIX versions are: FIX 4.0, 4.1, 4.2, 4.3, 4.4 and 5.0. The biz.onixs.fix.engine.Version enum
is used to identify them.
Example:
Version v = Version.FIX44;
Each FIX version can be produced by appropriate number too, e.g.:
final Version fixVersion = Version.getByNumber("4.2");
The general format of a FIX message is a stream of <tag>=<value> fields with a field delimiter (<SOH>) between fields in the stream (so-called "tag-value FIX format").
Below is an example of a FIX message:

It is represented with the biz.onixs.fix.engine.Message class.
To create a message the biz.onixs.fix.engine.Message(java.lang.String
type, biz.onixs.fix.engine.Version version) constructor is used.
To parse a message in the raw format the biz.onixs.fix.engine.Message(java.lang.String
rawMessage) constructor is used.
To validate a message the biz.onixs.fix.engine.Message.validate() method
is used. This method checks for the presence of required
fields.
Example:
// New Order - Single (MsgType = D) Message order1 = new Message("D", Version.FIX40); // Validate created message order1.validate(); // Another way String rawMsg = "8=FIX.4.0\u00019=86\u000135=D\u000149=0\u000156=0\u000134=1\u000152=99990909-17:17:17\u0001" + "11=90001008\u000121=1\u000155=IBM\u000154=1\u000138=10\u000140=1\u000159=0\u000110=191\u0001"; Message order2 = new Message(rawMsg); // Validate created message order2.validate();
To set a field value the appropriate biz.onixs.fix.engine.Message.set() method
is used.
To get a field value the biz.onixs.fix.engine.Message.get() method
is used.
Example:
String ClOrdID = order.get(11); execReport.set(17, "Unique identifier of execution message");
To remove a field the biz.onixs.fix.engine.Message.remove(int tag) method
is used.
The Tag class contains the constants for the tag values. This class is defined for each FIX version namespace. The use of these constants makes the source code more readable.
Example:
import biz.onixs.fix.engine.Message; import static biz.onixs.fix.engine.FIX40.Tag; ... // New Order – Single Message order = new Message("D", Version.FIX40); order.set(Tag.ClOrdID, "90001008"); order.set(Tag.Side, "1"); order.set(Tag.TimeInForce, "0");
See also: FIX Repeating Group.
A FIX session is defined as a bi-directional stream of ordered messages between
two parties within a continuous sequence number series. It is represented by
the biz.onixs.fix.engine.Session class.
To create a session object the appropriate constructor is used.
To terminate the session the Session.dispose() method
is used.
A session has one of two possible roles: Acceptor or Initiator.
Acceptor is the receiving party of the FIX session. It listens for the incoming connection on the pre-defined port. The acceptor has responsibility to perform first level authentication and formally declare the connection request "accepted" through transmission of an acknowledgment Logon message.
Initiator establishes the telecommunications link and initiates the session via transmission of the initial Logon message.
To obtain current role the Session.getRole() method is used.
To establish the session as Acceptor the Session.logonAsAcceptor() method
is used.
To establish the session as Initiator the Session.logonAsInitiator() method
is used.
To disconnect the session the Session.logout(...) method
is used.
Example:
import biz.onixs.fix.engine.Message;
import biz.onixs.fix.engine.Session;
import biz.onixs.fix.engine.Version;
...
Session acceptor = new Session("SenderCompID", "TargetCompID", Version.FIX40);
acceptor.logonAsAcceptor();
Session initiator = new Session("TargetCompID", "SenderCompID", Version.FIX40);
// Sends the Logon message and waits for the acknowledgment Logon
initiator.logonAsInitiator("localhost", Engine.getInstance().getListenPort());
// Message exchange and processing ...
// Sends the Logout message and waits for the confirming Logout
initiator.logout();
acceptor.logout();
// Free resources
initiator.dispose();
acceptor.dispose();
See also: Session state, Custom Logon Message, Sequence Numbers.
To send a message to counterparty the Session.send(...) method
is used. As soon as a session is created it is possible to start sending messages
via the session. If the session is not established, the messages will be sent
when the connection is established with the counterparty.
To receive incoming application-level messages it is necessary to implement
the Session.InboundApplicationMessageListener interface
for incoming message event handler and register it by Session.setInboundApplicationMessageListener(Session.InboundApplicationMessageListener
listener).
Example.
package biz.onixs.fix.sample.proguide;
import biz.onixs.fix.engine.Session;
import biz.onixs.fix.engine.Engine;
import biz.onixs.fix.parser.Version;
import biz.onixs.fix.parser.Message;
import biz.onixs.fix.tag.FIX42;
import biz.onixs.fix.tag.Tag;
import biz.onixs.util.Utils;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MessageExchange implements Session.InboundApplicationMessageListener {
private static final String SENDER_COMP_ID = "SenderCompId";
private static final String TARGET_COMP_ID = "TargetCompId";
private static final Version VERSION = Version.FIX42;
private static final String ACCEPTOR_HOST = "localhost";
private static final int ACCEPTOR_PORT = 10000;
private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyyMMdd-HH:mm:ss");
public void onInboundApplicationMessage(Object sender, Session.InboundApplicationMessageArgs args) {
System.out.println("Incoming application-level message: " + args.getMsg());
// processing of the application-level incoming message...
}
private void run() {
final Engine engine = Engine.init(ACCEPTOR_PORT);
final Session acceptor = new Session(SENDER_COMP_ID, TARGET_COMP_ID, VERSION);
acceptor.logonAsAcceptor();
final Session initiator = new Session(TARGET_COMP_ID, SENDER_COMP_ID, VERSION);
initiator.logonAsInitiator(ACCEPTOR_HOST, ACCEPTOR_PORT);
initiator.setInboundApplicationMessageListener(this);
final Message order = new Message("D", VERSION);
order.set(Tag.ClOrdID, "Unique identifier for Order as assigned by the buy-side");
order.set(Tag.HandlInst, "1");
order.set(Tag.Symbol, "Ticker symbol");
order.set(Tag.Side, "1");
order.set(Tag.TransactTime, FORMATTER.format(new Date()));
order.set(FIX42.Tag.OrdType, "1");
order.validate();
acceptor.send(order);
Utils.waitForEnterToTerminateApp();
acceptor.logout();
acceptor.dispose();
initiator.dispose();
engine.shutdown();
}
public static void main(String[] args) {
final MessageExchange messageExchange = new MessageExchange();
messageExchange.run();
}
}
This example can be found in samples/ProGuide, class biz.onixs.fix.sample.proguide.MessageExchange.java
All FIX messages are identified by a unique sequence number (the MsgSeqNum field).
Sequence numbers are initialized at the start of each FIX session starting at 1 (one) and increment throughout the session. Each session establishes an independent incoming and outgoing sequence series.
A single FIX session can exist across multiple sequential (not concurrent) physical connections. Parties can connect and disconnect multiple times while maintaining a single FIX session. In other words, FIX Session is comprised of one or more FIX Connections.
Resetting the inbound and outbound sequence numbers back to 1, for whatever reason, constitutes the beginning of a new FIX session.
Monitoring sequence numbers enables parties to gracefully synchronize applications when reconnecting during a FIX session.
To disconnect the FIX Connection while maintaining a single FIX Session the Session.logout(...) method
is used. It is possible to continue the session later using the Session.logonAsAcceptor() or Session.logonAsInitiator(...) methods
again.
To terminate a FIX Session the Session.dispose() method
is used.
The Engine automatically synchronizes sequence numbers when reconnecting during a FIX session on the base of the information previously stored in log files.

See also: Sequence Numbers Management.
The engine is configured during initialization phase. The initialization method is overloaded. Thus there are multiple ways to pass the configuration.
The engine settings are taken from the properties.
PropertyBasedSettings settings = new PropertyBasedSettings("engine.properties");
Engine engine = Engine.init(settings);
The properties file is loaded as described in the Unified Resource Loading.
The configuration file example:
Dialect=LavaDialect.xml Log.InboundMessages=true Validate.NumberOfRepeatingGroupInstances=false Validate.RequiredFields=true Validate.UnknownFields=true
The engine settings are available as the class properties.
EngineSettings settings = new EngineSettings(); Engine engine = Engine.init(settings);
The settings can be changed before initialization method call.
The pre-defined license file name is "OnixS.lic". The license file is loaded during engine initialization as described in the Unified Resource Loading.
It means that no additional steps required if the license file is in:
The engine catches it automatically.
The default license file name can be changed using "LicenseFile" configuration parameter.
By default, the FIX engine uses file system directory specified by the "Log.Directory" parameter for storing log data. The FIX Engine default log file is "FixEngine.log".
By default, the FIX engine uses file system directory specified by the "Log.Directory" parameter for storing incoming and outgoing messages, session’s state data.
For each FIX session the following files are created:
Where:
When the biz.onixs.fix.engine.Session.logonAsAcceptor() object
is created anew after the Engine's restart, FIX Session's state (the sequence
numbers of last received and sent messages, previously sent messages, etc)
is restored from these files.
To start a FIX session as a new one (so called "clean start"), it is necessary to remove the log files from the previous runs.
Connecting parties must bi-laterally agree as to when sessions are to be started/stopped and log files are backed up based upon individual system and time zone requirements.
When the FIX session is finished, the log files are not needed anymore. They can be backed up and later a new FIX session with the same SenderCompID and TargetCompID will start sequence numbers from 1. The usual practice is to backup the log files at the end of each business day (so called "End Of Day procedure") to start the sequence numbers from 1 at the beginning of the next day.
See also: Log.Directory, Log.InboundMessages, Sequence Numbers.
| Property | Description | Type | Default Value |
|---|---|---|---|
| LicenseFile | Specifies the name of the license file resource. | string | OnixS.lic |
| Dialect | Specifies the location of one or several files with the FIX Dialects definition. The file names are separated with the '|' character. The dialect files are loaded during engine initialization as described in the Unified Resource Loading. | string | <empty> |
| ListenPort | FIX Engine listens on this port(s) for incoming connections. If it is set to '0' then only session-initiators can be created. If it is set to '-1' then the telecommunication level is disabled and only message parsing/assembling can be used. Use comma delimited list if more than one listen port is required. |
string | 0 |
| Log.Directory | Inbound and outbound messages, session's state data and the FIX Engine log file (FixEngine.log) are stored in this directory. | string | FixEngineStorage |
| Log.InboundMessages | Option to log inbound messages. | boolean | true |
| Validate.NumberOfRepeatingGroupInstances | Option to validate that the declared number of repeating group instances is equal to the actual one. For in inbound and outbound messages | boolean | false |
| Validate.RequiredFields | Option to validate the presence of required fields in inbound and outbound messages. | boolean | false |
| Validate.UnknownFields | Option to validate the presence of unknown fields in inbound and outbound messages. | boolean | false |
| ConnectionRetries.Interval | The initial time interval between the attempts to restore the telecommunication link (in milliseconds). | integer | 90000 |
| ConnectionRetries.Number | Number of attempts to restore the telecommunication link. The range is [0..MAX_INT]. | integer | 3 |
| Connection.TcpNoDelay | Option to improve latency at the expense of message throughput. | boolean | true |
| Connection.TcpSendBufferSize | The size of the TCP buffer allocated to FIX connection for sending data, in bytes. | integer | 65535 |
| Connection.TcpReceiveBufferSize | The size of the TCP buffer allocated to FIX connection for receiving data, in bytes. | integer | 65535 |
| Connection.OutputQueueSize | The size of the internal output queue allocated to FIX connection, in messages. | integer | 1000 |
The settings names (keys) are case-sensitive.
By default, any external resource is looked for at the following places and in the following order (if other is not set explicitely):
If it can't be found at the 1st location then the 2nd one is checked, etc.
For example, you can put a dialect file to the classpath or current directory and it will be located by engine.
It is permissible for fields to be repeated in the same message within a repeating
group (e.g. "215=2<SOH>216=2<SOH>217=Dest_1<SOH>216=4<SOH>217=Dest_2<SOH>" represents
a repeating group with two repeating instances "delimited" by tag 216 (first
field in the repeating group.).
The NoRoutingIDs<215> field specifies the number of repeating group instances (2 in this case). This is so called "NumberOfInstances field". The NumberOfInstances field must immediately precede the repeating group contents (repeating group instances).

The FIX repeating group is represented with the biz.onixs.fix.engine.Group class.
To get the biz.onixs.fix.engine.Group object that represents
the existing repeating group of the message the biz.onixs.fix.engine.Message.getGroup(int
numberOfInstancesTag) method is used.
To create a new repeating group or modify the number of instances in the existing
one the biz.onixs.fix.engine.Message.setGroup(int numberOfInstancesTag,
int numberOfInstances) method is used.
To remove a repeating group method biz.onixs.fix.engine.Message.remove(int
numberOfInstancesTag) is used.
The Group class works with fields and embedded repeating groups
in the same manner as the biz.onixs.fix.engine.Message class,
but each method has an additional parameter that defines the index of the repeating
group instance (starting from 0).
Example:
Message request = new Message("V", Version.FIX42);
request.set(Tag.MDReqID, "ABSD");
request.set(Tag.SubscriptionRequestType, 1);
request.set(Tag.MarketDepth, 1);
request.set(Tag.MDUpdateType, 1);
request.set(Tag.AggregatedBook, "N");
// create a repeating group NoMDEntryTypes with two instances
Group groupMDEntryTypes = request.setGroup(Tag.NoMDEntryTypes, 2);
// first instance
groupMDEntryTypes.set(Tag.MDEntryType, 0, "EntryType_1");
// second instance
groupMDEntryTypes.set(Tag.MDEntryType, 1, "EntryType_2");
// create a repeating group NoRelatedSym with two instances
Group groupRelatedSym = request.setGroup(Tag.NoRelatedSym, 2);
// first instance
groupRelatedSym.set(Tag.Symbol, 0, "EURUSD_0");
// second instance
groupRelatedSym.set(Tag.Symbol, 1, "EURUSD_1");
request.validate();
System.out.println(request.toString());
Sometimes there is a
requirement
to accept an incoming FIX session "on the fly", without the prior creation of the Session object. This happens when an unknown session-initiator is trying to connect to the Engine. For this reason, the Engine exposes an ability to accept such a connection by creating a temporary session-acceptor. To take advantage of this feature it is necessary to subscribe to the UnknownIncomingConnection event.
The automatically created Session object that corresponds to the incoming FIX connection is available via the Session property of the Engine.UnknownIncomingConnectionEventArgs object passed to your event handler.
To accept the incoming connection, set the Accept property of the Engine.UnknownIncomingConnectionEventArgs object to true. Otherwise the incoming connection will be rejected and the created Session object will be disposed of by the Engine.
Example:
public class UnknownIncomingConnectionSample implements Engine.UnknownIncomingConnectionEventListener {
private void run() {
// ...
engine.addUnknownIncomingConnectionEventListener(this);
// ...
}
public void onUnknownIncomingConnection(Object sender, Engine.UnknownIncomingConnectionEventArgs e) {
System.out.println("Accepting unknown incoming session: " + e.getCreatedSession());
// Don't forget to update event, otherwise connection will be rejected!
e.setAccept(true);
}
}
To obtain the current session state the biz.onixs.fix.engine.Session.getState() method
is used.
The states of the FIX session are listed below.
| State | Role: Acceptor | Role: Initiator |
|---|---|---|
| DISCONNECTED | The session is disconnected. |
|
| AWAIT_LOGON | The session is waiting for the initial Logon message. |
N/A |
| AWAIT_CONFIRMING_LOGON | N/A |
The initial Logon message was sent and the session is waiting for the acknowledgment Logon message. |
| ESTABLISHED | The session is fully established (after the successful Logon exchange). |
|
| RECONNECTING | Session-initiator is trying to restore the telecommunication link. | N/A |
| AWAIT_CONFIRMING_LOGOUT | The initial Logout message was sent and the session
is waiting for the acknowledgment Logout message. |
|
To be notified about the changes in the session state implement biz.onixs.fix.engine.Session.StateChangeListener and
the register it as event handler by the biz.onixs.fix.engine.Session.setStateChangeListener(biz.onixs.fix.engine.Session.StateChangeListener
listener).
Example:
import biz.onixs.fix.engine.Session; import biz.onixs.fix.engine.Version; class SessionListener implements Session.StateChangeListener { private static final String SENDER_COMP_ID = "AcceptorAndInitiator_SND"; private static final String TARGET_COMP_ID = "AcceptorAndInitiator_TRG"; private static final Version VERSION = Version.FIX42; public void onStateChange(Object sender, Session.StateChangeArgs e) { System.out.println("New session state: " + e.getNewState()); // processing of the application-level incoming message... } public static void main(String[] args) { try { final Engine engine = Engine.init(); Session sn = new Session(SENDER_COMP_ID, TARGET_COMP_ID, VERSION); SessionListener listener = new SessionListener(); sn.setStateChangeListener(listener); // ... } catch (Exception ex) System.out.println("Exception: " + ex); } } }
The events of the biz.onixs.fix.engine.Session class are
listed below.
| Event Listener | Event Description |
|---|---|
biz.onixs.fix.engine.Session.StateChangeListener |
Session state is changed. |
biz.onixs.fix.engine.Session.ErrorListener |
Error condition is detected. |
biz.onixs.fix.engine.Session.InboundApplicationMessageListener |
Application-level message is received from the counterparty. |
biz.onixs.fix.engine.Session.InboundSessionMessageListener |
Session-level message is received from the counterparty. |
biz.onixs.fix.engine.Session.OutboundApplicationMessageListener |
Application-level message will be sent to the counterparty. |
biz.onixs.fix.engine.Session.OutboundSessionMessageListener |
Session-level message will be sent to the counterparty. |
biz.onixs.fix.engine.Session.WarningListener |
Warning condition is detected. |
biz.onixs.fix.engine.Session.MessageResendingListener |
Application-level message resending request. |
Warning. It is critical to avoid time-consuming tasks inside event handlers.
Example:
import biz.onixs.fix.engine.Session;
import biz.onixs.fix.engine.Engine;
import biz.onixs.fix.parser.Version;
public class SessionListener implements Session.StateChangeListener, Session.InboundSessionMessageListener,
Session.InboundApplicationMessageListener, Session.OutboundSessionMessageListener,
Session.MessageResendingListener, Session.OutboundApplicationMessageListener,
Session.WarningListener, Session.ErrorListener {
private static final String SENDER_COMP_ID = "AcceptorAndInitiator_SND";
private static final String TARGET_COMP_ID = "AcceptorAndInitiator_TRG";
private static final Version VERSION = Version.FIX42;
public void onStateChange(Object sender, Session.StateChangeArgs e) {
System.out.println("New session state: " + e.getNewState());
}
public void onInboundApplicationMessage(Object sender, Session.InboundApplicationMessageArgs e) {
System.out.println("Incoming application-level message: " + e.getMsg());
}
public void onInboundSessionMessage(Object sender, Session.InboundSessionMessageArgs e) {
System.out.println("Incoming session-level message: " + e.getMsg());
}
public void onOutboundApplicationMessage(Object sender, Session.OutboundApplicationMessageArgs e) {
System.out.println("Outgoing application-level message: " + e.getMsg());
}
public void onOutboundSessionMessage(Object sender, Session.OutboundSessionMessageArgs e) {
System.out.println("Outbound session-level message: " + e.getMsg());
}
public void onWarning(Object sender, Session.WarningArgs args) {
System.out.println("Session warning: " + args.getReason());
}
public void onError(Object sender, Session.ErrorArgs args) {
System.out.println("Session error: " + args.getReason());
}
public boolean onMessageResending(Object sender, Session.MessageResendingArgs args) {
return false;
}
public static void main(String[] args) {
try {
final Engine engine = Engine.init();
final Session sn = new Session(SENDER_COMP_ID, TARGET_COMP_ID, VERSION);
final SessionListener listener = new SessionListener();
sn.setStateChangeListener(listener);
sn.setInboundSessionMessageListener(listener);
sn.setInboundApplicationMessageListener(listener);
sn.setOutboundSessionMessageListener(listener);
sn.setOutboundApplicationMessageListener(listener);
sn.setWarningListener(listener);
sn.setErrorListener(listener);
sn.setMessageResendingListener(listener);
// ...
engine.shutdown();
} catch (Exception e) {
System.out.println("Exception: " + e);
}
}
}
Sometime there is need to set additional fields (e.g. Username<553>,
Password<554>) in the initiation Logon message. In this
case the biz.onixs.fix.engine.Session.logonAsInitiator(java.lang.String
host, int port, int heartBtInt, biz.onixs.fix.engine.Message customLogonMsg) method
must be used.
Example:
Session acceptor = new Session("CustomLogonMessage_SND", "CustomLogonMessage_TRG", Version.FIX43);
acceptor.LogonAsAcceptor();
Session initiator = new Session("CustomLogonMessage_TRG", "CustomLogonMessage_SND", Version.FIX43);
Message customLogonMsg = new Message("A", Version.FIX43);
customLogonMsg.set(Tag.Username, "USER_NAME");
customLogonMsg.set(Tag.Password, "PASSWORD");
initiator.LogonAsInitiator("localhost", Engine.getInstance().getListenPort(), 30, customLogonMsg);
// message exchange and processing ...
acceptor.logout();
initiator.logout();
acceptor.dispose();
initiator.dispose();
Check samples/BuySide, the CredentialBuySide example.
The expected sequence number of the next incoming message can be:
Session.getInSeqNum(...);Session.setInSeqNum(...), but only when session is not connected.The sequence number of the next outgoing message can be:
Session.getOutSeqNum(...);Session.setOutSeqNum(...), but only when session is not connected.Some implementations of FIX protocol (FIX Dialects) expect that the FIX Session coincides with FIX Connection, in other words that the sequence numbers are reset back to 1 after the Logout messages exchange. To interact with such FIX implementations, the keepSequenceNumbersAfterLogout parameter of Session's constructor should be set to false.
ResetSeqNumFlag (141) field in the Logon (A) message indicates that the both sides of the FIX session should reset sequence numbers.
To send a Logon message with this field during FIX connection establishment, use the setResetSeqNumFlag parameter of the Session.logonAsInitiator(String host, int port, boolean setResetSeqNumFlag) method.
Next time when the session object is created incoming and outgoing sequence numbers:
setResetSeqNumFlag = true in the Session.logonAsInitiator(...);setResetSeqNumFlag = false in the Session.logonAsInitiator(...).See also: Sequence Numbers.
It is common for firms to implement slightly different interpretations of the FIX protocol (FIX dialects).
Within the FIX protocol such deviations from the FIX specification must be described in the FIX Engine, to ensure that the parsing or creation of the corresponding FIX messages are correct.
The Dialect configuration setting specifies
one or several dialect definition files in XML format. The dialect definition file must conform
to the dialect XML schema: dialects-2_4.xsd.
FIX dialect can be set on:
Please read details below.
The engine level dialect is defined by <FIX> element with no id attribute specified. The dialect defined for the engine level is set implicitly for all engine sessions.
<?xml version="1.0" encoding="utf-8"?>
<Dialect xmlns="http://onixs.biz/fix/dialects"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://onixs.biz/fix/dialects http://onixs.biz/fix/dialects/dialects-2_4.xsd">
<FIX version="4.2">
<Message type="N">
<Group numberOfInstancesTag="73">
<Field tag="37"/>
</Group>
</Message>
</FIX>
</Dialect>
In this example the dialect is set for all FIX 4.2 sessions. I.e. it changes the base FIX version definitions in the engine.
You need no additional steps to start using this dialect from your code.
Session session = new Session("SenderCompID","TargetCompID", Version.FIX42);
...
Message message = new Message("D", Version.FIX42);
session.send(message);
The session level dialect is defined by <FIX> element with id attribute specified. The dialect defined for the session level needs to be set explicitly for the selected sessions.
<?xml version="1.0" encoding="utf-8"?>
<Dialect xmlns="http://onixs.biz/fix/dialects"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://onixs.biz/fix/dialects http://onixs.biz/fix/dialects/dialects-2_4.xsd">
<FIX version="4.2" id="MyFIX">
<Message type="N">
<Group numberOfInstancesTag="73">
<Field tag="37"/>
</Group>
</Message>
</FIX>
</Dialect>
In this example the dialect is defined over base FIX 4.2 version definition and has specified id. I.e. it doesn't change the base FIX version definitions in the engine.
Using FIX dialect in the code is easy.
Version version = Version.getById("MyFIX");
Session session = new Session("SenderCompID","TargetCompID", version);
...
Message message = new Message("D", version);
session.send(message);
To add a new user-defined field to a FIX Message add the corresponding <Field> entity to the FIX Dialect description file.
<?xml version="1.0" encoding="utf-8"?>
<Dialect xmlns="http://onixs.biz/fix/dialects"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://onixs.biz/fix/dialects http://onixs.biz/fix/dialects/dialects-2_4.xsd"> <FIX version="4.0"> <Message type="D"> <!-- Does not belong to Standard FIX 4.0 --> <Field tag="526" name="SecondaryClOrdID"/> </Message> </FIX> </Dialect>
To add a new user-defined repeating group to a FIX Message add the corresponding <Group> entity to the FIX Dialect description file.
<?xml version="1.0" encoding="utf-8"?>
<Dialect xmlns="http://onixs.biz/fix/dialects"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://onixs.biz/fix/dialects http://onixs.biz/fix/dialects/dialects-2_4.xsd">
<FIX version="4.0">
<Message type="D">
<!-- Number of repeating groups for pre-trade allocation, does not belong to Standard FIX 4.0 -->
<Group numberOfInstancesTag="78" name="NoAllocs">
<!-- Does not belong to Standard FIX 4.0 -->
<Field tag="79" name="AllocAccount"/>
<!-- Does not belong to Standard FIX 4.0 -->
<Field tag="661" name="AllocAcctIDSource"/>
<!-- Does not belong to Standard FIX 4.0 -->
<Field tag="736" name="AllocSettlCurrency"/>
<!-- Other group fields -->
</Group>
</Message>
</FIX>
</Dialect>
To make a field, which is required according to the FIX Protocol specification, optional, and visa-versa, add the corresponding <Field> entity to the FIX Dialect description and set the isRequired attribute accordingly.
<?xml version="1.0" encoding="utf-8"?>
<Dialect xmlns="http://onixs.biz/fix/dialects"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://onixs.biz/fix/dialects http://onixs.biz/fix/dialects/dialects-2_4.xsd">
<FIX version="4.0">
<Message type="D">
<!-- Required in Standard FIX 4.0, but optional in this FIX dialect -->
<Field tag="21" isRequired="false" name="HandlInst"/>
<!-- Optional in Standard FIX 4.0, but required in this FIX dialect -->
<Field tag="109" isRequired="true" name="ClientID"/>
</Message>
</FIX>
</Dialect>
To define a user-defined message add the corresponding <Message> entity to the FIX Dialect description.
<?xml version="1.0" encoding="utf-8"?>
<Dialect xmlns="http://onixs.biz/fix/dialects"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://onixs.biz/fix/dialects http://onixs.biz/fix/dialects/dialects-2_4.xsd">
<FIX version="4.0">
<Message type="UserDefinedMessage_1">
<Field tag="100"/>
<Field tag="101"/>
</Message>
</FIX>
</Dialect>
Such a user-defined message can be used exactly the same way as the standard FIX Message:
Message userDefinedMsg = new Message(Version.FIX40, "UserDefinedMessage_1");
userDefinedMsg.set(100, "Field 100");
userDefinedMsg.set(101, "Field 101");
userDefinedMsg.validate();
System.out.println("User defined message: " + userDefinedMsg);
Check samples/buyside and samples/sellside for paired live applications with dialect support.
See also: Configuration → Settings.
The SSL (Secure Sockets Layer) support helps to make FIX communication secure.
The SSL support is implemented using Sun's java security / JSSE (Java Secure Socket Extension) implementation. Learn more here about java security and JSSE.
The SSL configuration procedure is slightly different for FIX acceptor and initiator sessions.
The acceptor SSL configuration is performed on the engine level via the following method.
Engine.setSSLContext(sslContext); ... Engine.init(...);
Parameters:
sslContext — SSL context. Make sure that you configure SSL before doing engine init.
The initiator SSL configuration is performed on the session level via the following method.
Session session = new Session("SenderCompID", "TargetCompID", fixVersion);
...
session.setSSLContext(sslContext);
...
session.logonAsInitiator(...);
Parameters:
sslContext — SSL conext.Make sure that you configure SSL before doing session logon.
One of the methods to create SSL context follows.
SSLContext sslContext = SSLContextFactory.getInstance(keyStoreName, trustStoreName, keyPassword);
Parameters:
keyStoreName — key store resource name;trustStoreName — trust store resource name; can be set to null if you don't want to validate counterparty's certificate;keyPassword — key pair password used during key pair generation.The key and trust stores are loaded as described in the Unified Resource Loading.
To perform key and certificate management the keytool can be used. This tool is a part of JDK package
and the complete documentation can be found in the JDK documentation, section "JDK Tools and Utilities".
Below you can find the simplified pre-steps to do in order to organize secure communication between two parties.
Generate the key pair for the "SellSide":
keytool -genkey -keyalg RSA -dname "cn=SellSide, ou=FixEngine, o=OnixS, c=US" -alias sellside -keypass keypass1 -keystore C:\sellside.keystore.bin -validity 360
Generate the key pair for the "BuySide":
keytool -genkey -keyalg RSA -dname "cn=BuySide, ou=FixEngine, o=OnixS, c=US" -alias buyside -keypass keypass2 -keystore C:\buyside.keystore.bin -validity 360
Export the certificate of "SellSide":
keytool -export -alias sellside -file sellside.cer -keystore C:\sellside.keystore.bin
Export the certificate of "BuySide":
keytool -export -alias buyside -file buyside.cer -keystore C:\buyside.keystore.bin
Import the certificate of "BuySide" into the "SellSide" trust store:
keytool -import -alias buyside -file buyside.cer -keystore C:\sellside.truststore.bin
Import the certificate of "SellSide" into the "BuySide" trust store:
keytool -import -alias sellside -file sellside.cer -keystore C:\buyside.truststore.bin
As a result we have two pairs of key store and trust store for each party to establish secure communication:
This is what was used for samples.
Check samples/buyside and samples/sellside for paired live applications with SSL support.
Business processes may dictate that you need to customize inbound application message objects. For instance the addition of calculated values such as option greeks, or values which are not transmitted via the broker nor exchange with are required by trading systems. You may wish to avoid creating an additional java object for every inbound message. In this case you can create your message factory. This is a custom message factory can be set on a per session basis.
Firstly, create your FIX message class extending standard biz.onixs.fix.engine.Message and adding new logic.
public class MyMessage extends Message {
// my additional FIX message logic
}
Secondly, create your message factory via implementing biz.onixs.fix.engine.MessageFactory. This message factory will be used to create inbound application messages objects.
public class MyMessageFactory implements MessageFactory {
public Message createMessage() {
// my message creation
return new MyMessage();
}
}
Finally, alpply your message factory to specific FIX session.
Session acceptor = new Session(...); ... acceptor.setInboundApplicationMessageFactory(new MyMessageFactory());
Thus inbound application level messages within this session are now created using your custom message factory.
There is an option to skip saving of some inbound FIX messages to session storage. For instance, for a performance reason.
This can be configured on a per-session basis:
session.setInboundMessageLogFilter(messageFilter);
The messageFilter is the implementation of biz.onixs.fix.filter.MessageFilter interface.
For instance, the TypeMessageFilter implementation is used to filter specified message types:
MessageFilter messageFilter = new TypeMessageFilter("W X");
session.setInboundMessageLogFilter(messageFilter);
The space-delimited list of message types to filter is specified.
When the Resend Request (2) message is received from the counterparty (e.g. due to a sequence number mismatch), MessageResending event is raised if an application has previously subscribed to this event. Otherwise, the SequenceReset-GapFill (4) message will be sent instead of the requested message.
If the sent application-level message needs to be resent to the counterparty then the return value of the MessageResending event listener should be set to true while handling the event. Otherwise the SequenceReset-GapFill (4) message will be sent instead (e.g. in case of an aged order).
The message that is about to be resent is available via Msg property of Session.MessageResendingArgs parameter.
Example.
public class MessageResendingListenerSample implements Session.MessageResendingListener {
private void run() {
// ...
final Session session = new Session("SenderCompID", "TargetCompID", Version.FIX50);
session.setMessageResendingListener(this);
// ...
}
public boolean onMessageResending(Object sender, Session.MessageResendingArgs args) {
System.out.println("Message is about to be resent to the counterpart: " + args.getMsg());
// Return false if it's necessary to skip this message (GapFill will be sent).
return false;
}
// ...
}
Memory based session storage could be used to maintain a high-performance FIX session when persisting of session state and messages in the file system is not required.
To create such a session storageType parameter of Session constructor should be set to SessionStorageType.MemoryBasedStorage.
boolean keepSequenceNumbersAfterLogout = false;
Session session = new Session("SenderCompID", "TargetCompID", Version.FIX42, keepSequenceNumbersAfterLogout, SessionStorageType.MemoryBasedStorage);
For the security reasons the values of the following fields can be scrambled in the session storage files:
In order to achieve this on the session level the following option can be used:
session.setScramblePassword(true);
In order to achieve this on the engine level the following option can be used:
Engine engine = Engine.getInstance(); engine.getSessionStorageRepositoryManager().get(SessionStorageType.FileBasedStorage).setScramblePassword(true);
In real life Sessions FIX Connections occur at regular intervals. A lot of trading systems have public schedules which declare time frames for trading. Session class exposes members for FIX Connections basic handling. It also provides users with automatic reconnection facility in case of connection failure. However, there is no way in Session functionality to maintain Connections on systematic basis.
To satisfy the needs of real life trading schedules, the OnixS Java FIX Engine offers the Sessions Scheduler. This service will automatically connect certain FIX sessions to the counterpart at the beginning of the trading day as well as disconnect at the end of a day. It also possible to keep a FIX Session connected for an entire trading week and disconnect it at the end of last trading day.
The Scheduler is a workhorse class of the Sessions Scheduler component. This class exposes a simple but comprehensive API to handle connections by schedules of any complexity.
The register(Session, SessionSchedule, SessionConnectionSettings) method schedules a session for automatic logon and logout according to the specified session time which can be delivered to the Scheduler as an instance of appropriate class or as a name of predefined preset. The parameter of type SessionConnectionSettings specifies the role of Session (either Acceptor or Initiator) and primary connection parameters like host and port which the Session will use to establish the FIX Connection.
If a Session is being registered at the time noted by schedule, the the scheduler will connect the Session immediately.The unregister(Session) method removes given session from the scheduling services.
The unregister(Session) doesn't disconnect active session from trading system. Therefore, if session was already connected by scheduler, it remains connected after unregistering.
The Scheduler exposes Error event to get notified about errors in session scheduling.
The Warning event is exposed by the Scheduler to provide its users with more information about scheduling flow. This kind of information usually related with non-critical errors which occur while scheduling a session.
The Session Scheduler exposes SessionSchedule class to define the interval of time during which session must be logged on (active). It also provides the facility to automatically reset message sequence numbers as is commonly required by trading systems and venues.
The SessionSchedule constructor initializes the session schedule for all supported cases based on the given parameters.
The first two parameters (firstDay and lastDay) define activity week. During these days the session will always be connected at logon time and disconnected at logout time if specified session duration equals to a single day. If the session must continue for entire week, then the scheduler will connect session at logon time on the day specified by the firstDay parameter and disconnected at logout time on the day specified by lastDay parameter.
The logonTime and logoutTime parameters respectively define time of logon and logout for the session for each activity day if session duration is a single day. If the session must continue for the entire week, then logonTime parameter value specifies the time for logon to be performed on the first day of activity week and logoutTime parameter value defines the time of logout performed on the last day of the activity week.
The sessionDuration parameter defines whether session must continue for the entire activity week (specified by firstDay and lastDay parameters) or that the activity time frame is limited to a single day (24 hours). In particular, if the parameter value equals to Day then logon and logout occur on the same day (logout may occur on next day if value of logoutTime parameter is less than value of logonTime parameter).
Final seqNumberResetPolicy parameter specifies whether the message sequence numbers must be reset and on which basis (daily or weekly).
Check samples/Scheduler, the ProgramScheduler example.
To simplify development, the Session Scheduler provides an ability to define session schedules and connecting settings in configuration files for later referencing in source code.
Once presets are defined in the file, the session scheduler can use them during the instance initialization stage (Scheduler(String) constructor available for these purposes). Afterwards, both schedules and connection settings can be referenced in source code using the string identifiers. The Scheduler exposes Register(Session, String, String) method to schedule a session with parameters described in a configuration file.
The configuration file has XML-based format. The appropriate XML schema is available here.
Check samples/Scheduler, the FileScheduler example.
When Accepting an incoming FIX connection additional authentication checks may be required. The typical checks are Logon username/password and source IP address. Depending on the result of the logon verification check the decision can be made whether to Accept the FIX connection or reject and close the connection. This is typically performed at the logon stage.
In order to achieve this you should subscribe to the inbound session messages and add the required check logic. If the check fails and the FIX connection needs to be rejected (closed) then an exception can be thrown from the inbound session message listener.
In the following example the password authentication check is demonstrated.
public class LogonPasswordVerification implements Session.InboundSessionMessageListener {
private void run() {
// ...
session.setInboundSessionMessageListener(this);
// ...
}
public void onInboundSessionMessage(Object sender, Session.InboundSessionMessageArgs args) {
final Message message = args.getMsg();
if (message.getType().equals(FIX43.MsgType.Logon)) {
// ...
if (! "ExpectedPassword".equals(message.get(FIX43.Tag.Password))) {
throw new RuntimeException("Password is incorrect");
}
// ...
}
}
}
The text from the exception goes to the FIX logout message text field (Text<58>).
Check samples/BuySide/Credential and samples/SellSide/Credential examples pair.
FAST is a binary encoding method for message oriented data streams. FAST is an acronym for FIX Adapted for STreaming. The original purpose of FAST was optimization of FIX messages.
In order to decode FAST data to FIX message the following 4 steps are required:
The FIX engine must be initialized as described in the following section. The appropriate FIX dialect must be configured during this step if necessary as described here.
To load FAST templates from an XML source the following code sequence can be used.
XmlTemplateLoader templateLoader = new DomXmlTemplateLoader();
InputStream is = new FileInputStream("templates.xml");
TemplateLibrary templateLibrary = templateLoader.load(is);
Create Decoder instance first.
Decoder decoder = new Decoder(templateLibrary, FastVersion.FAST_1_1, Version.FIX50);
Decode FAST stream chunks then.
Message fixMessage = decoder.decode(data);
The FIX engine must be shutdown as described in the following section.
FAST encoder and decoder use logging approach slightly different from the FIX engine. The SLF4J (Simple Logging Facade for Java) is used. The SLF4J detects and uses the concrete logging implementation configured by user. By default, the Logback logging implementation is recommended.
The Logback (or any other logging implementation) must be configured at the beginning of the application.
The examples of Logback configurations can be found in the FAST application examples.
The details of Logback configuration can be found here.
See also: Classpath Libraries Selection.
Check samples/fast for FAST related examples.
A lot of examples can be found in the samples directory. The examples are categorized by sub-directories.
In most cases the example sub-directory contains Readme.html file with the important information - configuration, startup, etc.
The examples are ready to be opened in the Eclipse Java IDE, the workspace is pre-created for your convinience. However, the additional configuraion steps are required:
You can use Session InSeqNum and OutSeqNum properties to set the start sequence numbers before establishing the session.
Yes, you can have multiple session objects per engine instance.
Yes, all incoming events related to a particular session are sent from the same thread.
It is important to avoid time-consuming tasks inside session event handlers. Thus, you should fork a thread and listener can't be heavyweight.
The fields that start with the "Encoding" prefix should be used.
For example:
During message creation the following approach can be used:
final String text = "string using local charset"; final byte[] encodedText = text.getBytes(); order.set(Tag.EncodedTextLen, encodedText.length); order.set(Tag.EncodedText, encodedText);
During message processing the following approach can be used:
final byte[] encodedText = order.getBytes(Tag.EncodedText); final String charset = "cp1251"; final String text = new String(encodedText, charset);
By default the FIX Engine automatically sets the SendingTime (52) field value to the current date and time using GMT+0 time zone.
This can be overridden in the session listener.
session.setOutboundApplicationMessageListener(new Session.OutboundApplicationMessageListener() {
public void onOutboundApplicationMessage(Object sender, Session.OutboundApplicationMessageArgs args) {
final Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT+5"));
final String sendingTime = String.format("%1$tY%1$tM%1$td-%1$tH:%1$tm:%1$tS.%1$tL", calendar);
final Message message = args.getMsg();
message.set(Tag.SendingTime, sendingTime);
}
});
Session-acceptor is the receiving party of the FIX session. It listens for the incoming connection on the pre-defined port. The acceptor has responsibility to perform first level authentication and formally declare the connection request "accepted" through transmission of an acknowledgment Logon message.
Fields which are required based on the presence or value of other fields.
The non-printing, ASCII "SOH" (\u0001, hex: 0x01, referred to in this document as <SOH>), is used for field termination.
Integer message sequence number, the tag number is 34.
The Financial Information Exchange (FIX) Protocol is a message standard developed to facilitate the electronic exchange of information related to securities transactions. It is intended for use between trading partners wishing to automate communications.
It is comprised of three parts: logon, message exchange, and logout.
This is a custom, slightly different interpretation of FIX protocol.
It is comprised of one or more FIX Connections, meaning that a FIX Session spans multiple logins.
Session-Initiator establishes the telecommunications link and initiates the session via transmission of the initial Logon message.
Each message within the FIX protocol is comprised of required, optional and conditionally required fields (fields which are required based on the presence or value of other fields). Systems should be designed to operate when only the required and conditionally required fields are present.
Fields in a FIX message that are not expected in accordance with the FIX protocol or its dialect.
Assigned value used to identify firm sending message, the tag number is 49.
Assigned value used to identify receiving firm, the tag number is 56.
These fields are intended to be implemented between consenting trading partners and should be used with caution to avoid conflicts, which will arise as multiple parties begin implementation of the protocol. The tag numbers 5000 to 9999 have been reserved for them. These tags can be registered/reserved via the FIX website.
Messages those format is privately defined between the sender and receiver. A "U" as the first character in the MsgType field (i.e. U1, U2, etc) indicates such messages.
The binary encoding method for message oriented data streams. FAST is an acronym for FIX Adapted for STreaming.