B2BITS FIX Antenna C++  2.27.0
Protocol customization quick start

Table of Contents

Customization is required when changes that are to be made do not fit into the user defined fields approach (see User defined fields).

For example:

FIX Antenna adopts the notion of "additional fields" to create FIX dialects. The configuration parameter can be used to customize the standard FIX version.

FIX Dictionaries included in FIX Antenna package

Protocol ID / Parser NameXML File
FIX40fixdic40.xml
FIX41fixdic41.xml
FIX42fixdic42.xml
FIX43fixdic43.xml
FIX44fixdic44.xml
FIX50fixdic50.xml
FIX50SP1fixdic50sp1.xml
FIX50SP2fixdic50sp2.xml
FIX50SP2EPfixdic50sp2ep.xml

Dictionaries setup

Perform dictionaries configuration in engine.properties file before starting application.

# This parameter contains list of the XML files, separated by coma or semicolon,
# with FIX protocol definition. In additional, this parameter could contain list
# of XML files with additional protocol customization, if required.
#
# Note: FIX protocol definition files could be found in "dic" folder in the package
# installation dir
#
# Warning: FIX protocol customiztion files MUST be specified AFTER protocol definition
# files
DictionariesFilesList = fixdic43.xml;additional.xml

It is also possible to load additional dictionaries customizations in runtime.

Creating protocol customization

The protocol customization is specified in a separate XML file. There are two types of protocol updates:

To perform update of the exiting protocol, the id of the fixdic field must be set to id of protocol you want to change. The example of FIX Dialect:

<?xml version="1.0" encoding="UTF-8"?>
<fixdics>
<update>
<fixdic fixversion="4.3" title="FIX 4.3" date="2007/03/22" id="FIX43">
<fielddic>
</fielddic>
<msgdic>
<msgdef msgtype="F" >
<field tag="555" />
<group nofield="555" startfield="600">
<field tag="600" req="N"/>
<field tag="608" req="N"/>
<field tag="610" req="N"/>
<field tag="616" req="N"/>
<field tag="624" req="N"/>
</group>
</msgdef>
</msgdic>
</fixdic>
</update>
</fixdics>

This example will update the FIX 4.3 protocol message Order Cancel Request (F) with a new non-required repeating group NoLegs (555)

To create a new FIX dialect, set parent_id property to base protocol id and id to new dialect id. Note, that id value must be unique for FIX Antenna instance
The example of FIX Dialect:

<?xml version="1.0" encoding="UTF-8"?>
<fixdics>
<update>
<fixdic fixversion="4.4" title="FIX 4.4" date="2009/12/07" id="FIX44_MY" parent_id="FIX44">
<fielddic>
<fielddef tag="5001" name="field5001" type="NumInGroup"/>
<fielddef tag="5002" name="field5002" type="String"/>
</fielddic>
<msgdic>
<msgdef msgtype="X" >
<field tag="5001" />
<group nofield="5001" startfield="5002">
<field tag="5002" req="Y"/>
</group>
</msgdef>
</msgdic>
</fixdic>
</update>
</fixdics>

Creating sessions

Call one of the methods below to create a session:

const std::string& senderCompID,
const std::string& targetCompID,
const Engine::SessionExtraParameters* pParam = NULL,
const Engine::MessageStorageType storageType = persistent_storageType,
Engine::UnderlyingProtocol underlyingProtocolType = FIX_TCP);
const std::string& senderCompID,
const std::string& targetCompID,
ParserID scpID,
const SessionExtraParameters* pParam = NULL,
const MessageStorageType storageType = default_storageType,
FIXVersion defaultAppProtocol = NA );

To create session based on one of default protocols, it is enough to pass Engine::FixVersion to ver parameter of FixEngine::createSession function. FIXAntenna will automatically convert FixVersion to appropriate ParserID. But for creating session based on a custom FIX dialect, it is needed to convert string name of a protocol to an internal ParserID handle:

Engine::ParserID Engine::FixEngine::getParserID( const std::string& name ) const;

The example below shows how to create both kinds of sessions:

// Create session based on FIX 4.3 protocol
Engine::Session * session_fix43 = Engine::FixEngine::singleton()->createSession(&application, "SenderFIX43", "TargetFIX43", Engine::FIX43 );
// Create session, based on custom FIX dialect, described as FIX44_MY
Engine::Session * session_fix44 = Engine::FixEngine::singleton()->createSession(&application, "SenderFIX44", "TargetFIX44", pid, Engine::FIX44);

Refer to the section FIX Session for additional information about sessions.

Full sample

The sample below illustrates all abovementioned instructions combined in one application.

engine.properties

#
# The FIX Engine configuration file.
#
# $Revision: 1.6 $
#

# For UNIX platforms, the filename-separator character is "/".
# For Win32 platforms, the filename-separator character is "//" or "/".

# The top of the directory tree under which the engine's configuration,
# and log files are kept.
#
# Do NOT add a slash at the end of the directory path.
EngineRoot = .

# Engine's listen port. Must be > 0.
ListenPort = 9021

# Engine's local IP address to bind to. It can be used on a multi-homed host
# for a FIX Engine that will only accept connect requests to one of its addresses.
# If this parameter is commented, the engine will accept connections to any/all 
# local addresses.
# ListenAddress = localhost

# Engine's local IP address to send from. It can be used on a multi-homed host
# for a FIX Engine that will only send IP datagrams from one of its addresses.
# If this parameter is commented, the engine will send IP datagrams from any/all 
# local addresses.
# ConnectAddress = localhost

# Number of threads that serve FIX sessions.
# 
# Changing this value will impact upon the performance of FIX Engine. 
# The recommended value is 10. The value must be integer and greater than zero.
NumberOfWorkers = 10

# This property is the path of the directory in which the logs for all incoming 
# (if LogIncomingMessages is set to "true") and outgoing FIX messages are stored. 
# It is possible to specify a path related to the EngineRoot directory or an absolute path.
# For example if LogDirectory is set to /"logs/" then the real path is $(EngineRoot)/logs.
# The specified directory must exist.
LogDirectory = logs

# This property provides an option to log incoming FIX messages (those received) from 
# a counterparty FIX Engine. They will be stored in the directory specified by 
# the LogDirectory parameter in a file with extension "in".
LogIncomingMessages = false

# This parameter sets the time period after which a session is non-gracefully terminated 
# if a response is not received to a first "Logon" message (message type A). 
# The corresponding Logout message is sent to the counterparty.
# This value is in seconds. 
# The recommended value is 30 seconds for dedicated connections or private networks. 
# Trading connections via the internet will require calibration. 
# If it is set to "0", then the time period is unlimited. 
# The value must be integer and not negative.
LogonTimeFrame = 30

# This parameter sets the time period after which a session is automatically terminated 
# if a response is not received to a "Logout message" (message type 5). 
# This value is in seconds. 
# The recommended value is 10 seconds for dedicated connections or private networks. 
# Trading connections via the internet will require calibration. 
# The value must be integer and greater than 0.
LogoutTimeFrame = 10

# An option not to reset sequence numbers after Logout.
# Logout sender should initiate session recovery by sending Logon message
# with SeqNum = <last outgoing SeqNum> + 1;
# expecting reply Logon with SeqNum = <last incoming SeqNum> + 1.
# If a gap is detected, standard message recovery or gap filling process
# takes place.
IntradayLogoutTolerance = true

# This parameter controls existance of required tags in application level messages. 
# The possible values are "true" and "false". If set to "true" then all application 
# level messages are validated. If set to "false" then the responsibility for message validity 
# rests with the counterparty. Please note that session level messages are validated in 
# all cases. The recommended setting is "true".
MessageMustBeValidated = false

# This parameter specifies the delta (increment) to the Heartbeat interval between
# a TestRequest message being sent by FIX Engine and a Response Heartbeat being received. 
# The session attains a "telecommunication failed state" if no Response Heartbeat message 
# is received after the normal Heartbeat interval plus delta. For example if no message 
# (application or session level) is received during the Heartbeat interval then Engine sends 
# a TestRequest message. If the required Response Heartbeat message is not received during 
# Heartbeat interval plus Delta then the session moves to the state "Telecommunication link 
# failed". This parameter is specified in (Heartbeat Interval/100). The recommended value is 
# twenty percent.
ReasonableTransmissionTime = 20

# FIX Engine has inbuilt FIX message routing capability and  fully supports 
# the "Deliver To On Behalf Of" mechanism as specified by the FIX protocol.
# If this parameter is set to "True" then Engine will redirect FIX messages automatically 
# to other FIX sessions it maintains. 
# If this parameter is set to "False" Engine directs all messages received to the client 
# application.
ThirdPartyRoutingIsEnabled = false

# This parameter provides an option whereby FIX Engine will accept a FIX session for which it 
# has no registered application (an acceptor). If set to "true" Engine establishes a session, 
# all application level messages are rejected (Application Level Reject - type 3). When 
# an application is registered behaviour is as standard. If set to false then Logon messages 
# are ignored.
UnregisteredAcceptor.CreateSession = true 

# This parameter specifies the time interval between attempts to deliver an application level 
# message to a registered client application in the event the application does not confirm 
# receipt and operation upon the message. The value is specified in milliseconds. 
# The value must be integer and greater than 0.
# This parameter is required ony if the DelayedProcessing.MaxDeliveryTries
# parameter is specified.
DelayedProcessing.DeliveryTriesInterval = 500

# This parameter specifies the number of attempts that will be made to deliver an application 
# level message to the registered client application. If this value is exceeded then 
# the session will be closed with the logout reason "Application not available". The recommended value is 10.
# The value must be integer and not negative.
DelayedProcessing.MaxDeliveryTries = 2

# This parameter specifies the number of attempts to restore the session.
# The session is considered as restored if the telecommunication link was
# restored and the exchange of Logon messages was successful.
# If it is set to "-1", then the number of attempts is unlimited. 
# This value is integer. 
# This parameter is optional.
Reconnect.MaxTries = 3

# This parameter specifies the time interval between reconnection attempts in order to restore
# a communications link. This value is specified in milliseconds (seconds*10-3). 
# The recommended value is 1000 for dedicated connections and private networks. 
# Internet connections require calibration. The value must be integer and greater than 0.
Reconnect.Interval = 1000

# The license file name.
LicenseFile=../../../engine.license

# This parameter defines the upper limit to the number of outgoing messages that are resent 
# in the event of a Resend Request. The recommended value is 20000 if no data on mean activity is known.
# WARNING: Changing this value will impact upon the performance of FIX Engine. 
# Larg storage increases application working set.
OutgoingMessagesStorageSize = 1000

# This parameter is an option whereby the version of FIX protocol used for the outgoing message
# is validated against that of the established session. If set to "true" then the application 
# must use the same version of the protocol as the established session otherwise an error 
# occurs. If set to false then the application level message will be sent to the counterparty. 
# The recommended value is "true".
CheckVersionOfOutgoingMessages = true

# If this parameter is true than file streams are flushed after each I/O operation. 
ExtraSafeMode = true

# This parameter allow to automaticaly resolve sequence gap problem. 
# When parameter is true and outgoing SeqNum is 0, session use 141(ResetSeqNumFlag) 
# tag in sending/confirming Logon message to reset seqNum at the initiator or acceptor.
ForceSeqNumReset=false

# Default storage type of the created sessions. By default persistent storage 
# type used. Use "transient" value to use transient storage for the sessions.
#UnregisteredAcceptor.SessionStorageType = 

# This parameter contains name of the XML file with extensions of the FIX protocols.
DictionariesFilesList = ../../../data/fixdic43.xml;../../../data/fixdic44.xml;custom_fix43.xml

UnregisteredAcceptor.IgnoreSeqNumTooLowAtLogon = true

BackupDirectory = logs/backup

UnregisteredAcceptor.RejectMessageWhileNoConnection = false

ResetSeqNumAfter24hours = false

Validation.CheckRequiredGroupFields = true

MessageTimeToLive = 1000

AllowZeroNumInGroup = false

Log.Device = File
Log.DebugIsOn = true
Log.NoteIsOn = true
Log.WarnIsOn = true
Log.ErrorIsOn = true
Log.FatalIsOn = true
Log.Cycling = false
Log.File.RootDir = ./logs/
Log.File.Locked = false
Log.File.Rotate = false
Log.File.Backup.Time =
Log.File.Name = _log
Log.File.Recreate = true
Log.File.AutoFlush = true
Log.EventLog.EventSource = TestService

# Monitoring
Monitoring.Enable = true

Monitoring.AdminSessionNames = AdminClient
#
## User monitoring tool (TargetCompId = AdminClient)
Monitoring.AdminSession.AdminClient.TargetCompId = AdminClient
Monitoring.AdminSession.AdminClient.Version = FIX44
Monitoring.AdminSession.AdminClient.Username = user
Monitoring.AdminSession.AdminClient.Password = pass
Monitoring.AdminSession.AdminClient.IntradayLogoutToleranceMode = true
Monitoring.AdminSession.AdminClient.ForceSeqNumResetMode = true
Monitoring.AdminSession.AdminClient.IgnoreSeqNumTooLowAtLogon = true
Monitoring.AdminSession.AdminClient.DisableTCPBuffer = false
Monitoring.AdminSession.AdminClient.MaxMessagesAmountInBunch = 10
Monitoring.AdminSession.AdminClient.SocketOpPriority = AGGRESSIVE_SEND

custom_fix43.xml

<?xml version="1.0" encoding="UTF-8"?>
<fixdics>
  <update>
    <fixdic fixversion="4.3" title="FIX 4.3" date="2007/03/22" id="FIX43">
      <msgdic>
        <msgdef msgtype="F" >
          <field tag="555" />
          <group nofield="555" startfield="600">
            <field tag="600" req="N"/>
            <field tag="608" req="N"/>
            <field tag="610" req="N"/>
            <field tag="616" req="N"/>
            <field tag="624" req="N"/>
          </group>
        </msgdef>
      </msgdic>
    </fixdic>
  </update>
</fixdics>

custom_fix44.xml

<?xml version="1.0" encoding="UTF-8"?>
<fixdics>
  <update>
    <fixdic fixversion="4.4" title="FIX 4.4" date="2009/12/07" id="FIX44_MY" parent_id="FIX44">
      <fielddic>
        <fielddef tag="5001" name="field5001" type="NumInGroup"/>
        <fielddef tag="5002" name="field5002" type="String"/>
      </fielddic>
      <msgdic>
        <msgdef msgtype="X" >
          <field tag="5001" />
          <group nofield="5001" startfield="5002">
            <field tag="5002" req="Y"/>
          </group>
        </msgdef>
      </msgdic>
    </fixdic>
  </update>
</fixdics>

sender.cpp

/*
  <copyright>

  $Revision: 1.3 $

  (c) B2BITS EPAM Systems Company 2000-2017.
  "Licensor" shall mean B2BITS EPAM Systems Company (B2BITS).

  This software is for the use of the paying client of B2BITS (which may be
  a corporation, business area, business unit or single user) to whom it was
  delivered (the "Licensee"). The use of this software is subject to
  license terms.

  The Licensee acknowledges and agrees that the Software and Documentation
  (the "Confidential Information") is confidential and proprietary to
  the Licensor and the Licensee hereby agrees to use the Confidential
  Information only as permitted by the full license agreement between
  the two parties, to maintain the confidentiality of the Confidential
  Information and not to disclose the confidential information, or any part
  thereof, to any other person, firm or corporation. The Licensee
  acknowledges that disclosure of the Confidential Information may give rise
  to an irreparable injury to the Licensor in-adequately compensable in
  damages. Accordingly the Licensor may seek (without the posting of any
  bond or other security) injunctive relief against the breach of the forgoing
  undertaking of confidentiality and non-disclosure, in addition to any other
  legal remedies which may be available, and the licensee consents to the
  obtaining of such injunctive relief. All of the undertakings and
  obligations relating to confidentiality and non-disclosure, whether
  contained in this section or elsewhere in this agreement, shall survive
  the termination or expiration of this agreement for a period of five (5)
  years.

  The Licensor agrees that any information or data received from the Licensee
  in connection with the performance of the support agreement relating to this
  software shall be confidential, will be used only in connection with the
  performance of the Licensor's obligations hereunder, and will not be
  disclosed to third parties, including contractors, without the Licensor's
  express permission in writing.

  Information regarding the software may be provided to the Licensee's outside
  auditors and attorneys only to the extent required by their respective
  functions.

  </copyright>
*/

#include <iostream>
#include <string>
#include <memory>

#include <B2BITS_V12.h>
#include "FixApp.h"

using namespace std;

const char* LISTENER_IP = "127.0.0.1";
const int LISTENER_PORT = 9022;

int main()
{
    cout << "starting FIX Sender..." << endl;

    try {
        // Initializes engine.
        // If error appears during initialization (properties file is not found, required property is missing, etc.) then exception is thrown.
        Engine::FixEngine::init( "sender.engine.properties" );

        // Create Application instance. CFIXApp class derived from Engine::Application
        CFIXApp application;

        cout << "starting FIX Sender session..." << endl;

        Engine::SessionExtraParameters params;
        params.intradayLogoutToleranceMode_ = true;

        // Create FIX 4.3 session instance
        Engine::Session* pSIFIX43 =  Engine::FixEngine::singleton()->createSession( &application, "TargetCompID_FIX43", "SenderCompID_FIX43",  Engine::FIX43, &params );

        // Connect session as initiator
        pSIFIX43->connect( 30, LISTENER_IP, LISTENER_PORT );

        // create FIX 4.3 Order Cancel Request using the Flat model
        std::auto_ptr<Engine::FIXMessage> pFIX43Message( Engine::FIXMsgFactory::singleton()->newSkel( Engine::FIX43, "F" ) );

        // Fill required by FIX 4.3 fields
        std::string clrodid;
        Engine::UTCTimestamp::now().toFixString( &clrodid );
        pFIX43Message->set( FIXField::OrigClOrdID, clrodid );
        pFIX43Message->set( FIXField::ClOrdID, clrodid );
        pFIX43Message->set( FIXField::Symbol, "MSFT" );
        pFIX43Message->set( FIXField::Side, '1' ); // Buy
        pFIX43Message->set( FIXField::OrderQty, 400 );
        pFIX43Message->set( FIXField::OrdType, '2' ); // Limit
        pFIX43Message->set( FIXField::TransactTime, Engine::UTCTimestamp::now() );

        // Fill custom fields
        pFIX43Message->set( 555, 1 );
        pFIX43Message->getGroup( 555 )->set( 600, "MSFS", 0 );
        pFIX43Message->getGroup( 555 )->set( 616, "XAMS", 0 );
        pFIX43Message->getGroup( 555 )->set( 624, '2', 0 );
        pFIX43Message->getGroup( 555 )->set( 600, "MSFT", 0 );
        pFIX43Message->getGroup( 555 )->set( 616, "XAMS", 0 );
        pFIX43Message->getGroup( 555 )->set( 624, '1', 0 );

        cout << "sending the message: " << *pFIX43Message->toString( '|' ) << endl << endl;

        // Send order to session initiator
        pSIFIX43->put( pFIX43Message.get() );

        // Wait for trade
        application.tradeReceived_.wait();

        // Closing the session
        pSIFIX43->disconnect();
        application.logoutReceived_.wait();

        // Releasing resources
        pSIFIX43->registerApplication( NULL );
        pSIFIX43->release();

        // Load new FIX protocol dialect from XML file and store ParserID
        Engine::FixEngine::singleton()->loadProtocolFile( "custom_fix44.xml" );
        Engine::ParserID pid = Engine::FixEngine::singleton()->createFixParser( "FIX44_MY" );
        // Create session using customized FIX44 protocol
        Engine::Session* pSIFIX44 = Engine::FixEngine::singleton()->createSession( &application, "TargetCompID_FIX44", "SenderCompID_FIX44", pid, &params );
        // Start session as initiator
        pSIFIX44->connect( 30, LISTENER_IP, LISTENER_PORT );

        // Create and fill default "X" message fields
        std::auto_ptr<Engine::FIXMessage> pFIX44Message( Engine::FIXMsgFactory::singleton()->newSkel( pid, "X" ) );
        pFIX44Message->set( FIXField::NoMDEntries, 1 );
        pFIX44Message->getGroup( FIXField::NoMDEntries )->set( FIXField::MDUpdateAction, '0', 0 );
        pFIX44Message->getGroup( FIXField::NoMDEntries )->set( FIXField::Symbol, "MSTS", 0 );
        pFIX44Message->getGroup( FIXField::NoMDEntries )->set( FIXField::NoUnderlyings, 1, 0 );
        pFIX44Message->getGroup( FIXField::NoMDEntries )->getGroup( FIXField::NoUnderlyings, 0 )->set( FIXField::UnderlyingSymbol, "MSTS", 0 );

        // Fill customized fields
        pFIX44Message->set( 5001, 1 );
        pFIX44Message->getGroup( 5001 )->set( 5002, "APL", 0 );

        cout << "sending the message: " << *pFIX44Message->toString( '|' ) << endl << endl;

        // Send message to session initiator
        pSIFIX44->put( pFIX44Message.get() );

        // Wait for response
        application.tradeReceived_.wait();

        // Closing the session
        pSIFIX44->disconnect();
        application.logoutReceived_.wait();

        // Releasing resources
        pSIFIX44->registerApplication( NULL );
        pSIFIX44->release();

        // Destroying the engine
        Engine::FixEngine::destroy();
    } catch( const std::exception& ex ) {
        cout << "Error: " << ex.what() << endl;

        // Destroying the engine
        Engine::FixEngine::destroy();
    } catch ( ... ) {
        cout << "Unknown error." << endl;

        // Destroying the engine
        Engine::FixEngine::destroy();
    }

    return 0;
}

Old format

The format below is deprecated and cannot be used. The value syntax is the following:

Version:MsgType1:GroupLeadingTag1(ReqTag1, OptTag2?,..), GroupLeadingTag1=>NestedGroupLeadingTag1(ReqTag1, OptTag2?,..), OptTag1?, optTag2?,..,ReqTagN;Version:MsgType2:..

The example below means:

Validation.AdditionalFields = FIX42:8:639?,204?;FIX44:r:528,534(50001?);