标签:cpp logo ndis cross 通信 gen ros gety 版本号
交易系统开发(十一)——QuickFIX简介QuickFIX是一款C++实现的开源FIX引擎,同时提供Python、Ruby语言实现。
QuickFIX官网:
http://www.quickfixengine.org
Github地址:
https://github.com/quickfix/quickfix
编译选项配置:
configure
编译:
make
检查:
make check
安装:
sudo make install
FIX应用有initiator和acceptor两种模式。
initiator是TCP连接的发起方,acceptor是TCP连接监听方。标准FIX应用(如CTS FIX网关)可以同时支持initiator和acceptor两种模式,既可以发起连接,也可以接受连接请求。
开发FIX应用时,需要先确定FIX应用模式,然后选择对应的QuickFIX类对象。
initiator模式的FIX应用可以使用SocketInitiator、SSLSocketInitiator、ThreadedSocketInitiator、ThreadedSSLSocketInitiator创建FIX Initiator应用。
acceptor模式的FIX应用可以使用SocketAcceptor、SSLSocketAcceptor、ThreadedSocketAcceptor、ThreadedSSLSocketAcceptor创建FIX Acceptor应用。
FIX应用业务是通过在initiator与acceptor间建立一个FIX Session并交换消息来进行的。FIX业务消息有一系列预定义类型与格式,目前标准的消息类型有5、60个,函盖了交易、行情、结算等投资管理的各个环节。FIX应用开发基本上是对FIX消息的编程。
Fix Session可以由一个或多个Fix连接组成,即Fix Session可以多次登陆。Fix Session通常使用几个重要标识区分,如Fix版本号字符串(如:FIX.4.2),发送者ID,接收者ID,Fix Session每发送一条消息时,消息头的BeginString、SenderCompID、TargetCompID都会被赋值。当消息通过FIX连接到达对等方时,对等方可以根据消息头中的的标识找到本地端的Fix Session去处理消息。
FIX通信双方包括Initiator和Acceptor,会各自维护2个递增的序列号(发送消息序列号–每发送一个消息加1,接收消息序列号–每收到一个消息加1)。
(1)通信首先由Initiator开始发起TCP连接请求, Acceptor接收网络连接请求,建立TCP连接。
(2)Initiator发起登录消息请求。
(3)Acceptor收到登录请求后,经过一系列消息检查,合格后,返回登录确认。
(4)Initiator收到登录确认后,经过一系列消息检查,合格后,双方FIX Session连接成功。
(5)Initiator和Acceptor交换消息。
(6)Initiator和Acceptor任何一方发出退出消息。
QuickFix中initiator或acceptor会维护多个Fix Session。QuickFix中使用BeginString(Fix版本号)、SenderCompID、TargetCompID的组合标识一个Session,Session标识用于区分其它不同的Session。
Session配置文件包含[DEFAULT]和[SESSION]两种分节,[SESSION]分节表示QuickFix中定义一个Session,[DEFAULT]表示所有Session默认使用的配置项,如果不提供QuickFix所需的配置,QuickFix会抛出ConfigError异常,表示配置缺失或格式不正确。
如果[DEFAULT]和[SESSION]分区中都包含相同的配置项,则[SESSION]分区的配置项会覆盖[DEFAULT]分区相应的配置项。
QuickFix配置文件sessions.ini如下:
[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
FIX应用需要实现FIX::Application接口:
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:当一个Fix Session建立时调用。
onLogon:当一个Fix Session登录成功时调用。
onLogout:当一个Fix Session退出时调用。
fromAdmin:当收到一个消息,经过一系列检查,合格后,属于Admin类型时调用。
fromApp:当收到一个消息,经过一系列检查,合格后,不属于Admin 类型时候调用。
toAdmin:当发送一个admin类型消息调用。
toApp:当发送一个非admin(业务类型)消息调用。
如果需要使用QuickFIX开发FIX应用,则需要实现FIX::Application接口,并重载不同FIX协议版本的MessageCracker::OnMessage接口,如FIX42::MessageCracker。
FIX业务都是异步方式处理的,而业务处理的基本对象是消息。OnMessage是消息接收回调函数,有多个重载版本,开发者只需要使重载一个FIX版本即可。
对于支持交易业务的FIX Initiator应用,通常要重写4个基本消息,即OnMessage(NewOrderSingle)、OnMessage(CancelRequest)、 OnMessage(ExecutionReport)、 OnMessage(CancelReject),分别用于做委托、撤单、执行回报(包括对委托的拒绝)和对撤单的拒绝等4项业务。
#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& )
{
}
};
FIX应用配置使用FIX::SessionSettings读取FIX Session配置文件并传递给QuickFIX框架。一个FIX应用可以管理多个FIX Session,每个Session可以采用相同的FIX协议版本,也可以采用不同的版本。即使采用的是相同的FIX协议版本,不同FIX Session间也可以有FIX协议细节的差异,通过绑定FIX Session与FIX协议字典的方式来实现,即在Session配置文件中[Session]配置项中使用DataDictionary选项指定相应FIX字典文件来实现。FIX::SessionSettings settings("sessionConfig.ini");
QuickFIX提供了存储消息到文件的类FIX::FileLogFactory。消息文件存储的路径在Session配置中指定。FIX::FileStoreFactory storeFactory(settings);
QuickFIX提供了给Fix Session持久化类型(如文件存储、数据存储,存储内容包括状态、创建时间、消息及其自己维护的发送序列号和接收序列号等)。
如果开发者要自定义持久化方式,可以自己定义MessageStoreFactory实现,并且自定义一种MessageStore。
QuickFIX提供了存储所有日志事件到文件的类FIX::FileLogFactory。
QuickFIX中提供了显示所有消息事件到标准输出的类ScreenLogFactory。FIX::ScreenLogFactory logFactory(settings);
QuickFIX中定义了不同FIX协议版本消息的基类FIX::Message,用于定义FIX消息的通用结构,不同的FIX消息版本的消息定义在不同的FIX命名空间内定义,如FIX42::Message。FIX::MessageCracker则继承了所有不同FIX协议版本的MessageCracker类,接收消息后生成具体FIX协议Message对象实现对消息进行处理。
无论是FIX Initiator应用还是FIX Acceptor应用,在Fix Session初始化时,即在FIX::SessionFactory创建Fix Session后都会检查Fix Session时间范围。如果Fix Session启动不是当天有效的Session,则会重置Fix Session的发送序列号和接收序列号。(FIX规定一个Fix Session一般不超过24小时)。
FIX::Session部分接口定义如下:
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()方法是定时运行的一个方法,主要用于检测是否需要发心跳消息,是否需要发TEST消息,是否需要断开连接,是否需要产生LOGON(Initiator)。
next( const Message&)方法用于处理Session收到的FIX消息。
FIX::Acceptor用于从Session配置文件读取信息创建和管理本Acceptor支持的FIX Session,具体FIX Session的TCP连接管理、数据读写由具体的SocketAcceptor、SSLSocketAcceptor、ThreadedSocketAcceptor、ThreadedSSLSocketAcceptor实现。FIX::Acceptor* acceptor = new FIX::SocketAcceptor(application, storeFactory, settings, logFactory);
FIX::Initiator用于从Session配置文件读取信息创建和管理本Initiator支持的FIX Session,具体FIX Session的TCP连接管理、数据读写由具体的SocketInitiator、SSLSocketInitiator、ThreadedSocketInitiator、ThreadedSSLSocketInitiator实现。FIX::Initiator * initiator = new FIX::SocketInitiator(application, storeFactory, settings, logFactory);
FIX Acceptor应用通常用于FIX网关,部署在卖方侧。
(1)创建FIX Session配置对象FIX::SessionSettings settings(sessionFile);
(2)创建FIX应用:Application application;
创建日志工厂:LogFactory logFactory(settings);
创建消息存储文件工厂:FIX::FileStoreFactory storeFactory(settings);
创建Acceptor服务端:FIX::Acceptor* acceptor = new SocketAcceptor(application, storeFactory, settings, logFactory);
启动SocketAcceptor:acceptor->start();
Executor示例演示了接收订单请求并返回成交回执的FIX Acceptor应用。
Application.h文件:
#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文件:
#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文件:
#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;
}
}
FIX Initiator应用通常用于交易客户端,部署在买方侧。
(1)创建FIX Session配置对象FIX::SessionSettings settings(sessionFile);
(2)创建FIX应用:Application application;
创建日志工厂:LogFactory logFactory(settings);
创建消息存储文件工厂:FIX::FileStoreFactory storeFactory(settings);
创建Acceptor服务端:FIX::Initiator* client= new SocketInitiator(application, storeFactory,settings, logFactory);
启动SocketInitiator:client->start();
tradeclient交易客户端
Application.h文件:
#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文件:
#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文件:
#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;
}
}
标签:cpp logo ndis cross 通信 gen ros gety 版本号
原文地址:https://blog.51cto.com/9291927/2536108