xConnectivity is a FIX connectivity bridge. It comes with a high performance FIX engines plugin developed in C++.It has an open iterface that allowed customer to developer their own plugins for integration with your private OMS.
The x Connectivity platform support FIX versions from 4.2 to 5.0sp2. Different FIX version can be configured with differernt plugins. The bridge provide a feature to allow you to transfer the messages from one plugin to another plugin with a different version using Lua scripting language.
How to integrate the system with your private OMS? The solution provides an open interface for you to development your own plugins. Its FIX plugin can also be directed called from your private OMS system.
The system is designed to run on 64 bit Windows and Linux.
xconnectivity
│──bin
│ │ codec_fix.dll --Fix encoder/decoder
│ │ fix.dll --FIX plugin, support all version of FIX protocol
│ │ fix.lib --FIX plugin library for re-development
│ │ key --License key file
│ │ LICENSE.txt --License policy
│ │ message.dll --Processes message template
│ │ msvcp140.dll --VC140 redistribution library
│ │ vcruntime140.dll --VC140 redistribution library
│ │ x.exe --xConnectivity application
│ │ x.xml --xConnectivity configuration file
│ │ buy.exe --buy side sample application
│ │ buy.xml --buy side sample configuration
│ │ sell.exe --sell side sample application
│ │ sell.xml --sell side sample configuration
│ ├───db
│ ├───fix --FIX specifications
│ │ fix42.xml
│ │ fix44.xml
│ │ fix50sp1.xml
│ │ fix50sp2.xml
│ ├───log
│ └───script
├───include
└───sample
xconnectivity
├───bin
│ │ buy
│ │ buy.sh
│ │ buy.xml
│ │ key
│ │ libcodec_fix.so
│ │ libfix.so
│ │ libmessage.so
│ │ LICENSE.txt
│ │ sell
│ │ sell.sh
│ │ sell.xml
│ │ x
│ │ x.sh
│ │ x.xml
│ ├───db
│ ├───fix
│ │ fix42.xml
│ │ fix44.xml
│ │ fix50sp1.xml
│ │ fix50sp2.xml
│ ├───log
│ └───script
├───include
└───sample
The syste is designed to use XML format as standard configuration file. it always comes with the following format:
<?xml version="1.0" encoding="utf-8"?>
<!--x system configuration always start with application. Name will display on the UI-->
<application name="xConnectivity">
<!-- Log configuration
name : name of the log
file : log file path and name, the actual name will be suffixed with date & time.
queue_size: async log queue size. default set 65535
pattern: each log line format:
%Y - year in 4 digital
%C - year in 2 digital
%m - Month 01- 12
%d - Day of the month 01-31
%H - Hour
%M - Minutes
%S - Seconds
%f - Microseconds
%t - thread id
%L - log level
%V - log content
%E - line end
%P - process id
%n - log name
level: 0 - 10, 0 is the lowest, and 10 is the highest.
-->
<log name="x" file="./log/x" queue_size="65536" pattern="[%H:%M:%S.%f] %t %L %v%E" level="2" />
<!--In menory data file configuration, initial db size=128mb,
set this number big enough to avoid memory relocation.
file : file path and name of the database. it creates as an memory map file.
name : name of the database
access_type: 0-read only, 1 - read & write
init_size : 1,2,4,8,16m etc in byte.
extension_quantum : specify the extension size when mentioned size is in sufficent.
commit_delay: 1 - delayed, 0- no delayed, synchorinize immediately into file.
Replications can be setup for the in memory database.
-->
<db file="./db/x.fdb"
name="x"
access_type="1"
init_size="134217728"
extension_quantum="0"
commit_delay="1">
<replication my_index="0">
<connection addr="127.0.0.1:18000"/>
</replication>
</db>
<!-- configure the plugins to be loaded into the application. The system comes with a series of
ready to use plugins such as FIX, ipc, IBMMQ, multicast, exchange APIs, (SGX, etc.)
With the open source interface, it is easy to develop your own plugins.
-->
<plugins>
<plugin name="fix" lib="fix" config="./x.xml" />
</plugins>
<!-- Below configuration used by FIX plugin.
the fix can be configured as initiator or acceptor.
sender : compid for this instance
target : compid for counter party
template : specifys the version of FIX plugins.
codec : encoding /decoding format.
heartbeat_interval: for initiator
recv_buffer_size/send_buffer_size : receive and sender buffer size for each session
property : default 0x0
connections : specifies the connections, can add multiple ip address and port for
auto failover.
scheduler : fix session start , stop and reset timing. holidays can be configured as well.
-->
<fix number_of_thread="1">
<initiator sender="X"
target="SELL"
template="./fix/fix42.xml"
codec="codec_fix"
heartbeat_interval="10"
recv_buffer_size="102400"
send_buffer_size="102400"
property="0x00000001">
<connections connect_interval="10" connect_timeout="10">
<connection addr="127.0.0.1" port="8001" />
</connections>
<scheduler>
<tasks>
<session start="daily@00:10:00" stop="daily@23:59.59" reset="daily@00:05"/>
</tasks>
</scheduler>
</initiator>
<acceptor sender="X"
target=""
template="./fix/fix42.xml"
codec="codec_fix"
recv_buffer_size="1024000"
send_buffer_size="1024000"
property="0x00000059">
<!-- connections -->
<connections connect_timeout="10">
<connection port="8000"/>
</connections>
<scheduler>
<tasks>
<session start="daily@00:10:00" stop="daily@23:59.59" reset="daily@00:05"/>
</tasks>
<holidays>
<holiday date="20161120" />
</holidays>
</scheduler>
</acceptor>
</fix>
<!-- Specifies the routing option
dropcopy : for any message, you can specify multiple destination for dropcopy.
encrichment : you can specify the enrichment script as well.
-->
<router>
<target name="SELL">
<sender name="BUY" dropcopy="BO"/>
</target>
</router>
</application>
With the open source interface, it is it easy to develop your own plugin or integrate the ultra low latency fix plugins into your own application. The interface files in C++
are provided in the include
in the package.
The following are the interfaces files:
sessionhandler.h
virtual interface to handle the session activity. You have to implement this virtual interface to handle the messages or sending message out.
session.h
define the session interface. you can start/stop session via this interface.
message.h
message definition.It defines the interfaces to get/set value on a specific messages.
field.h
interface for the specific field on a message.
fix42.h
fix tag/value definition. You can modify this file to add your customermized tags.
plugin.h
to start and stop a plugin.
Below is am exaple in C++ code. For more details, refer to the sample code included in this package.
class Application :public SessionHandler
{
public:
Application() : id(0)
{
void* handle = dlopen("libfix.so", RTLD_NOW| RTLD_GLOBAL|RTLD_DEEPBIND);
if (handle != NULL)
{
createPlugin = (lib_func) dlsym(handle, "createPlugin");
plugin = createPlugin(*this, NULL, NULL);
}
}
virtual ~Application() {}
virtual bool Initialize(const char* config, bool encrypted = false)
{
if (!plugin->Initialize(config, encrypted))
{
printf("error:failed to initialize fix plugin");
return false;
}
return true;
}
virtual bool Start()
{
if (!plugin->Start())
{
printf("error:failed to start fix plugin");
return false;
}
return true;
}
virtual void Stop()
{
plugin->Stop();
}
virtual void Destory(bool force_failover = false)
{
plugin->Destory(force_failover);
}
virtual Session* findSession(const char* target)
{
return plugin->findSession(target);
}
virtual void onUnhandledMessage(Session* session, Message* msg, const char* msg_type, char* buffer, int len)
{
if (session->isConnected())
{
if (msg_type[0] == 'D')// NewOrderSingle
ExecutionReport(session, msg);
}
}
public:
void ExecutionReport(Session* session, Message* imsg)
{
Message* omsg = session->CreateMessage(MsgType::EXECUTION_REPORT);
if (omsg != NULL)
{
Field* ibody = imsg->getBody();
Field* obody = omsg->getBody();
char execid[20];
char t[25];
sprintf(execid, "%015d", ++id);
obody->setString(ExecutionReport::OrderID, "NONE")
->setString(ExecutionReport::ClOrdID, ibody->getString(NewOrderSingle::ClOrdID, NULL))
->setString(ExecutionReport::ExecID, execid)
->setChar(ExecutionReport::ExecType, ExecType::REJECTED)
->setChar(ExecutionReport::OrdStatus, OrdStatus::REJECTED)
->setString(ExecutionReport::Account, ibody->getString(NewOrderSingle::Account, NULL))
->setString(ExecutionReport::Symbol, ibody->getString(NewOrderSingle::SecurityExchange))
->setString(ExecutionReport::SecurityType, ibody->getString(NewOrderSingle::SecurityType, NULL))
->setString(ExecutionReport::SecurityExchange, ibody->getString(NewOrderSingle::SecurityExchange, NULL))
->setChar(ExecutionReport::Side, ibody->getChar(NewOrderSingle::Side, Side::BUY))
->setString(ExecutionReport::TransactTime, GetUTCDateTime(t, 25))
->setDouble(ExecutionReport::OrderQty, ibody->getDouble(NewOrderSingle::OrderQty, 0))
->setChar(ExecutionReport::OrdType, ibody->getChar(NewOrderSingle::OrdType))
->setDouble(ExecutionReport::Price, ibody->getDouble(NewOrderSingle::Price, 0))
->setChar(ExecutionReport::TimeInForce, ibody->getChar(NewOrderSingle::TimeInForce, '0'))
->setDouble(ExecutionReport::LastShares, 0.0)
->setDouble(ExecutionReport::LastPx, 0.0)
->setDouble(ExecutionReport::LeavesQty, 0.0)
->setDouble(ExecutionReport::CumQty, 0.0)
->setString(ExecutionReport::Text, "Order Rejected");
sendMessage(session, omsg, MsgType::EXECUTION_REPORT, true);
session->ReleaseMessage(omsg);
}
else
{
printf("error: failed to create message:%s\n", MsgType::EXECUTION_REPORT);
}
}
private:
Plugin* plugin;
lib_func createPlugin;
int id;
};
int main()
{
const char* config_file = "./sell.xml";
char buffer[100];
Application app;
try
{
if (app.Initialize(config_file))
{
if (!app.Start())
{
printf("error: failed to start application\n");
printf("Press ENTER to quit!\n");
GetLine(buffer, 100);
}
}
else
{
printf("error: failed to initialize application\n");
printf("Press ENTER to quit!\n");
GetLine(buffer, 100);
}
printf("Press ENTER to quit!\n");
GetLine(buffer, 100);
app.Stop();
app.Destory();
}
catch (std::exception& e)
{
printf("exception:%s\n", e.what());
}
printf("Press ENTER to quit!\n");
GetLine(buffer, 100);
return 0;
}
There are two examples included in this package:
example 1
: integrate ultra low latency fix plugin into your own application, and directly connect to other counter party. In this example, after you start both buy & sell application, you can trigger the NewOrderSingle message to sell side. It will response with an ExecutionReport(8) once received the NewOrderSingle message.
Below is the performance shows for a round trip latency.Both buy and sell application runs on the same server. The sample testing runs on Ubuntu 18.04, Intel Core i7-8750H CPU @2.2GHz, 8G DDR3 RAM and 500G SSD
example 2
: buy and sell side to connect to xConnectivity and routing message via xConnectivity.
In this example, we measures the timing xConnectivity used to forward a message.Ubuntu 18.04, Intel Core i7-8750H CPU @2.2GHz, 8G DDR3 RAM and 500G SSD