交易系统开发(十一)——QuickFIX简介
一、QuickFIX簡(jiǎn)介
1、QuickFIX簡(jiǎn)介
QuickFIX是一款C++實(shí)現(xiàn)的開源FIX引擎,同時(shí)提供Python、Ruby語言實(shí)現(xiàn)。
QuickFIX官網(wǎng):
http://www.quickfixengine.org
Github地址:
https://github.com/quickfix/quickfix
2、QuickFIX編譯
編譯選項(xiàng)配置:
configure
編譯:
make
檢查:
make check
安裝:
sudo make install
二、FIX應(yīng)用模式
1、FIX應(yīng)用模式簡(jiǎn)介
FIX應(yīng)用有initiator和acceptor兩種模式。
initiator是TCP連接的發(fā)起方,acceptor是TCP連接監(jiān)聽方。標(biāo)準(zhǔn)FIX應(yīng)用(如CTS FIX網(wǎng)關(guān))可以同時(shí)支持initiator和acceptor兩種模式,既可以發(fā)起連接,也可以接受連接請(qǐng)求。
開發(fā)FIX應(yīng)用時(shí),需要先確定FIX應(yīng)用模式,然后選擇對(duì)應(yīng)的QuickFIX類對(duì)象。
initiator模式的FIX應(yīng)用可以使用SocketInitiator、SSLSocketInitiator、ThreadedSocketInitiator、ThreadedSSLSocketInitiator創(chuàng)建FIX Initiator應(yīng)用。
acceptor模式的FIX應(yīng)用可以使用SocketAcceptor、SSLSocketAcceptor、ThreadedSocketAcceptor、ThreadedSSLSocketAcceptor創(chuàng)建FIX Acceptor應(yīng)用。
2、FIX通信
FIX應(yīng)用業(yè)務(wù)是通過在initiator與acceptor間建立一個(gè)FIX Session并交換消息來進(jìn)行的。FIX業(yè)務(wù)消息有一系列預(yù)定義類型與格式,目前標(biāo)準(zhǔn)的消息類型有5、60個(gè),函蓋了交易、行情、結(jié)算等投資管理的各個(gè)環(huán)節(jié)。FIX應(yīng)用開發(fā)基本上是對(duì)FIX消息的編程。
Fix Session可以由一個(gè)或多個(gè)Fix連接組成,即Fix Session可以多次登陸。Fix Session通常使用幾個(gè)重要標(biāo)識(shí)區(qū)分,如Fix版本號(hào)字符串(如:FIX.4.2),發(fā)送者ID,接收者ID,Fix Session每發(fā)送一條消息時(shí),消息頭的BeginString、SenderCompID、TargetCompID都會(huì)被賦值。當(dāng)消息通過FIX連接到達(dá)對(duì)等方時(shí),對(duì)等方可以根據(jù)消息頭中的的標(biāo)識(shí)找到本地端的Fix Session去處理消息。
FIX通信雙方包括Initiator和Acceptor,會(huì)各自維護(hù)2個(gè)遞增的序列號(hào)(發(fā)送消息序列號(hào)–每發(fā)送一個(gè)消息加1,接收消息序列號(hào)–每收到一個(gè)消息加1)。
(1)通信首先由Initiator開始發(fā)起TCP連接請(qǐng)求, Acceptor接收網(wǎng)絡(luò)連接請(qǐng)求,建立TCP連接。
(2)Initiator發(fā)起登錄消息請(qǐng)求。
(3)Acceptor收到登錄請(qǐng)求后,經(jīng)過一系列消息檢查,合格后,返回登錄確認(rèn)。
(4)Initiator收到登錄確認(rèn)后,經(jīng)過一系列消息檢查,合格后,雙方FIX Session連接成功。
(5)Initiator和Acceptor交換消息。
(6)Initiator和Acceptor任何一方發(fā)出退出消息。
3、FIX Session配置
QuickFix中initiator或acceptor會(huì)維護(hù)多個(gè)Fix Session。QuickFix中使用BeginString(Fix版本號(hào))、SenderCompID、TargetCompID的組合標(biāo)識(shí)一個(gè)Session,Session標(biāo)識(shí)用于區(qū)分其它不同的Session。
Session配置文件包含[DEFAULT]和[SESSION]兩種分節(jié),[SESSION]分節(jié)表示QuickFix中定義一個(gè)Session,[DEFAULT]表示所有Session默認(rèn)使用的配置項(xiàng),如果不提供QuickFix所需的配置,QuickFix會(huì)拋出ConfigError異常,表示配置缺失或格式不正確。
如果[DEFAULT]和[SESSION]分區(qū)中都包含相同的配置項(xiàng),則[SESSION]分區(qū)的配置項(xiàng)會(huì)覆蓋[DEFAULT]分區(qū)相應(yīng)的配置項(xiàng)。
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三、QuickFIX核心類
1、FIX::Application
FIX應(yīng)用需要實(shí)現(xiàn)FIX::Application接口:
class?Application { public:virtual?~Application()?{};///?Notification?of?a?session?begin?createdvirtual?void?onCreate(?const?SessionID&?)?=?0;///?Notification?of?a?session?successfully?logging?onvirtual?void?onLogon(?const?SessionID&?)?=?0;///?Notification?of?a?session?logging?off?or?disconnectingvirtual?void?onLogout(?const?SessionID&?)?=?0;///?Notification?of?admin?message?being?sent?to?targetvirtual?void?toAdmin(?Message&,?const?SessionID&?)?=?0;///?Notification?of?app?message?being?sent?to?targetvirtual?void?toApp(?Message&,?const?SessionID&?)EXCEPT?(?DoNotSend )?=?0;///?Notification?of?admin?message?being?received?from?targetvirtual?void?fromAdmin(?const?Message&,?const?SessionID&?)EXCEPT?(?FieldNotFound,?IncorrectDataFormat,?IncorrectTagValue,?RejectLogon?)?=?0;///?Notification?of?app?message?being?received?from?targetvirtual?void?fromApp(?const?Message&,?const?SessionID&?)EXCEPT?(?FieldNotFound,?IncorrectDataFormat,?IncorrectTagValue,?UnsupportedMessageType?)?=?0; };onCreate:當(dāng)一個(gè)Fix Session建立時(shí)調(diào)用。
onLogon:當(dāng)一個(gè)Fix Session登錄成功時(shí)調(diào)用。
onLogout:當(dāng)一個(gè)Fix Session退出時(shí)調(diào)用。
fromAdmin:當(dāng)收到一個(gè)消息,經(jīng)過一系列檢查,合格后,屬于Admin類型時(shí)調(diào)用。
fromApp:當(dāng)收到一個(gè)消息,經(jīng)過一系列檢查,合格后,不屬于Admin 類型時(shí)候調(diào)用。
toAdmin:當(dāng)發(fā)送一個(gè)admin類型消息調(diào)用。
toApp:當(dāng)發(fā)送一個(gè)非admin(業(yè)務(wù)類型)消息調(diào)用。
如果需要使用QuickFIX開發(fā)FIX應(yīng)用,則需要實(shí)現(xiàn)FIX::Application接口,并重載不同F(xiàn)IX協(xié)議版本的MessageCracker::OnMessage接口,如FIX42::MessageCracker。
FIX業(yè)務(wù)都是異步方式處理的,而業(yè)務(wù)處理的基本對(duì)象是消息。OnMessage是消息接收回調(diào)函數(shù),有多個(gè)重載版本,開發(fā)者只需要使重載一個(gè)FIX版本即可。
對(duì)于支持交易業(yè)務(wù)的FIX Initiator應(yīng)用,通常要重寫4個(gè)基本消息,即OnMessage(NewOrderSingle)、OnMessage(CancelRequest)、 OnMessage(ExecutionReport)、 OnMessage(CancelReject),分別用于做委托、撤單、執(zhí)行回報(bào)(包括對(duì)委托的拒絕)和對(duì)撤單的拒絕等4項(xiàng)業(yè)務(wù)。
#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?createdvirtual?void?onCreate(?const?SessionID&?){}///?Notification?of?a?session?successfully?logging?onvirtual?void?onLogon(?const?SessionID&?){}///?Notification?of?a?session?logging?off?or?disconnectingvirtual?void?onLogout(?const?SessionID&?){}///?Notification?of?admin?message?being?sent?to?targetvirtual?void?toAdmin(?Message&,?const?SessionID&?){}///?Notification?of?app?message?being?sent?to?targetvoid?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?targetvirtual?void?fromAdmin(?const?Message&,?const?SessionID&?)throw?(?FIX::FieldNotFound,?FIX::IncorrectDataFormat,?FIX::IncorrectTagValue,FIX::RejectLogon?){}///?Notification?of?app?message?being?received?from?targetvirtual?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應(yīng)用配置使用FIX::SessionSettings讀取FIX Session配置文件并傳遞給QuickFIX框架。一個(gè)FIX應(yīng)用可以管理多個(gè)FIX?Session,每個(gè)Session可以采用相同的FIX協(xié)議版本,也可以采用不同的版本。即使采用的是相同的FIX協(xié)議版本,不同F(xiàn)IX Session間也可以有FIX協(xié)議細(xì)節(jié)的差異,通過綁定FIX Session與FIX協(xié)議字典的方式來實(shí)現(xiàn),即在Session配置文件中[Session]配置項(xiàng)中使用DataDictionary選項(xiàng)指定相應(yīng)FIX字典文件來實(shí)現(xiàn)。
FIX::SessionSettings?settings("sessionConfig.ini");3、FIX::FileStoreFactory
QuickFIX提供了存儲(chǔ)消息到文件的類FIX::FileLogFactory。消息文件存儲(chǔ)的路徑在Session配置中指定。
FIX::FileStoreFactory?storeFactory(settings);4、FIX::MessageStoreFactory
QuickFIX提供了給Fix Session持久化類型(如文件存儲(chǔ)、數(shù)據(jù)存儲(chǔ),存儲(chǔ)內(nèi)容包括狀態(tài)、創(chuàng)建時(shí)間、消息及其自己維護(hù)的發(fā)送序列號(hào)和接收序列號(hào)等)。
如果開發(fā)者要自定義持久化方式,可以自己定義MessageStoreFactory實(shí)現(xiàn),并且自定義一種MessageStore。
5、FIX::FileLogFactory
QuickFIX提供了存儲(chǔ)所有日志事件到文件的類FIX::FileLogFactory。
6、FIX::ScreenLogFactory
QuickFIX中提供了顯示所有消息事件到標(biāo)準(zhǔn)輸出的類ScreenLogFactory。
FIX::ScreenLogFactory?logFactory(settings);7、FIX::Message
QuickFIX中定義了不同F(xiàn)IX協(xié)議版本消息的基類FIX::Message,用于定義FIX消息的通用結(jié)構(gòu),不同的FIX消息版本的消息定義在不同的FIX命名空間內(nèi)定義,如FIX42::Message。FIX::MessageCracker則繼承了所有不同F(xiàn)IX協(xié)議版本的MessageCracker類,接收消息后生成具體FIX協(xié)議Message對(duì)象實(shí)現(xiàn)對(duì)消息進(jìn)行處理。
8、FIX::Session
無論是FIX Initiator應(yīng)用還是FIX Acceptor應(yīng)用,在Fix Session初始化時(shí),即在FIX::SessionFactory創(chuàng)建Fix Session后都會(huì)檢查Fix Session時(shí)間范圍。如果Fix Session啟動(dòng)不是當(dāng)天有效的Session,則會(huì)重置Fix Session的發(fā)送序列號(hào)和接收序列號(hào)。(FIX規(guī)定一個(gè)Fix Session一般不超過24小時(shí))。
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()方法是定時(shí)運(yùn)行的一個(gè)方法,主要用于檢測(cè)是否需要發(fā)心跳消息,是否需要發(fā)TEST消息,是否需要斷開連接,是否需要產(chǎn)生LOGON(Initiator)。
next( const Message&)方法用于處理Session收到的FIX消息。
9、FIX::Acceptor
FIX::Acceptor用于從Session配置文件讀取信息創(chuàng)建和管理本Acceptor支持的FIX Session,具體FIX Session的TCP連接管理、數(shù)據(jù)讀寫由具體的SocketAcceptor、SSLSocketAcceptor、ThreadedSocketAcceptor、ThreadedSSLSocketAcceptor實(shí)現(xiàn)。
FIX::Acceptor*?acceptor?=?new?FIX::SocketAcceptor(application,?storeFactory,?settings,?logFactory);10、FIX::Initiator
FIX::Initiator用于從Session配置文件讀取信息創(chuàng)建和管理本Initiator支持的FIX Session,具體FIX Session的TCP連接管理、數(shù)據(jù)讀寫由具體的SocketInitiator、SSLSocketInitiator、ThreadedSocketInitiator、ThreadedSSLSocketInitiator實(shí)現(xiàn)。
FIX::Initiator?*?initiator?=?new?FIX::SocketInitiator(application,?storeFactory,?settings,?logFactory);四、FIX Acceptor應(yīng)用開發(fā)
1、FIX Acceptor應(yīng)用簡(jiǎn)介
FIX Acceptor應(yīng)用通常用于FIX網(wǎng)關(guān),部署在賣方側(cè)。
2、FIX Acceptor應(yīng)用創(chuàng)建
(1)創(chuàng)建FIX Session配置對(duì)象
FIX::SessionSettings settings(sessionFile);(2)創(chuàng)建FIX應(yīng)用:
Application application;創(chuàng)建日志工廠:
LogFactory logFactory(settings);創(chuàng)建消息存儲(chǔ)文件工廠:
FIX::FileStoreFactory storeFactory(settings);創(chuàng)建Acceptor服務(wù)端:
FIX::Acceptor* acceptor = new SocketAcceptor(application, storeFactory, settings, logFactory);啟動(dòng)SocketAcceptor:
acceptor->start();3、FIX Acceptor應(yīng)用示例
Executor示例演示了接收訂單請(qǐng)求并返回成交回執(zhí)的FIX Acceptor應(yīng)用。
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?overloadsvoid?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?overloadsvoid?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; };#endifApplication.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應(yīng)用開發(fā)
1、FIX Initiator應(yīng)用簡(jiǎn)介
FIX Initiator應(yīng)用通常用于交易客戶端,部署在買方側(cè)。
2、FIX Initiator應(yīng)用創(chuàng)建
(1)創(chuàng)建FIX Session配置對(duì)象
FIX::SessionSettings settings(sessionFile);(2)創(chuàng)建FIX應(yīng)用:
Application application;創(chuàng)建日志工廠:
LogFactory logFactory(settings);創(chuàng)建消息存儲(chǔ)文件工廠:
FIX::FileStoreFactory storeFactory(settings);創(chuàng)建Acceptor服務(wù)端:
FIX::Initiator* client= new SocketInitiator(application, storeFactory,settings, logFactory);啟動(dòng)SocketInitiator:
client->start();3、FIX Initiator應(yīng)用示例
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(); };#endifApplication.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;} }總結(jié)
以上是生活随笔為你收集整理的交易系统开发(十一)——QuickFIX简介的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 串的查找和替换课程设计c语言,(串的查找
- 下一篇: PyDraw 所见即所得的 Pytho