FIX Antenna HFT B3 SBE support (Order Entry)


Overview

B3 SBE support is implemented as a kind of session inside FIX Antenna HFT engine scope. It allows to work with B3 protocol transparently like with other session types such as FIX sessions. The configuration is quite similar to FIX sessions configuration. The implementation allows end-user to get direct binary data and utilize any binary message handling API on his choice. Initiator(client) sessions are supported only. Further information about basic concepts and initial Fix Antenna HFT engine configuration can be found here. All basic concepts regarding errors handling and general session management are the same among any session type. Here is the link to B3 documentation that describes B3 SBE protocol in details. Please refer to it for B3 details not described in this document.

Quick start

Quick start guide can be found here. This guide describes briefly how to start working with the engine, initialize it and do basic operations. Further described differences are mostly connected to B3 specifically but general concept of Quick start guide remains the same and is valid. The difference is in details only.

Configuration

There are engine parameters that have to be configured on engine start. These parameters are B3 related and applicable for B3 sessions only. Please see the table below for details. To obtain these parameters please contact B3 support.

Engine::FixEngine::InitParameters members. All parameters are mandatory!


ParameterTypeDescription
1b3ClientAppNamestd::stringTrading system name. This parameter is registered with B3 for end-user business application that connects to B3 order-entry gateway. 1-30 symbols.
2b3ClientAppVersionstd::stringTrading system version. This parameter is registered with B3 for end-user business application that connects to B3 order-entry gateway. 1-30 symbols.


Session related parameters. These parameters are configured on per-session basis. So every B3 session can have these parameters different.

Engine::SessionExtraParameters members. All parameters are mandatory!


ParameterTypeDescriptionCan be set with properties file?
1extFirm_std::stringB3 firm. Usually this parameters corresponds to "Primary Globex Firm".Session.<Sender>/<Target>.Ext.Firm
2getSessionSecurityKeyCallback_Engine::SessionExtraParameters::GetSessionSecurityKeyCallbackCallback routine used by the engine to get password used to populate B3 logon. Provided by B3.No
3b3ClientIP_std::stringClient IP to be used during logon phase. Optional. If empty actual interface IP is used.Session.<Sender>/<Target>.B3.ClientIP
4b3CancelOnDisconnectType_Utils::Emptily< Engine::B3CancelOnDisconnectType >Cancel on disconnection operation mode passed to B3. Optional. Default value is Engine::B3CancelOnDisconnectType::DO_NOT_CANCEL_ON_DISCONNECT_OR_TERMINATE. For other values see Engine::B3CancelOnDisconnectType enum declaration.Session.<Sender>/<Target>.B3.CancelOnDisconnectType
5b3CodTimeoutWindow_TriUInt64Cancel on disconnect timeout value in milliseconds. Optional. Default value is 0. For more details see B3 documentation.Session.<Sender>/<Target>.B3.CodTimeoutWindow

Please pay attention

To achieve the best performance  LiteFixMessage should be used. So configure your SessionExtraParameters with useLiteMessage_ = true.


Arguments for Engine::FixEngine::createSession() routine.


ArgumentTypeDescription
1senderCompIDstd::stringB3 session ID. This parameter is provided by B3 and is unique for each B3 session. An unsigned integer is expected here according to B3 specification.
2targetCompIDstd::stringCan be any value(usually "B3"). This parameter is not used by B3 handler in any specific manner and is used for session logs naming and utility only.
3scpProtocolNamestd::stringMust be Exactly "B3". The value tells the engine that B3 handler must be used for the newly created session.

Engine initialization

See the sample code below.

Engine initialization
    // Initialize engine
    Engine::FixEngine::InitParameters params;
    params.propertiesFileName_ = "myapp.properties";

	...
    
    params.b3ClientAppName = "MyTradeSystem";// B3 system name
    params.b3ClientAppVersion = "1.0";       // B3 system version     

    FixEngine::init( params );

Session creation

The session is created in the same manner like any other(FIX) session within the engine except minor details connected with newly added configuration parameters. See the sample code below.

Session creation
    Engine::SessionExtraParameters extraParams;

	...

	extraParams.useLiteMessage_ = true;
    extraParams.extFirm_ = "123"; // Session Firm
    extraParams.getSessionSecurityKeyCallback_ = GetPassword;

	std::string sessionID = "101230084"; // Session ID

    RefCounter<Session> pSn(FixEngine::singleton()->createSession( pMyB3App, sessionID, "b3", "B3", &extraParams), false);

In the simplest case GetPassword routine can be defined as following:

Simple get signature key callback routine
static std::string GetPassword ( const std::string& /*sessionID*/ )
{
    return "123345678"; // Session password
}

Session connection

B3 session connects the same way like a FIX session does. If fail over mechanism is used secondary ip/port should be set as backup connection for the session. See the sample code below.

Session connection
  	std::string backupHost;
	int backupPort = 0;
	Engine::SessionExtraParameters extraParams;	

	... // parameters setup here
	
	bool hasBackup = !backupHost.empty() && backupPort != 0;
    if(hasBackup)
    {
        extraParams.enableAutoSwitchToBackupConnection_ = true; // Auto switch to backup
        extraParams.cyclicSwitchBackupConnection_ = true; // Auto switch back to primary
    }
    
	... // Session creation here

	Engine::SessionBackupParameters backupParams;
    backupParams.host_ = backupHost;
    backupParams.port_ = backupPort;
    backupParams.hbi_ = hbi;

    pSn->connect(hbi, host, port, Engine::NONE, hasBackup ? &backupParams : NULL);

Send message

B3 session works with binary data only.  The engine automatically updates outgoing sequence number of the message being sent, so no sequence handling from business application is required. Below is send message sample.

Message sending
static void sendMessage( RefCounter<Session> pB3Session, const char* pMessageData, size_t messageDataSize )
{
    pB3Session->put( pMessageData, messageDataSize ); // Sequence number is updated automatically before message is sent.
}

Receive message

B3 session delivers binary data only. So, the business application gets binary data to process.

There is no special callback to receive incoming messages from B3 session. The same callback as for FIX sessions is used but there is a new function inside Engine::FIXMessage interface introduced that should be used to get binary data from a message. It is named getBinaryData and returns true if the message contains binary data(always true for B3 sessions) and false otherwise (always false for ordinary FIX sessions).

The function has two arguments.

  1. The first is a reference to a pointer that receives a pointer to binary data
  2. The second is a reference to a variable that receives binary data size. The binary data got has the same scope as Engine::FIXMessage it was gotten from, so one has to copy it if one needs a wider scope. 

See the sample below.

Message receiving
bool TraderApp::process( const Engine::FIXMessage& msg, const Engine::Session& aSn )
{
    const char* buffer;
    size_t bufferSize;

    if(!msg.getBinaryData( buffer, bufferSize ))
        throw Utils::Exception( "Message without binary data received! Unable to process!" );
	// buffer points to binary data now, bufferSize contains binary data size.
    // Please pay attention that binary data is valid in the scope of process routine only. So one must copy it if one needs it for a wider scope!
	// See iLink3_certification sample on possible solution.
    return true;
}


B3_client sample in the package demonstrates the process callback usage


Working with binary data

It is up to end-user how to handle binary data. One can use built-in B3 binary messages handling API or any other API on his choice for example Real logic SBE. Built-in API is contained within B3BinaryMessages.h. This is a generated file that contains all(session and application layer) in/out messages from/to B3 order entry gateway. See B3 documentation for details. One should use B3 specification in order to populate outgoing and processing incoming messages data correctly. See samples below and inline comments.

For sending/receiving details please refer to corresponding iLink3 section. B3 has exactly the same pattern. The only difference is particular business fileds/messages definitions.

Session termination

Session termination can be made in a simple manner. One just needs to call session's disconnect() method. This method accepts logout text that is sent to counter-party and terminates the session correctly. See the sample below.

Terminate session
void terminate( RefCounter<Session> pB3Session, bool bReleaseSession )
{
    // Send logout and disconnect
	pB3Session->disconnect( "The session was closed by application" );

    // Unregister our application from the session to avoid any callback be called after this point. Application object can be destroyed after this call.
    pB3Session->registerApplication(NULL);

	// It is safe to release reference to the session. The engine keeps its our reference and releases it after session's termination is finished but it is safe to keep this reference if needed and release it later.
	if( bReleaseSession )
		pB3Session.reset();

}

Errors handling

Errors handling can be done utilizing Engine::Application callbacks. The names are quite descriptive. The general idea behind is that any important action has particular callback that corresponds to it. So, one can define callbacks required inside Engine::Application interface to react on some erroneous events and act as required. The engine handles most error conditions related to session level errors internally. The only event of interest is the case when NotApplied message from B3 is received. The engine handles this condition the way B3 recommends. in particular, send Sequences message to gap-fill. So, if there is a need to know what sequence range is to be gap-filled Engine::Application::onResendRequestEvent() callback should be implemented. One can force engine to ignore NotApplied from B3 by setting processResendRequest_ member of Engine::ResendRequestEvent to false in order to process NotApplied manually. Its default value is true. More details can be found at https://corp-web.b2bits.com/fixahft/doc/html/classEngine_1_1Application.html#a54fde5f18f9f63c4aadcbb5b6f10b1c8. See the sample below.

Handle resend request event
class MyApp: public Engine::Application
{
public:
	virtual void onResendRequestEvent( const Engine::ResendRequestEvent& event, const Engine::Session& /*sn*/ );
}
...
void MyApp::onResendRequestEvent( const Engine::ResendRequestEvent& event, const Engine::Session& /*sn*/ ) 
{
	// Getting begin and end sequence numbers of the gap
	int gapBegin = event.getBeginSeqNo();
	int gapEnd = event.getEndSeqNo();
	
	if(gapEnd - gapBegin < 100) // Do custom NotApplied processing if the gap is more than 100 messages. It is just a sample not related to any actual business needs!
		return;
	// Tell the engine to ignore NotApplied message.
	event.processResendRequest_ = false;

	// Getting original binary message if required.
    const char* buffer;
    size_t bufferSize;

    if(!event.resendRequestMsg_->getBinaryData( buffer, bufferSize ))
        throw Utils::Exception( "Message without binary data received! Unable to process!" );
	
    // Cast data to base B3 type
	const B3::NotApplied* pNotApplied = reinterpret_cast<const B3::NotApplied*>(buffer);

	// Check whatever the message is valid	
    if(!B3::isValidB3Message( pNotApplied ) ||  pNotApplied ->getSbeHeader().getTemplateId() != B3::NotApplied::TemplateID)
        throw std::exception( "Invalid NotApplied message received!" );

	// Do custom NotApplied processing here

	...
	
    return;
}

Multiple segments connection

B3 has the market split into several segments each of which has it's separate IP and port defined. So one can connect to several or even all segments simultaneously. To do this  one needs to create separate B3 session to each segment needed the same way as describe above in the samples. So, every segment looks like separate session. The only thing to take into account here is that every session has to have unique combination of senderCompID/targetCompID. Since senderCompID is used as sessionID for B3 sessions and is the same for all segments targetCompID should be different for every segment. So the combinations might be like following: 101230084/B3-seg00, 101230084/B3-seg01 and so on. Please see the sample below.

Multi segments sample
    Engine::SessionExtraParameters extraParams;

	...

	extraParams.useLiteMessage_ = true;
	extraParams.extFirm_ = "123"; // Session Firm 
	extraParams.getSessionSecurityKeyCallback_ = GetPassword;
	std::string sessionID = "101230084"; // Session ID

	// pMyB3AppForSeg00 and pMyB3AppForSeg01 can be the same if no separate processing for different segments is required.
	// Create session for segment 00
    RefCounter<Session> pSn00(FixEngine::singleton()->createSession( pMyB3AppForSeg00, sessionID, "B3-seg00", "B3", &extraParams), false);

	// Connect to segment 0
    pSn99->connect(hbi, seg00Host, seg00Port);

	// Create session for segment 01
    RefCounter<Session> pSn01(FixEngine::singleton()->createSession( pMyB3AppForSeg01, sessionID, "B3-seg01", "B3", &extraParams), false);

	// Connect to segment 01
    pSn21->connect(hbi, seg01Host, seg01Port);

Sample

There are projects named B3_client/B3_fix_bridge that are provided within the package. These projects demonstrate possible solutions how to work with B3 using the engine. It is real operating applications that can be used as a base to build on end-user business project or to build an application to pass B3 certification. These applications, after setting correct configuration values in engine.properties file (see configuration section above), can be used to connect to B3 gateway and do some basic operations like sending a test order and similar. B3_fix_bridge transparently converts FIX to B3 SBE and vice versa. It utilizes object pool model to queue messages for processing incoming messages. It can be used for quick and transparent connection of a FIX endpoint to B3 gateway.

How-To

Here is the link where How-To links regarding latency configuration and other useful topics are located. https://b2bits.atlassian.net/wiki/pages/viewpage.action?pageId=6129580