Onix Solutions Logo

Java FIX Engine — Programmer's Guide

Version 1.9.6

Introduction

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:

High-level Architecture of FIX Engine

System Requirements

Distribution Package

3rd Party Libraries

Application Classpath

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.

Credits

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

Classpath Libraries Selection

Getting Started

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:

  1. Initialize the Engine.
  2. Create the Session object.
  3. Establish the FIX session as Initiator or Acceptor.
  4. Send and receive application-level FIX messages.
  5. Disconnect the session.
  6. Shutdown the Engine.

Error Reporting

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.

Engine

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.

FIX Version

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");

FIX Message

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:

FIX Message example

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();

Fields

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.

FIX Session

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.

Connection Establishment

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.

Message Exchange

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

Sequence Numbers

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.

Sequence numbers diagram

See also: Sequence Numbers Management.

Configuration

Engine Initialization

The engine is configured during initialization phase. The initialization method is overloaded. Thus there are multiple ways to pass the configuration.

Properties File

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

Settings Class

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.

License File

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.

Logging

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".

Persistent Session Storage

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.

Settings

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.

Unified Resource Loading

By default, any external resource is looked for at the following places and in the following order (if other is not set explicitely):

  1. Classpath
  2. Absolute file path
  3. Current directory
  4. User home directory

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.

Advanced

FIX Repeating Group

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).

Repeating Group

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());

Accepting Uninitialised Incoming Sessions

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);
} }

Session States

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.

FIX Session States
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);
        }
    }
}

Session Events and Listeners

The events of the biz.onixs.fix.engine.Session class are listed below.

Session Listeners and Events
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);
        }
    }
}

Custom Logon Message

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.

Sequence Numbers Management

The expected sequence number of the next incoming message can be:

The sequence number of the next outgoing message can be:

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.

Reset Using ResetSeqNumFlag Field

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:

See also: Sequence Numbers.

FIX Dialects

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.

Engine Level

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.

Example
<?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);

Session Level

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.

Example
<?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);

Dialect Definition Examples

Example 1. Adding New User-Defined Field

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>

Example 2. Adding New User-Defined Repeating Group

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>

Example 3. Making Field Optional / Required

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>

Example 4. Adding New User-Defined Message

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);

Example 5. Dialect BuySide/SellSide Applications

Check samples/buyside and samples/sellside for paired live applications with dialect support.

See also: Configuration → Settings.

SSL Encryption

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.

Acceptor: Configuring SSL

The acceptor SSL configuration is performed on the engine level via the following method.

Engine.setSSLContext(sslContext);
...
Engine.init(...);

Parameters:

Make sure that you configure SSL before doing engine init.

Initiator: Configuring SSL

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:

Make sure that you configure SSL before doing session logon.

Creating SSL Context

One of the methods to create SSL context follows.

SSLContext sslContext = SSLContextFactory.getInstance(keyStoreName, trustStoreName, keyPassword);

Parameters:

The key and trust stores are loaded as described in the Unified Resource Loading.

Key and Certificate Management

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.

Example

Check samples/buyside and samples/sellside for paired live applications with SSL support.

Resources

Inbound Application Message Factory

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.

Inbound Message Log Filtering

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.

Resending Messages

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

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);

Scrambling Password in Session Storage

For the security reasons the values of the following fields can be scrambled in the session storage files:

Session Level

In order to achieve this on the session level the following option can be used:

session.setScramblePassword(true);

Engine Level

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);

Session Schedule

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.

Sessions Scheduler

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.

Scheduler class

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.

Registering a Session

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.

Removing a Session from Scheduling Services

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.

Handling Scheduling Warnings and Errors

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.

Programmatic Configuration

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.

Defining Session Connection Time-Frames

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).

Example

Check samples/Scheduler, the ProgramScheduler example.

Configuration File

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.

Configuration File Reference

The configuration file has XML-based format. The appropriate XML schema is available here.

Example

Check samples/Scheduler, the FileScheduler example.

Logon Password Authentication

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>).

Examples

Check samples/BuySide/Credential and samples/SellSide/Credential examples pair.

FAST Encoding and Decoding

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.

Decoding in 4 Steps

In order to decode FAST data to FIX message the following 4 steps are required:

  1. FIX Engine Initialization
  2. Template Library Loading
  3. Decoding
  4. FIX Engine Shutdown

FIX Engine Initialization

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.

Template Library Loading

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);

Decoding

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);

FIX Engine Shutdown

The FIX engine must be shutdown as described in the following section.

Logging

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.

Example

Check samples/fast for FAST related examples.

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.

Additional Prerequisites

Eclipse Project

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:

FAQ

I need to continue the FIX Session starting from the specific message sequence number, but I have deleted the log files from the previous runs. How can I do this?

You can use Session InSeqNum and OutSeqNum properties to set the start sequence numbers before establishing the session.

Can I have multiple session objects per engine?

Yes, you can have multiple session objects per engine instance.

What is the thread model for individual session object: are incoming events all sent from the same thread?

Yes, all incoming events related to a particular session are sent from the same thread.

Can session event listeners be heavyweight? I.e. would I be looking to fork a thread to avoid holding up receipt of further events?

It is important to avoid time-consuming tasks inside session event handlers. Thus, you should fork a thread and listener can't be heavyweight.

How can I send non-ASCII text field values (i.g. Arabic)?

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);

How can I change value of the SendingTime (52) field in the outgoing message?

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);
    }
});

Glossary

Acceptor

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.

Conditionally Required Fields

Fields which are required based on the presence or value of other fields.

Delimiter Character

The non-printing, ASCII "SOH" (\u0001, hex: 0x01, referred to in this document as <SOH>), is used for field termination.

MsgSeqNum Field

Integer message sequence number, the tag number is 34.

FIX

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.

FIX Connection

It is comprised of three parts: logon, message exchange, and logout.

FIX Dialect

This is a custom, slightly different interpretation of FIX protocol.

FIX Session

It is comprised of one or more FIX Connections, meaning that a FIX Session spans multiple logins.

Initiator

Session-Initiator establishes the telecommunications link and initiates the session via transmission of the initial Logon message.

Required Fields

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.

Unknown Fields

Fields in a FIX message that are not expected in accordance with the FIX protocol or its dialect.

SenderCompID Field

Assigned value used to identify firm sending message, the tag number is 49.

TargetCompID Field

Assigned value used to identify receiving firm, the tag number is 56.

User-defined Fields

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.

User-defined Messages

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.

FAST

The binary encoding method for message oriented data streams. FAST is an acronym for FIX Adapted for STreaming.

Resources


© Onix Solutions