当前位置:网站首页>Development of trading system (XI) -- Introduction to quickfix
Development of trading system (XI) -- Introduction to quickfix
2022-06-25 04:02:00 【Tianshan old demon】
One 、QuickFIX brief introduction
1、QuickFIX brief introduction
QuickFIX Is a C++ Open source implementation FIX engine , At the same time provide Python、Ruby Language implementation .
QuickFIX Official website :
http://www.quickfixengine.org
Github Address :
https://github.com/quickfix/quickfix
2、QuickFIX compile
Compilation options configuration :
configure
compile :
make
Check :
make check
install :
sudo make install
Two 、FIX Application mode
1、FIX Introduction to application mode
FIX Applications include initiator and acceptor Two modes .
initiator yes TCP The initiator of the connection ,acceptor yes TCP Connect listener . standard FIX application ( Such as CTS FIX gateway ) Can support at the same time initiator and acceptor Two modes , You can initiate a connection , You can also accept connection requests .
Development FIX When applied , You need to make sure FIX Application mode , Then choose the corresponding QuickFIX Class object .
initiator Mode FIX Applications can use SocketInitiator、SSLSocketInitiator、ThreadedSocketInitiator、ThreadedSSLSocketInitiator establish FIX Initiator application .
acceptor Mode FIX Applications can use SocketAcceptor、SSLSocketAcceptor、ThreadedSocketAcceptor、ThreadedSSLSocketAcceptor establish FIX Acceptor application .
2、FIX signal communication
FIX The application business is realized through initiator And acceptor Build a FIX Session And exchange messages .FIX Business messages have a series of predefined types and formats , The current standard message types are 5、60 individual , The letter covers the transaction 、 The market 、 Settlement and other aspects of investment management .FIX Application development is basically about FIX Message programming .
Fix Session Can be made up of one or more Fix Connection composition , namely Fix Session Can log in multiple times .Fix Session Several important signs are usually used to distinguish , Such as Fix Version number string ( Such as :FIX.4.2), sender ID, The receiver ID,Fix Session Every time a message is sent , The message header BeginString、SenderCompID、TargetCompID Will be assigned . When the message passes FIX When the connection reaches the peer , The peer can find the local side according to the ID in the message header Fix Session To process messages .
FIX The communication parties include Initiator and Acceptor, They will maintain each other 2 Incremental serial numbers ( Send message serial number – Add... For each message sent 1, Receive message sequence number – Add... For each message received 1).
(1) Communication is first and foremost by Initiator Start to initiate TCP Connection request , Acceptor Receive network connection request , establish TCP Connect .
(2)Initiator Initiate login message request .
(3)Acceptor After receiving the login request , After a series of message checks , After being qualified , Return to login confirmation .
(4)Initiator After receiving the login confirmation , After a series of message checks , After being qualified , The two sides FIX Session Successful connection .
(5)Initiator and Acceptor Exchange messages .
(6)Initiator and Acceptor Either party sends an exit message .
3、FIX Session To configure
QuickFix in initiator or acceptor Will maintain multiple Fix Session.QuickFix Use in BeginString(Fix Version number )、SenderCompID、TargetCompID A combination of Session,Session Identification is used to distinguish other different Session.
Session The configuration file contains [DEFAULT] and [SESSION] Two kinds of segmentation ,[SESSION] The subsection represents QuickFix Define a Session,[DEFAULT] Express all Session Configuration items used by default , If not provided QuickFix The required configuration ,QuickFix Will throw out ConfigError abnormal , Indicates that the configuration is missing or the format is incorrect .
If [DEFAULT] and [SESSION] All partitions contain the same configuration items , be [SESSION] The configuration items of the partition will overwrite [DEFAULT] Partition the corresponding configuration items .
QuickFix The configuration file sessions.ini as follows :
[DEFAULT]
ConnectionType=initiator
ReconnectInterval=60
FileLogPath=log
FileStorePath=store
StartTime=00:00:00
EndTime=23:59:59
HeartBtInt=30
ResetOnDisconnect=Y
ResetOnLogout=Y
ResetOnLogon=Y
[SESSION]
BeginString=FIX.4.2
SenderCompID=CLIENT
TargetCompID=SERVER
SocketConnectPort=6666
SocketConnectHost=127.0.0.1
DataDictionary=FIX42.xml
3、 ... and 、QuickFIX Core class
1、FIX::Application
FIX The application needs to implement FIX::Application Interface :
class Application
{
public:
virtual ~Application() {};
/// Notification of a session begin created
virtual void onCreate( const SessionID& ) = 0;
/// Notification of a session successfully logging on
virtual void onLogon( const SessionID& ) = 0;
/// Notification of a session logging off or disconnecting
virtual void onLogout( const SessionID& ) = 0;
/// Notification of admin message being sent to target
virtual void toAdmin( Message&, const SessionID& ) = 0;
/// Notification of app message being sent to target
virtual void toApp( Message&, const SessionID& )
EXCEPT ( DoNotSend ) = 0;
/// Notification of admin message being received from target
virtual void fromAdmin( const Message&, const SessionID& )
EXCEPT ( FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon ) = 0;
/// Notification of app message being received from target
virtual void fromApp( const Message&, const SessionID& )
EXCEPT ( FieldNotFound, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType ) = 0;
};
onCreate: When one Fix Session Call .
onLogon: When one Fix Session When the login succeeds, call .
onLogout: When one Fix Session Call... On exit .
fromAdmin: When you receive a message , After a series of checks , After being qualified , Belong to Admin Called on type .
fromApp: When you receive a message , After a series of checks , After being qualified , Do not belong to Admin Call when type .
toAdmin: When sending a admin Type message call .
toApp: When sending a non admin( Business types ) Message call .
If needed QuickFIX Development FIX application , You need to achieve FIX::Application Interface , And reload different FIX Protocol version MessageCracker::OnMessage Interface , Such as FIX42::MessageCracker.
FIX Businesses are handled asynchronously , The basic object of business processing is message .OnMessage Is the message receiving callback function , There are multiple overloaded versions , Developers only need to overload one FIX Version can .
For those who support trading business FIX Initiator application , Usually you have to rewrite 4 A basic message , namely OnMessage(NewOrderSingle)、OnMessage(CancelRequest)、 OnMessage(ExecutionReport)、 OnMessage(CancelReject), They are used separately for delegation 、 cancel the order 、 Execution return ( Including the rejection of entrustment ) And rejection of cancellation, etc 4 Business .
#include "quickfix/Application.h"
#include "quickfix/MessageCracker.h"
class FIXApplication: public FIX::Application, public FIX::MessageCracker
{
public:
/**************************************************
* reimplementation from Application
* ***********************************************/
/// Notification of a session begin created
virtual void onCreate( const SessionID& )
{
}
/// Notification of a session successfully logging on
virtual void onLogon( const SessionID& )
{
}
/// Notification of a session logging off or disconnecting
virtual void onLogout( const SessionID& )
{
}
/// Notification of admin message being sent to target
virtual void toAdmin( Message&, const SessionID& )
{
}
/// Notification of app message being sent to target
void fromApp( const FIX::Message& message, const FIX::SessionID& sessionID )
throw( FIX::FieldNotFound&, FIX::IncorrectDataFormat&, FIX::IncorrectTagValue&,
FIX::UnsupportedMessageType& )
{
crack(message, sessionID);
}
/// Notification of admin message being received from target
virtual void fromAdmin( const Message&, const SessionID& )
throw ( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue,
FIX::RejectLogon )
{
}
/// Notification of app message being received from target
virtual void fromApp( const Message&, const SessionID& )
throw ( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue,
FIX::UnsupportedMessageType )
{
}
/**************************************************
* reimplementation from FIX42::MessageCracker
* ***********************************************/
virtual void onMessage( const FIX42::NewOrderSingle& message, const FIX::SessionID& )
{
}
virtual void onMessage( const FIX42::OrderCancelRequest& message, const FIX::SessionID& )
{
}
virtual void onMessage( ExecutionReport&, const FIX::SessionID& )
{
}
virtual void onMessage( OrderCancelReject&, const FIX::SessionID& )
{
}
};
2、FIX::SessionSettings
FIX Application configuration uses FIX::SessionSettings Read FIX Session Configure the file and pass it to QuickFIX frame . One FIX Applications can manage multiple FIX Session, Every Session The same... Can be used FIX Protocol version , You can also use different versions . Even if the same FIX Protocol version , Different FIX Session There can also be FIX Differences in agreement details , By binding FIX Session And FIX Protocol dictionary , That is to say Session In profile [Session] Used in configuration items DataDictionary Option specifies the corresponding FIX Dictionary file .
FIX::SessionSettings settings("sessionConfig.ini");
3、FIX::FileStoreFactory
QuickFIX Provides classes for storing messages to files FIX::FileLogFactory. The path of message file storage is Session Specified in configuration .
FIX::FileStoreFactory storeFactory(settings);
4、FIX::MessageStoreFactory
QuickFIX Provide for Fix Session Persistence type ( Such as file storage 、 data storage , The stored contents include status 、 Creation time 、 The message and its own maintained sending sequence number and receiving sequence number ).
If the developer wants to customize the persistence method , You can define yourself MessageStoreFactory Realization , And customize one MessageStore.
5、FIX::FileLogFactory
QuickFIX Provides a class that stores all log events to a file FIX::FileLogFactory.
6、FIX::ScreenLogFactory
QuickFIX A class that displays all message events to standard output is provided in ScreenLogFactory.
FIX::ScreenLogFactory logFactory(settings);
7、FIX::Message
QuickFIX Different... Are defined in FIX Base class for protocol version messages FIX::Message, Used for definition FIX The general structure of messages , Different FIX Message versions of messages are defined in different FIX Namespace , Such as FIX42::Message.FIX::MessageCracker Inherited all the differences FIX Protocol version MessageCracker class , After receiving the message, a specific message is generated FIX agreement Message Object implementation handles messages .
8、FIX::Session
Whether it's FIX Initiator Application or FIX Acceptor application , stay Fix Session On initialization , That is to say FIX::SessionFactory establish Fix Session Will check after Fix Session Time range . If Fix Session Start is not valid for the day Session, Will reset Fix Session Send serial number and receive serial number of .(FIX Specify a Fix Session Generally not more than 24 Hours ).
FIX::Session Some interfaces are defined as follows :
class Session
{
public:
static bool sendToTarget( Message& message,
const std::string& qualifier = "" )
EXCEPT ( SessionNotFound );
static bool sendToTarget( Message& message,
const SessionID& sessionID )
EXCEPT ( SessionNotFound );
static bool sendToTarget( Message&,
const SenderCompID& senderCompID,
const TargetCompID& targetCompID,
const std::string& qualifier = "" )
EXCEPT ( SessionNotFound );
static bool sendToTarget( Message& message,
const std::string& senderCompID,
const std::string& targetCompID,
const std::string& qualifier = "" )
EXCEPT ( SessionNotFound );
bool send( Message& );
void next();
void next( const UtcTimeStamp& timeStamp );
void next( const std::string&, const UtcTimeStamp& timeStamp, bool queued = false );
void next( const Message&, const UtcTimeStamp& timeStamp, bool queued = false );
};
next() Method is a method that runs regularly , It is mainly used to detect whether a heartbeat message needs to be sent , Whether it is necessary to send TEST news , Need to disconnect , Whether it is necessary to produce LOGON(Initiator).
next( const Message&) Method for processing Session received FIX news .
9、FIX::Acceptor
FIX::Acceptor For from Session Configuration file reads information to create and manage this Acceptor Supported by FIX Session, Specifically FIX Session Of TCP Connection management 、 Data reading and writing are performed by specific SocketAcceptor、SSLSocketAcceptor、ThreadedSocketAcceptor、ThreadedSSLSocketAcceptor Realization .
FIX::Acceptor* acceptor = new FIX::SocketAcceptor(application, storeFactory, settings, logFactory);
10、FIX::Initiator
FIX::Initiator For from Session Configuration file reads information to create and manage this Initiator Supported by FIX Session, Specifically FIX Session Of TCP Connection management 、 Data reading and writing are performed by specific SocketInitiator、SSLSocketInitiator、ThreadedSocketInitiator、ThreadedSSLSocketInitiator Realization .
FIX::Initiator * initiator = new FIX::SocketInitiator(application, storeFactory, settings, logFactory);
Four 、FIX Acceptor application development
1、FIX Acceptor Application Introduction
FIX Acceptor Applications are usually used for FIX gateway , Deployed on the seller's side .
2、FIX Acceptor Application creation
(1) establish FIX Session Configuration object
FIX::SessionSettings settings(sessionFile);
(2) establish FIX application :
Application application;
Create a log factory :
LogFactory logFactory(settings);
Create a message store file factory :
FIX::FileStoreFactory storeFactory(settings);
establish Acceptor Server side :
FIX::Acceptor* acceptor = new SocketAcceptor(application, storeFactory, settings, logFactory);
start-up SocketAcceptor:
acceptor->start();
3、FIX Acceptor Application example
Executor The example demonstrates how to receive an order request and return a transaction receipt FIX Acceptor application .
Application.h file :
#ifndef EXECUTOR_APPLICATION_H
#define EXECUTOR_APPLICATION_H
#include "quickfix/Application.h"
#include "quickfix/MessageCracker.h"
#include "quickfix/Values.h"
#include "quickfix/Utility.h"
#include "quickfix/Mutex.h"
#include "quickfix/fix40/NewOrderSingle.h"
#include "quickfix/fix41/NewOrderSingle.h"
#include "quickfix/fix42/NewOrderSingle.h"
#include "quickfix/fix43/NewOrderSingle.h"
#include "quickfix/fix44/NewOrderSingle.h"
#include "quickfix/fix50/NewOrderSingle.h"
class Application
: public FIX::Application, public FIX::MessageCracker
{
public:
Application() : m_orderID(0), m_execID(0) {}
// Application overloads
void onCreate( const FIX::SessionID& );
void onLogon( const FIX::SessionID& sessionID );
void onLogout( const FIX::SessionID& sessionID );
void toAdmin( FIX::Message&, const FIX::SessionID& );
void toApp( FIX::Message&, const FIX::SessionID& )
EXCEPT( FIX::DoNotSend );
void fromAdmin( const FIX::Message&, const FIX::SessionID& )
EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::RejectLogon );
void fromApp( const FIX::Message& message, const FIX::SessionID& sessionID )
EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::UnsupportedMessageType );
// MessageCracker overloads
void onMessage( const FIX40::NewOrderSingle&, const FIX::SessionID& );
void onMessage( const FIX41::NewOrderSingle&, const FIX::SessionID& );
void onMessage( const FIX42::NewOrderSingle&, const FIX::SessionID& );
void onMessage( const FIX43::NewOrderSingle&, const FIX::SessionID& );
void onMessage( const FIX44::NewOrderSingle&, const FIX::SessionID& );
void onMessage( const FIX50::NewOrderSingle&, const FIX::SessionID& );
std::string genOrderID() {
std::stringstream stream;
stream << ++m_orderID;
return stream.str();
}
std::string genExecID() {
std::stringstream stream;
stream << ++m_execID;
return stream.str();
}
private:
int m_orderID, m_execID;
};
#endif
Application.cpp file :
#include "config.h"
#include "Application.h"
#include "quickfix/Session.h"
#include "quickfix/fix40/ExecutionReport.h"
#include "quickfix/fix41/ExecutionReport.h"
#include "quickfix/fix42/ExecutionReport.h"
#include "quickfix/fix43/ExecutionReport.h"
#include "quickfix/fix44/ExecutionReport.h"
#include "quickfix/fix50/ExecutionReport.h"
void Application::onCreate( const FIX::SessionID& sessionID ) {}
void Application::onLogon( const FIX::SessionID& sessionID ) {}
void Application::onLogout( const FIX::SessionID& sessionID ) {}
void Application::toAdmin( FIX::Message& message,
const FIX::SessionID& sessionID ) {}
void Application::toApp( FIX::Message& message,
const FIX::SessionID& sessionID )
EXCEPT( FIX::DoNotSend ) {}
void Application::fromAdmin( const FIX::Message& message,
const FIX::SessionID& sessionID )
EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::RejectLogon ) {}
void Application::fromApp( const FIX::Message& message,
const FIX::SessionID& sessionID )
EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::UnsupportedMessageType )
{ crack( message, sessionID ); }
void Application::onMessage( const FIX40::NewOrderSingle& message,
const FIX::SessionID& sessionID )
{
FIX::Symbol symbol;
FIX::Side side;
FIX::OrdType ordType;
FIX::OrderQty orderQty;
FIX::Price price;
FIX::ClOrdID clOrdID;
FIX::Account account;
message.get( ordType );
if ( ordType != FIX::OrdType_LIMIT )
throw FIX::IncorrectTagValue( ordType.getField() );
message.get( symbol );
message.get( side );
message.get( orderQty );
message.get( price );
message.get( clOrdID );
FIX40::ExecutionReport executionReport = FIX40::ExecutionReport
( FIX::OrderID( genOrderID() ),
FIX::ExecID( genExecID() ),
FIX::ExecTransType( FIX::ExecTransType_NEW ),
FIX::OrdStatus( FIX::OrdStatus_FILLED ),
symbol,
side,
orderQty,
FIX::LastShares( orderQty ),
FIX::LastPx( price ),
FIX::CumQty( orderQty ),
FIX::AvgPx( price ) );
executionReport.set( clOrdID );
if( message.isSet(account) )
executionReport.setField( message.get(account) );
try
{
FIX::Session::sendToTarget( executionReport, sessionID );
}
catch ( FIX::SessionNotFound& ) {}
}
void Application::onMessage( const FIX41::NewOrderSingle& message,
const FIX::SessionID& sessionID )
{
FIX::Symbol symbol;
FIX::Side side;
FIX::OrdType ordType;
FIX::OrderQty orderQty;
FIX::Price price;
FIX::ClOrdID clOrdID;
FIX::Account account;
message.get( ordType );
if ( ordType != FIX::OrdType_LIMIT )
throw FIX::IncorrectTagValue( ordType.getField() );
message.get( symbol );
message.get( side );
message.get( orderQty );
message.get( price );
message.get( clOrdID );
FIX41::ExecutionReport executionReport = FIX41::ExecutionReport
( FIX::OrderID( genOrderID() ),
FIX::ExecID( genExecID() ),
FIX::ExecTransType( FIX::ExecTransType_NEW ),
FIX::ExecType( FIX::ExecType_FILL ),
FIX::OrdStatus( FIX::OrdStatus_FILLED ),
symbol,
side,
orderQty,
FIX::LastShares( orderQty ),
FIX::LastPx( price ),
FIX::LeavesQty( 0 ),
FIX::CumQty( orderQty ),
FIX::AvgPx( price ) );
executionReport.set( clOrdID );
if( message.isSet(account) )
executionReport.setField( message.get(account) );
try
{
FIX::Session::sendToTarget( executionReport, sessionID );
}
catch ( FIX::SessionNotFound& ) {}
}
void Application::onMessage( const FIX42::NewOrderSingle& message,
const FIX::SessionID& sessionID )
{
FIX::Symbol symbol;
FIX::Side side;
FIX::OrdType ordType;
FIX::OrderQty orderQty;
FIX::Price price;
FIX::ClOrdID clOrdID;
FIX::Account account;
message.get( ordType );
if ( ordType != FIX::OrdType_LIMIT )
throw FIX::IncorrectTagValue( ordType.getField() );
message.get( symbol );
message.get( side );
message.get( orderQty );
message.get( price );
message.get( clOrdID );
FIX42::ExecutionReport executionReport = FIX42::ExecutionReport
( FIX::OrderID( genOrderID() ),
FIX::ExecID( genExecID() ),
FIX::ExecTransType( FIX::ExecTransType_NEW ),
FIX::ExecType( FIX::ExecType_FILL ),
FIX::OrdStatus( FIX::OrdStatus_FILLED ),
symbol,
side,
FIX::LeavesQty( 0 ),
FIX::CumQty( orderQty ),
FIX::AvgPx( price ) );
executionReport.set( clOrdID );
executionReport.set( orderQty );
executionReport.set( FIX::LastShares( orderQty ) );
executionReport.set( FIX::LastPx( price ) );
if( message.isSet(account) )
executionReport.setField( message.get(account) );
try
{
FIX::Session::sendToTarget( executionReport, sessionID );
}
catch ( FIX::SessionNotFound& ) {}
}
void Application::onMessage( const FIX43::NewOrderSingle& message,
const FIX::SessionID& sessionID )
{
FIX::Symbol symbol;
FIX::Side side;
FIX::OrdType ordType;
FIX::OrderQty orderQty;
FIX::Price price;
FIX::ClOrdID clOrdID;
FIX::Account account;
message.get( ordType );
if ( ordType != FIX::OrdType_LIMIT )
throw FIX::IncorrectTagValue( ordType.getField() );
message.get( symbol );
message.get( side );
message.get( orderQty );
message.get( price );
message.get( clOrdID );
FIX43::ExecutionReport executionReport = FIX43::ExecutionReport
( FIX::OrderID( genOrderID() ),
FIX::ExecID( genExecID() ),
FIX::ExecType( FIX::ExecType_FILL ),
FIX::OrdStatus( FIX::OrdStatus_FILLED ),
side,
FIX::LeavesQty( 0 ),
FIX::CumQty( orderQty ),
FIX::AvgPx( price ) );
executionReport.set( clOrdID );
executionReport.set( symbol );
executionReport.set( orderQty );
executionReport.set( FIX::LastQty( orderQty ) );
executionReport.set( FIX::LastPx( price ) );
if( message.isSet(account) )
executionReport.setField( message.get(account) );
try
{
FIX::Session::sendToTarget( executionReport, sessionID );
}
catch ( FIX::SessionNotFound& ) {}
}
void Application::onMessage( const FIX44::NewOrderSingle& message,
const FIX::SessionID& sessionID )
{
FIX::Symbol symbol;
FIX::Side side;
FIX::OrdType ordType;
FIX::OrderQty orderQty;
FIX::Price price;
FIX::ClOrdID clOrdID;
FIX::Account account;
message.get( ordType );
if ( ordType != FIX::OrdType_LIMIT )
throw FIX::IncorrectTagValue( ordType.getField() );
message.get( symbol );
message.get( side );
message.get( orderQty );
message.get( price );
message.get( clOrdID );
FIX44::ExecutionReport executionReport = FIX44::ExecutionReport
( FIX::OrderID( genOrderID() ),
FIX::ExecID( genExecID() ),
FIX::ExecType( FIX::ExecType_TRADE ),
FIX::OrdStatus( FIX::OrdStatus_FILLED ),
side,
FIX::LeavesQty( 0 ),
FIX::CumQty( orderQty ),
FIX::AvgPx( price ) );
executionReport.set( clOrdID );
executionReport.set( symbol );
executionReport.set( orderQty );
executionReport.set( FIX::LastQty( orderQty ) );
executionReport.set( FIX::LastPx( price ) );
if( message.isSet(account) )
executionReport.setField( message.get(account) );
try
{
FIX::Session::sendToTarget( executionReport, sessionID );
}
catch ( FIX::SessionNotFound& ) {}
}
void Application::onMessage( const FIX50::NewOrderSingle& message,
const FIX::SessionID& sessionID )
{
FIX::Symbol symbol;
FIX::Side side;
FIX::OrdType ordType;
FIX::OrderQty orderQty;
FIX::Price price;
FIX::ClOrdID clOrdID;
FIX::Account account;
message.get( ordType );
if ( ordType != FIX::OrdType_LIMIT )
throw FIX::IncorrectTagValue( ordType.getField() );
message.get( symbol );
message.get( side );
message.get( orderQty );
message.get( price );
message.get( clOrdID );
FIX50::ExecutionReport executionReport = FIX50::ExecutionReport
( FIX::OrderID( genOrderID() ),
FIX::ExecID( genExecID() ),
FIX::ExecType( FIX::ExecType_TRADE ),
FIX::OrdStatus( FIX::OrdStatus_FILLED ),
side,
FIX::LeavesQty( 0 ),
FIX::CumQty( orderQty ) );
executionReport.set( clOrdID );
executionReport.set( symbol );
executionReport.set( orderQty );
executionReport.set( FIX::LastQty( orderQty ) );
executionReport.set( FIX::LastPx( price ) );
executionReport.set( FIX::AvgPx( price ) );
if( message.isSet(account) )
executionReport.setField( message.get(account) );
try
{
FIX::Session::sendToTarget( executionReport, sessionID );
}
catch ( FIX::SessionNotFound& ) {}
}
main.cpp file :
#include "config.h"
#include "quickfix/FileStore.h"
#include "quickfix/SocketAcceptor.h"
#include "quickfix/Log.h"
#include "quickfix/SessionSettings.h"
#include "Application.h"
#include <string>
#include <iostream>
#include <fstream>
void wait()
{
std::cout << "Type Ctrl-C to quit" << std::endl;
while(true)
{
FIX::process_sleep(1);
}
}
int main( int argc, char** argv )
{
if ( argc < 2 )
{
std::cout << "usage: " << argv[ 0 ]
<< " FILE." << std::endl;
return 0;
}
std::string file = argv[ 1 ];
FIX::Acceptor * acceptor = 0;
try
{
FIX::SessionSettings settings( file );
Application application;
FIX::FileStoreFactory storeFactory( settings );
FIX::ScreenLogFactory logFactory( settings );
acceptor = new FIX::SocketAcceptor ( application, storeFactory, settings, logFactory );
acceptor->start();
wait();
acceptor->stop();
delete acceptor;
return 0;
}
catch ( std::exception & e )
{
std::cout << e.what() << std::endl;
delete acceptor;
return 1;
}
}
5、 ... and 、FIX Initiator application development
1、FIX Initiator Application Introduction
FIX Initiator Applications are usually used for trading clients , Deployed on the buyer's side .
2、FIX Initiator Application creation
(1) establish FIX Session Configuration object
FIX::SessionSettings settings(sessionFile);
(2) establish FIX application :
Application application;
Create a log factory :
LogFactory logFactory(settings);
Create a message store file factory :
FIX::FileStoreFactory storeFactory(settings);
establish Acceptor Server side :
FIX::Initiator* client= new SocketInitiator(application, storeFactory,settings, logFactory);
start-up SocketInitiator:
client->start();
3、FIX Initiator Application example
tradeclient Trading Client
Application.h file :
#ifndef TRADECLIENT_APPLICATION_H
#define TRADECLIENT_APPLICATION_H
#include "quickfix/Application.h"
#include "quickfix/MessageCracker.h"
#include "quickfix/Values.h"
#include "quickfix/Mutex.h"
#include "quickfix/fix40/NewOrderSingle.h"
#include "quickfix/fix40/ExecutionReport.h"
#include "quickfix/fix40/OrderCancelRequest.h"
#include "quickfix/fix40/OrderCancelReject.h"
#include "quickfix/fix40/OrderCancelReplaceRequest.h"
#include "quickfix/fix41/NewOrderSingle.h"
#include "quickfix/fix41/ExecutionReport.h"
#include "quickfix/fix41/OrderCancelRequest.h"
#include "quickfix/fix41/OrderCancelReject.h"
#include "quickfix/fix41/OrderCancelReplaceRequest.h"
#include "quickfix/fix42/NewOrderSingle.h"
#include "quickfix/fix42/ExecutionReport.h"
#include "quickfix/fix42/OrderCancelRequest.h"
#include "quickfix/fix42/OrderCancelReject.h"
#include "quickfix/fix42/OrderCancelReplaceRequest.h"
#include "quickfix/fix43/NewOrderSingle.h"
#include "quickfix/fix43/ExecutionReport.h"
#include "quickfix/fix43/OrderCancelRequest.h"
#include "quickfix/fix43/OrderCancelReject.h"
#include "quickfix/fix43/OrderCancelReplaceRequest.h"
#include "quickfix/fix43/MarketDataRequest.h"
#include "quickfix/fix44/NewOrderSingle.h"
#include "quickfix/fix44/ExecutionReport.h"
#include "quickfix/fix44/OrderCancelRequest.h"
#include "quickfix/fix44/OrderCancelReject.h"
#include "quickfix/fix44/OrderCancelReplaceRequest.h"
#include "quickfix/fix44/MarketDataRequest.h"
#include "quickfix/fix50/NewOrderSingle.h"
#include "quickfix/fix50/ExecutionReport.h"
#include "quickfix/fix50/OrderCancelRequest.h"
#include "quickfix/fix50/OrderCancelReject.h"
#include "quickfix/fix50/OrderCancelReplaceRequest.h"
#include "quickfix/fix50/MarketDataRequest.h"
#include <queue>
class Application :
public FIX::Application,
public FIX::MessageCracker
{
public:
void run();
private:
void onCreate( const FIX::SessionID& ) {}
void onLogon( const FIX::SessionID& sessionID );
void onLogout( const FIX::SessionID& sessionID );
void toAdmin( FIX::Message&, const FIX::SessionID& ) {}
void toApp( FIX::Message&, const FIX::SessionID& )
EXCEPT( FIX::DoNotSend );
void fromAdmin( const FIX::Message&, const FIX::SessionID& )
EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::RejectLogon ) {}
void fromApp( const FIX::Message& message, const FIX::SessionID& sessionID )
EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::UnsupportedMessageType );
void onMessage( const FIX42::ExecutionReport&, const FIX::SessionID& );
void onMessage( const FIX42::OrderCancelReject&, const FIX::SessionID& );
void queryEnterOrder();
void queryCancelOrder();
void queryReplaceOrder();
FIX42::NewOrderSingle queryNewOrderSingle42();
FIX42::OrderCancelRequest queryOrderCancelRequest42();
FIX42::OrderCancelReplaceRequest queryCancelReplaceRequest42();
void queryHeader( FIX::Header& header );
char queryAction();
int queryVersion();
bool queryConfirm( const std::string& query );
FIX::SenderCompID querySenderCompID();
FIX::TargetCompID queryTargetCompID();
FIX::TargetSubID queryTargetSubID();
FIX::ClOrdID queryClOrdID();
FIX::OrigClOrdID queryOrigClOrdID();
FIX::Symbol querySymbol();
FIX::Side querySide();
FIX::OrderQty queryOrderQty();
FIX::OrdType queryOrdType();
FIX::Price queryPrice();
FIX::StopPx queryStopPx();
FIX::TimeInForce queryTimeInForce();
};
#endif
Application.cpp file :
#include "config.h"
#include "Application.h"
#include "quickfix/Session.h"
#include <iostream>
void Application::onLogon( const FIX::SessionID& sessionID )
{
std::cout << std::endl << "Logon - " << sessionID << std::endl;
}
void Application::onLogout( const FIX::SessionID& sessionID )
{
std::cout << std::endl << "Logout - " << sessionID << std::endl;
}
void Application::fromApp( const FIX::Message& message, const FIX::SessionID& sessionID )
EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::UnsupportedMessageType )
{
crack( message, sessionID );
std::cout << std::endl << "IN: " << message << std::endl;
}
void Application::toApp( FIX::Message& message, const FIX::SessionID& sessionID )
EXCEPT( FIX::DoNotSend )
{
try
{
FIX::PossDupFlag possDupFlag;
message.getHeader().getField( possDupFlag );
if ( possDupFlag ) throw FIX::DoNotSend();
}
catch ( FIX::FieldNotFound& ) {}
std::cout << std::endl
<< "OUT: " << message << std::endl;
}
void Application::onMessage
( const FIX42::ExecutionReport&, const FIX::SessionID& ) {}
void Application::onMessage
( const FIX42::OrderCancelReject&, const FIX::SessionID& ) {}
void Application::run()
{
while ( true )
{
try
{
char action = queryAction();
if ( action == '1' )
queryEnterOrder();
else if ( action == '2' )
queryCancelOrder();
else if ( action == '3' )
queryReplaceOrder();
else if ( action == '5' )
break;
}
catch ( std::exception & e )
{
std::cout << "Message Not Sent: " << e.what();
}
}
}
void Application::queryEnterOrder()
{
int version = queryVersion();
std::cout << "\nNewOrderSingle\n";
FIX::Message order;
switch ( version ) {
case 42:
order = queryNewOrderSingle42();
break;
default:
std::cerr << "No test for version " << version << std::endl;
break;
}
if ( queryConfirm( "Send order" ) )
FIX::Session::sendToTarget( order );
}
void Application::queryCancelOrder()
{
int version = queryVersion();
std::cout << "\nOrderCancelRequest\n";
FIX::Message cancel;
switch ( version ) {
case 42:
cancel = queryOrderCancelRequest42();
break;
default:
std::cerr << "No test for version " << version << std::endl;
break;
}
if ( queryConfirm( "Send cancel" ) )
FIX::Session::sendToTarget( cancel );
}
void Application::queryReplaceOrder()
{
int version = queryVersion();
std::cout << "\nCancelReplaceRequest\n";
FIX::Message replace;
switch ( version ) {
case 42:
replace = queryCancelReplaceRequest42();
break;
default:
std::cerr << "No test for version " << version << std::endl;
break;
}
if ( queryConfirm( "Send replace" ) )
FIX::Session::sendToTarget( replace );
}
FIX42::NewOrderSingle Application::queryNewOrderSingle42()
{
FIX::OrdType ordType;
FIX42::NewOrderSingle newOrderSingle(
queryClOrdID(), FIX::HandlInst( '1' ), querySymbol(), querySide(),
FIX::TransactTime(), ordType = queryOrdType() );
newOrderSingle.set( queryOrderQty() );
newOrderSingle.set( queryTimeInForce() );
if ( ordType == FIX::OrdType_LIMIT || ordType == FIX::OrdType_STOP_LIMIT )
newOrderSingle.set( queryPrice() );
if ( ordType == FIX::OrdType_STOP || ordType == FIX::OrdType_STOP_LIMIT )
newOrderSingle.set( queryStopPx() );
queryHeader( newOrderSingle.getHeader() );
return newOrderSingle;
}
FIX42::OrderCancelRequest Application::queryOrderCancelRequest42()
{
FIX42::OrderCancelRequest orderCancelRequest( queryOrigClOrdID(),
queryClOrdID(), querySymbol(), querySide(), FIX::TransactTime() );
orderCancelRequest.set( queryOrderQty() );
queryHeader( orderCancelRequest.getHeader() );
return orderCancelRequest;
}
FIX42::OrderCancelReplaceRequest Application::queryCancelReplaceRequest42()
{
FIX42::OrderCancelReplaceRequest cancelReplaceRequest(
queryOrigClOrdID(), queryClOrdID(), FIX::HandlInst( '1' ),
querySymbol(), querySide(), FIX::TransactTime(), queryOrdType() );
if ( queryConfirm( "New price" ) )
cancelReplaceRequest.set( queryPrice() );
if ( queryConfirm( "New quantity" ) )
cancelReplaceRequest.set( queryOrderQty() );
queryHeader( cancelReplaceRequest.getHeader() );
return cancelReplaceRequest;
}
void Application::queryHeader( FIX::Header& header )
{
header.setField( querySenderCompID() );
header.setField( queryTargetCompID() );
if ( queryConfirm( "Use a TargetSubID" ) )
header.setField( queryTargetSubID() );
}
char Application::queryAction()
{
char value;
std::cout << std::endl
<< "1) Enter Order" << std::endl
<< "2) Cancel Order" << std::endl
<< "3) Replace Order" << std::endl
<< "4) Market data test" << std::endl
<< "5) Quit" << std::endl
<< "Action: ";
std::cin >> value;
switch ( value )
{
case '1': case '2': case '3': case '4': case '5': break;
default: throw std::exception();
}
return value;
}
int Application::queryVersion()
{
char value;
std::cout << std::endl
<< "1) FIX.4.0" << std::endl
<< "2) FIX.4.1" << std::endl
<< "3) FIX.4.2" << std::endl
<< "4) FIX.4.3" << std::endl
<< "5) FIX.4.4" << std::endl
<< "6) FIXT.1.1 (FIX.5.0)" << std::endl
<< "BeginString: ";
std::cin >> value;
switch ( value )
{
case '1': return 40;
case '2': return 41;
case '3': return 42;
case '4': return 43;
case '5': return 44;
case '6': return 50;
default: throw std::exception();
}
}
bool Application::queryConfirm( const std::string& query )
{
std::string value;
std::cout << std::endl << query << "?: ";
std::cin >> value;
return toupper( *value.c_str() ) == 'Y';
}
FIX::SenderCompID Application::querySenderCompID()
{
std::string value;
std::cout << std::endl << "SenderCompID: ";
std::cin >> value;
return FIX::SenderCompID( value );
}
FIX::TargetCompID Application::queryTargetCompID()
{
std::string value;
std::cout << std::endl << "TargetCompID: ";
std::cin >> value;
return FIX::TargetCompID( value );
}
FIX::TargetSubID Application::queryTargetSubID()
{
std::string value;
std::cout << std::endl << "TargetSubID: ";
std::cin >> value;
return FIX::TargetSubID( value );
}
FIX::ClOrdID Application::queryClOrdID()
{
std::string value;
std::cout << std::endl << "ClOrdID: ";
std::cin >> value;
return FIX::ClOrdID( value );
}
FIX::OrigClOrdID Application::queryOrigClOrdID()
{
std::string value;
std::cout << std::endl << "OrigClOrdID: ";
std::cin >> value;
return FIX::OrigClOrdID( value );
}
FIX::Symbol Application::querySymbol()
{
std::string value;
std::cout << std::endl << "Symbol: ";
std::cin >> value;
return FIX::Symbol( value );
}
FIX::Side Application::querySide()
{
char value;
std::cout << std::endl
<< "1) Buy" << std::endl
<< "2) Sell" << std::endl
<< "3) Sell Short" << std::endl
<< "4) Sell Short Exempt" << std::endl
<< "5) Cross" << std::endl
<< "6) Cross Short" << std::endl
<< "7) Cross Short Exempt" << std::endl
<< "Side: ";
std::cin >> value;
switch ( value )
{
case '1': return FIX::Side( FIX::Side_BUY );
case '2': return FIX::Side( FIX::Side_SELL );
case '3': return FIX::Side( FIX::Side_SELL_SHORT );
case '4': return FIX::Side( FIX::Side_SELL_SHORT_EXEMPT );
case '5': return FIX::Side( FIX::Side_CROSS );
case '6': return FIX::Side( FIX::Side_CROSS_SHORT );
case '7': return FIX::Side( 'A' );
default: throw std::exception();
}
}
FIX::OrderQty Application::queryOrderQty()
{
long value;
std::cout << std::endl << "OrderQty: ";
std::cin >> value;
return FIX::OrderQty( value );
}
FIX::OrdType Application::queryOrdType()
{
char value;
std::cout << std::endl
<< "1) Market" << std::endl
<< "2) Limit" << std::endl
<< "3) Stop" << std::endl
<< "4) Stop Limit" << std::endl
<< "OrdType: ";
std::cin >> value;
switch ( value )
{
case '1': return FIX::OrdType( FIX::OrdType_MARKET );
case '2': return FIX::OrdType( FIX::OrdType_LIMIT );
case '3': return FIX::OrdType( FIX::OrdType_STOP );
case '4': return FIX::OrdType( FIX::OrdType_STOP_LIMIT );
default: throw std::exception();
}
}
FIX::Price Application::queryPrice()
{
double value;
std::cout << std::endl << "Price: ";
std::cin >> value;
return FIX::Price( value );
}
FIX::StopPx Application::queryStopPx()
{
double value;
std::cout << std::endl << "StopPx: ";
std::cin >> value;
return FIX::StopPx( value );
}
FIX::TimeInForce Application::queryTimeInForce()
{
char value;
std::cout << std::endl
<< "1) Day" << std::endl
<< "2) IOC" << std::endl
<< "3) OPG" << std::endl
<< "4) GTC" << std::endl
<< "5) GTX" << std::endl
<< "TimeInForce: ";
std::cin >> value;
switch ( value )
{
case '1': return FIX::TimeInForce( FIX::TimeInForce_DAY );
case '2': return FIX::TimeInForce( FIX::TimeInForce_IMMEDIATE_OR_CANCEL );
case '3': return FIX::TimeInForce( FIX::TimeInForce_AT_THE_OPENING );
case '4': return FIX::TimeInForce( FIX::TimeInForce_GOOD_TILL_CANCEL );
case '5': return FIX::TimeInForce( FIX::TimeInForce_GOOD_TILL_CROSSING );
default: throw std::exception();
}
}
main.cpp file :
#include "config.h"
#include "quickfix/FileStore.h"
#include "quickfix/SocketInitiator.h"
#include "quickfix/SessionSettings.h"
#include "quickfix/Log.h"
#include "Application.h"
#include <string>
#include <iostream>
#include <fstream>
int main( int argc, char** argv )
{
if ( argc < 2 )
{
std::cout << "usage: " << argv[ 0 ]
<< " FILE." << std::endl;
return 0;
}
std::string file = argv[ 1 ];
FIX::Initiator * initiator = 0;
try
{
FIX::SessionSettings settings( file );
Application application;
FIX::FileStoreFactory storeFactory( settings );
FIX::ScreenLogFactory logFactory( settings );
initiator = new FIX::SocketInitiator( application, storeFactory, settings, logFactory );
initiator->start();
application.run();
initiator->stop();
delete initiator;
return 0;
}
catch ( std::exception & e )
{
std::cout << e.what();
delete initiator;
return 1;
}
}
边栏推荐
- Cesium 拖拽3D模型
- Amazon's other side in China
- Work assessment of pharmacotherapeutics of Jilin University in March of the 22nd spring -00064
- uniapp 制作手机app程序, 使用uni.chooseVideo录制视频,视频播放模糊分辨率低的原因
- 冷热酸甜、想成就成?冷酸灵母公司登康口腔欲在深交所主板上市
- Development of trading system (V) -- Introduction to Sinovel counter
- Maintenant, les oreilles vont entrer dans le métacosme.
- Lao Ye's blessing
- Work assessment of pharmaceutical polymer materials of Jilin University in March of the 22nd spring -00025
- IE寿终正寝,网友们搞起了真·墓碑……
猜你喜欢
Development of trading system (V) -- Introduction to Sinovel counter
程序员真人秀又来了!呼兰当主持挑灯狂补知识,SSS大佬本科竟是药学,清华朱军张敏等加入导师团...
Sun Wu plays Warcraft? There is a picture and a truth
Xidian AI ranked higher than Qingbei in terms of AI majors, and Nantah ranked the first in China in 2022 in terms of soft science majors
Lu Qi invests in quantum computing for the first time
Intel 13代酷睿首次露出真面目:68MB缓存提升明显
Sleep more, you can lose weight. According to the latest research from the University of Chicago, sleeping more than 1 hour a day is equivalent to eating less than one fried chicken leg
China's SkyEye found suspicious signals of extraterrestrial civilization. Musk said that the Starship began its orbital test flight in July. Netinfo office: app should not force users to agree to proc
Trading system development (IV) - trading counter system
Tensorflow, danger! Google itself is the one who abandoned it
随机推荐
Monitoring pancakeswap new token
Configuration source code
如何使用IDE自动签名调试鸿蒙应用
Maintenant, les oreilles vont entrer dans le métacosme.
Wechat development related
佐喃社区
Serious PHP defects can lead to rce attacks on QNAP NAS devices
Work assessment of Biopharmaceutics of Jilin University in March of the 22nd spring -00031
北大换新校长!中国科学院院士龚旗煌接任,15岁考上北大物理系
JS tool function, self encapsulating a throttling function
x86 CPU,危!最新漏洞引发热议,黑客可远程窃取密钥,英特尔“全部处理器”受影响...
DevEco Studio 3.0编辑器配置技巧篇
Standing at the center of the storm: how to change the engine of Tencent
Break the memory wall with CPU scheme? Learn from PayPal stack to expand capacity, and the volume of missed fraud transactions can be reduced to 1/30
The more AI evolves, the more it resembles the human brain! Meta found the "prefrontal cortex" of the machine. AI scholars and neuroscientists were surprised
香蕉为什么能做随机数生成器?因为,它是水果界的“辐射之王”
【Harmony OS】【ArkUI】ets开发 图形与动画绘制
Interview with Mo Tianlun | ivorysql wangzhibin - ivorysql, an Oracle compatible open source database based on PostgreSQL
马斯克:推特要学习微信,让10亿人「活在上面」成为超级APP
Redis related-03