交易系统开发(十一)——QuickFIX简介

交易系统开发(十一)——QuickFIX简介

一、QuickFIX简介

1、QuickFIX简介

QuickFIX是一款C++实现的开源FIX引擎,同时提供Python、Ruby语言实+ 8 { J现。
QuickFIX官网:
http://= ~ .www.quickfixengine.org
Github地址:
https://github.com/quickfix/quickfix

2、QuickFIX编译

编译选项配置:
configure
编译:
make
检查:
make check
安装:
sudo make install

二、FIX应用模式

1、FIX应用模式简介

FIX应用有initiator和acc[ c 4 f _ C neptor两种模式。
initiator是I e c 6TCP连接的发起方,acceptor是TCP连接监听方。标准FIX应用(如CTS FIX网关D t Q)可以同时支持initiator和acceptor两种模式,既可以发起连接,也可以接受连接请求。
开发FIX应用时,需要先确定FIX应用模式,然后选择对应的QuickFIX类q i p 4 X L C对象。
initiator模式g Z 8 k U的FIX应用可以使用SocketInitiator、SSLSocketInitiator、ThreadedSocketInitiator、ThreadedSSLSocketInitiator创建FIX Initiator应用。
acci @ m 6 0 ~ d eptor模式的FIX应用可以使用SocketAcceptor、SSLSocketAcceptor、ThreadedSocketAcceptor、ThreadedSSLSocketAA A Rcceptn j s Y S q 2 for创建FIX Acceptor应用。

2、t ; 9 s k v h B wFIX通信

FIX应5 : u用业务是通过在iniD j O 3 | Ltiator与acceptor间k { / M v建立一个FIX Session并交换消息来进行的。FIX业务消息有一系列| 2 v W w /预定义类型与格式,目前标准的消息类型有5、60个,函盖了交易、行情、结算等投资管理的各个环节。FIX应用U [ p & U开发基本上是对FIX消息的编程。
Fix Session可以由一N q p个或多个Fix连/ P r ` V R t接组成,即Fix Session可以多次登陆。Fix Session通常使用几个重要标识区p . A w | t + }分,如Fix版本号字符串(如:FIX.4.2),发送者ID,接收者ID,Fix Session每发送一条消息时,消息头的BeginString、SenderCompID、TarX = s getCompID都会被赋值。当消息通过FIX连接到达对等方时,对等方可以根据消息头中的的标识找到本地端的Fix Session去处理消息。
FIX通信双方包Z a d / g b z括Initiator和Acceptor,会各自维护2个递增的k Q } z序列号(发送消息序列号–每发送一个消息加1,接收消息序列号–每收到一个消息加1)。
(1)通信首先由Initiator开始发起TCP连接请求, Accep7 p g X =tor接收网络连接请求,建立TCP连接。
(2)IP G { ] L .nitiator发起登录消息请求。
(3)Acc^ ( F heptor收到登录请求后,经过一系列消息检查,合格后,返回登录确认。
(4)Initiator收到登录确认后,经过一系列消息检查P q ^ Q - [ K,合格后,双方FIX Sl A l s 7ession连接成功。
(5)Initiator和Acceptor交换消息。
(6)Initiator和Acceptor任何一方发出退出消息w ! v { ? n4 % q 7 j W # 1

3、FIX Session配置

QuickFix中initiator或accepto~ d ; A mr会维护多个Fix Session。QuickFix中使用BeginString(Fix版本号)、SenderCompID、TargetCompID的组合标识一个Session,Session标识用于区分其它不同的Session。
Session配置文件包含[DEFAULT]和[SESSION]两种分节,[SESSION]分节表示QuickFx e g ^ix中定义一个Session,r P | Z D } 7[DEFAULT]表示所有Session默认使用的配置项,如果不提供QuickFix所需的配置,QuickFix会抛出ConfigError异常,表示配置缺失或格式不正确。
如果[DEFAULT]和[SESSI2 7 v ; I ` { v +ON]分区中都包含相同的9 @ 2配置项,则[SESSION]分区的配置项会覆盖[DEFAULT]分区相应的配置项。
QuickFix配s h } $ N置文件sessions.inp + ~ z di如下:

[DEFAULT]
ConnectionType=initiator
ReconnectInterval=60
FileLogPath=log
FileStorePath=store
StartTime=00:00:00
EndTime=23:59:59
HeartBtInt=30
ResetOnDisconnect=Y
ResetO2 M / W G 3  1 unLogout=Y
ResetOnLogon=Y
[SESSION]
BeginString=FIX.4.2
SM ;  } v y E lenderCompk d 3ID=CLIENT
TargetCompID=SERVER
SocketConnectPort=6666
SocketConnectHost=127.0.0.1
DataDictionary=FIX42.xml

~ H G f r 9 H、QuickFIX核心类

1、FIX::Applicz a = Lation

FIX应用需要实现FIX::Application接口

class Application
{
public$ . x 4 ^ @ H ; ^:
virtual ~Aw ; 4 I m 7pplication() {};
/// NotifiP X 9 @ p lcation of a session begin cre^ i [ q x , .ated
virtual void onCreate( const Session J P ? unID&K h ; U Z 1 c E |amp; ) = 0;
/// NotificatioZ # * W z J ( t snk n P of a session suj T  # ? o I wccessfully logging on
viJ 4 % Q * rtua& $ ) @ Y ; jl void onLogon( const S- ) _ ( & A x FessionID& ) = 0;
/// Notification of a session loggiq 4 } + | Tng off or din 2 D , f msconnecting
virtual void onLogout( const SessionID& ) = 0;
/// Notification of admin message being sent to target
virtual void toAdmin(^ f O h u  e Message&| 1 c h # ; p, const SessiV ~ [onID& ) = 0;
/// Notification of+ w a ] / z Y ^ * app message being sent to target! @ K y
virtual void toApp( Message&, const SessionID& )
EXCEPT ( DoNotSend ) = 0;
///= e j & Q M Notifi[ d W Ucation of admin meh N W [ | ) Jssage being received from target
virtual void fromAdmin( const Message&, const SessionID& )
EXCEPT ( FieldNotFound, IncorrectDataFor7 C Omat, IncorrectTagValue, RejectLogon ) = 0;
/// Notification of app message being receJ K ` / - 9 ` 5 uived from targy G 8et
virtual void fromApp( const Message&, const SessionID& )
EXCEPT ( FieldNotFound, Incoro q 5 H R z ` nrectDataFormat, IncorrectTagValue, UnsupportedMessageType ) = 0;
};

onCreate:当一个Fix Session建立时调+ k f @用。
onLogon:当6 e H一个Fix Session登录成功时调用。
onLogout:当一个Fix Session退出时调用。
fromAdmin:当收到一个消息,经过一系列检查,合格后,属于Admin类型时调用。
fromApp:当收到一个消息,经过一系列检查,6 w y合格后,不属于Admin 类型时候调用。
toAdmin:当发送一个admin类型消息调用。
toApp:当发送一个非admin(业务类j / ; 7 = . : 1 2型)消息调用。
如果需要使用QuickFIX开发FIX应用,则需要实现FIX::Application接口,并重载不同FIX协议版本的MessageCraC 3 9 G @ W ! jcker::OnMessage接口,如FIX42::MessageCrackt |er。
FIX业务都是异步方式处理的,7 G 2 = p ~ m 0而业务处理的基本对象是消息。OnMessage是消息接收回调函数,有多个重载S H _ + = - l u版本,开发者只需要使重载~ W ; M 7 ?一个FIX版本即可。
对于支持交易业务的FIX Initiator应用,通常要重写4个基本消息,即OnMessage(NewOrderSi` n M H ; 8 g *ngle)、OnMe; l } W ] W gssage(CancelRe* d H 6quest)、 OnMessage(ExecutC , ] N N hionReport)、 OnMessage(Ca3 - & C p G SncelReject),分别2 . C用于做委托、撤单、执行回报(包括对委托的拒绝)和对撤9 M - E + ! k F单的拒绝等4项业务。

#include "quickfix/Application.h"
#include "quickfix/MessageCracker.h"
class FIXApplication: public FIX::Application, public FIX::MessageCracker
{
public:
/*****************@ q  } **********************************
*  reimplementation~ ~ b | 7 8 from Application
* ***********************************************/
/// NotificE t ? . [ a Lation 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 sess, f n n 7ion logging off or dn % e a 1 @ Nisconnecting
virtual void onLogout( const SessionID& )d A i g i M U z c
{
}
/// Notification of admin message being sent to target
virtual void toAdmin( Message&w  6 [ -amp;, const SessionIm e SD& )
{
}
/// NoH : j Vtification of app message being sent to target
void} t * & fromAppS i f( cm q +onst FIX::Message&au # t - J z N @mp; message, const FIX::SessionID& sessionID )
throw( FIX::4 t g ; { _ g ^ =FieldNotFound&, FIX::IncorrectDataFormat&, FIX::IncorrectTagValue&,
F2 c +IX::UnsupportedMessageType& )
{
crack(meV [ # = 3 _ l yssage, sessie : v g g Z | (onID);
}
/// N; ~ ) 1 + V Wotification 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 apV I [ b W sp message being rece_ z x K c 9ived from target
virtual void fromApp( const Message| S .&, const SessionID& )
thk c h { c Crow ( FIX::FieldNotFound, FIX::IncorrectDataFo; { _ g ; K - )rmat, FIX:+ ] _ 6 / -:IncorrectTagValC Q l 3 f 4 z Jue,
FIX::UnsupportedMessageType )
{
}
/***************% , + + - G ^ | 3******************************y n o # 7 Z S :*****
*  reimplementation from FIX42::MessageCracker
* ***********************************************/
virtual void onMessage( const FIX42::U ] @ - R PNewOrderSingle& message, const FIX::SessionID& G A q Eamp; )
{
}
virtual void onMessage( co~ { 5nst FIX4i K 52::OrderCancelRequest& mesr b } { / F ( ?s2 & . n ` G ` vage, const FIX::SessionID& )
{
}
virtual void onMessage( ExecutionReport&, const FIX::SessionID& )
{
}
vi; f T .rtual void onMessage( OrderCancelRej| w kect&, const FIX::SessionID& )
{
}
};

2、FIX::SessionSetti; v j &ngs

FIX应用配置使用FIX::SessionSettin{ / $ [ Kgs读取FIX Session配置文件并传递给QuickFI| x = Q ! R K JX框架。一个FIX应用可以管理多个FIX Session,每个Session可以采用相同的FIX协议版本,也可以采用不同的版本。即使采用的是相同的FI& u Y X协议版本,不同FIX Session间也可以有FIX协议细节的差异,通过绑定FIX Session与FIX协议字典的方I D ~ 7 m o式来实现,即在Session配置文件中[Session]配置项中使用DataDiction@ t T * ~ W g /ary选项指定相应FS I L ,IX字典文件来实现。
FIX::SessionSettings settings(C - !"sessionConfig.ini");

3、Fm 3 9IX! C )::FileStoreFactoryX 5 ]

QuickFIX提供了存储消息到文件的类FIX::FileLogFactory。消息文件存储的路径在Session配置中指定。
FIX::FileSG n E . q Z @ !toreFactory storeFactory(settings);

4、FIX::MessageStoreFactory

QuickFIX提供了给Fix Session持久化类型(如文件存储、数据存储,存储内容包括状态、创% p l时间、消息及其自己维护的发送序列号和接收序列号等)。
如果开发者要自定义C t 8 y I持久化方 V + ~ _式,可以自己定义MessageStoreFactory实现,并且自定义一种MessageStore。

5、FIX:n ] x = `:FileLogFactory

QuickFIX提供了存储所有日志事件到文件的类FIX::FileLo~ L L LgFac+ ; a j W c u Xtoryg M T C 6 O I + V

6、FIX::ScreenLogFactory

QuickFIX中提供了显示所有消息事件到标G e 0 a _ V准输出的类ScreenLogFactory。
FIX::ScreenLogFactory logFactory(settingL n ; Us);

7、FIX::Message

QuickFIX中定义了不同FIX协议版本消息的基类FIX::Message,用于定义FIX消息的通用结构,$ j ( ? 3 J q ]不同的FIX消息版本的消息定义在不同的FIX命名z w | J # T E o空间内定义,如FIX42::Message。FIX::MessaG ; @geCracker则继承了所有不_ H i ( h S同FIX协议版本的MessageCracker类,接收消息后生成具体FIX协议Message对象实现对消息进行处理。

8、FIX::Session

无论是FIX Initiator应用还是FIX AcceptP Y $ O d wor应用,在Fix Sessio5 j O o ]n初始化时,即在FIX::SessionFe w 9 E 7 8 g x lact$ M g aory创建Fix Ses6 9 n ; ^ zsion后都会检查Fix Session时间范围。如果Fix Sessiond a py u , @ C i , H动不是当天有效的Session,则会重置Fix Session的发送序列号和接收序列号。(FIX规定一个Fix S, , oession一般不超过2l v U 1 8 q L4小时)。
FIX::Session部分接口定义如下:

class Seg n % g 3 L p ^ vssion
{
publiR N g ] { , ^c:
static bool sendToTarget( Message&a k } Gmp; message,
const std::string& qualifier = "" )
EXCEPT ( SessionNot} { { M #FouR r j a L 9nd );
static bool sendToTarget7 : G D i p 8 +( Message& message,
const SessionID& session2 9 . - l 4ID )
EXCEPT ( SessionNotFound );
static bool sendToTarget( Message&,
const SenderCompID& senderCompID,
const TargetCompID& targetCompID,
cov } e s j e 8 7nst sp i o  z _ K G $td::string& qualifier = "" )
EXCEPT ( SessionNotFou2 5 e ( = Znd );
static bool sendToTarget( Message& message,
const std::string& senderCompID,
consn = U 2 % h = 5 Qt std::string& targetCompID,
const4 Q q  } Y 3 @ { sP v  | | V 5 E td::( g astring& qualifier = "" )
EXCEPT (k M o R SessionNotFound );y { ? + _ ? w
bool send( Message& );
voi( _ W #d n1 i l C n next();
void next( const UtcTimeStamp& timeStamp );
void next( const std::string&, const UtcTimeStamp& timeStamp, bool queued = false );
void next( const Message&, cob @ p e W + ! } )nst UtcTimeStamp& timeStamp, bool queued = false );
};

ne- a P V & 2 P dxt()方法是定z s 9 l = c m @时运行的一个方法,主 - [要用于检测是否需要发心跳消息,是否需要发TEST% A h - % H [消息,是否需要断开连接,是否需要产生LOGON(Initiator)。
next( const Message&)方法用于处理Session收到的FIXk ! o 7消息。

9、FIX::Acceptor

FIX::Acceptor用于从Session配置文件读取信息创建和管理本Acceptor支持的F^ s IX Session,具体FIX Session的TCP连接管理、数据读写由具体的SocketAcceptor、SSLSocketAcceptor、ThreadedSocketAcceptor、ThreadedSSLZ J M : : )SocketAcceptor实现。
FIX::Acceptor* acceptor = new FIX::SocketAcceptor(application, storeFactory, settings, logFac@ y &tory);

10、FIX::Initiator

FIX:: W YInitiator用于从Session配置文件读取信息创建和管理本Initiator支持的FIX Session,具体FIX Session的TCP连接管理、数据读写由具体的SocketInitia7 - N *tor、t 3 S aSSLSocketInitiator、) L O u B L *ThreadedSocketInitiator、T/ a h o 0 ,hreadedSSLSocketInitiator实现。
FIX::Initiator * initiator = new[ R y $ [ P 3 t p FIX::SocketInitiator(application, storeFactory, settings, logFactory);

四、FIX Acceptor应用开发

1、FIX Acceptor应用简介

FIX Acceptor应用通常用于FIX网关,部署在卖方X n -侧。

2、FIX AcY b E c A ` Z aceptor应用创建

(1)创建FIX Session配L c r置对象
FIX::SessionSettingq T _ + ) L [s settings(session$ c 1File);
(2)创建FIX应用:
Application application;
创建日志工厂:
LogFactory logFactory(settings);
创建消息存储文件工厂:
FIX::FileStoreFactory storeFactory(settings);
创建Acceptor服务端:
FIX::Acceptor* a7 c o 4cceptor = new SocketAcceptor(application, storeFactory, settings, logFactory);
启动SocketAccg x j .eptor:
acceptor->start();

3、FIX Acceptor应用示例

Executor示例演示了接收订单请求并返回q 8 =成交回执的FIX Acceptor应用。
Application.h文件:

#{ & 8 } W @ qifndef EXECUTOR_APPLIC3 I B o z #  C FATION_H
#define EXECUTOR_APPLI_ D ;CATION_H
#include "quickfix/Application.h2 ) I A A"
#include "quickfix/MessageCracker.h"
#include "quickfix/Values.h"
#include L c H F"quickfix/Utility.h"
#include "quickfix/Mutex.hF 3 : b N ( @"
#include "quickf! m _ |ix/fix40/NewOrderSingle.h"
#inclR a D J M ; lude "quickfix/fix41/NewOrderSingle.h"
#include "quickfix/fix42/NewOrd+ F Q /erSingle.h"
#include "quickfix/fix43/NewOrderSingle. B q 6h"
#include "quickfix/fix44/NewOrderSine F ~ cgle.h"
#include "quickfix/fixd r Z ~ ? N50/NewOrderSingle.h"
classx s - 6 L c - Application
: public FIX::Application, public FIX::Messae s Z B . $geCracker
{
publ# A 6 E ^ .ic:
Application() : m_orderID(0), m_execID(0) {}
// Application overloads
vs g l w woid onCreate( const FIX::SessionID& );
void onLogon( const FIX::SessionID& sessionID );
void onLogout( cons] 1 tt FIX::SessionID& sessionID );
void toAdmin( FIX::Message&am: h ) G ~ Mp;, const FIX::SessionID&l l R ) T yamp; );
void toApp( FIX::Message&, const FIX::SessionID& )
EXCEW | c g =PO - B x fT( FIX::DoNotSend );
void fromAdmin( const FIX::Message&, const FIX. q 8::SessionIq h ; l ~ iD& )J % w - W
EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataF | ) Z +ormat, FIX::x - , F q 3IncorrectTagValue, FIX::h I + 8 oRejectLogon );
void fromApp( const FIX::Message& message, const FIX::SessionID& se^ , { X p U UssionI^ j n k / t ; [D )
EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::Incorrn x t d b j { tectTagValue, FIX::UnsupportedMessageType );
// MessageCracker overloads
void onMessage( const FIX40::NewOrh d x ; w / ~ vderSi O ~ g F N Xngle&, const FIX::SessionID& );
void onMessage0 ( ( 5 + A R b( const FIX41::NewOrderSingle&, const FIX::SessionID& );
void onMessage( const FIX42+ 4 s 4 7::NewOrderSingle&,| j W ( U const FIX::SessionID& );
void onMess# 7 eage( const FIX43::NewOrderSingli 9 ) f S u oe&, const Fk R KIX::SesU / _ x q D KsionID& );
void on~ Y _ , Y F p oMessage( const FIX44::NewOrderSingle&, const FIX::SessionID& );
void onM? G 0 h ~ ;essage( const FIX50::NewOrderSingle&, const FIX::SessionID& );
std::stri_ p @ p s { 8 ang genOrderID() {
std::stringstream stream;
stream << ++m_orderID;
return stream.str();
}
std::string genExecID() {
std::stringstream stream;
stream &# @ P S X Jlt;< ++m_M x y z r ! execID;
return stream.str();
}
private:
int m_orderID, m_execID;
};
#endif

Application.cpp文件:

#include "config.h"
#include "ApplicatioU W m k b g K D un.h"
#include "quiV ~ G i ^ t # w Xckfix/Session.h"
#include "quickfix/fix40/ExecutionReport.h"
#include "quickfix/f0 | a lix41/E(  8 8 U IxecutionReport.h"
#iR P c e dnclude "qx I M q c ! K G Guickfix/M + | . o f & k Ufix42/ExecutionReport.h"
#include "quickfix/fix43/ExecutionReport.h"
#include "quickfix/fix4F ( O y V y W ~ |4/ExecutionReport.h"
#include "quickfix/fix50/ExecutionReport.h"
void Applicati_ ! * w 0 t Son::N ~ M XonCreate( const FIX::Session; ! c ZID& session+ : ` d s uID ) {}
void Application:D A 0 1 ~ %:onLogon( const FIX::SessionID& sessionID ) {}
void Application::onLogout( const FIX::SessionID& sessionID ) {}
void ApplicatiV a G : 0 E &onM / V . 2::toAdmin( FIX::Message& message,
const FIX::SessionID& sessionID, l } q . B } u ) {}
void Applicatio} 0 b I m 9 en::toApp( FIX::Message& messagH ( g u v e,
const FIX::SessionID& sessionID )
EXCV + R j } I ; 5 pEPT( FIX::Do: v 9 ~ ( + 4  {NotSend ) {}
void Appl% / r 9 ` $ d % Cication::fromAdmin( const FIX::MP ! ~ . ^essageE + D Q X X N ] [& message,
const FIX::SessionID& sessionID )
EXCEPT( FIX::FieldNoto ! J w [ K v @FoundV O D R T, FIX::IncorrectDataFoM 6 i Urmat, FIX::IncorrectTagValue, FIX::RejectLogon ) {}
void Application::fromApp( conC $ j /st FIX::Message& message,
conR s {st FIX::SeY R P { : U _ *ssionID& sessionID )
EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::UnsupportedMessageType )
{ crack( message, sessionID ); }
void Application::onMessage( const FIX40::NewOrderSingle&6 i L ~ _ a N A Oamp; message,
const FIX::SessionID& s+ T s : - % M JessionID )
{
FIX::Symbol symbol;
FI7 U 2 M f , ^ 7X::Si@ + Dde side;
FIX::OrdType ordType;
FIX::OrderQL V . L L P 4 wty orderQty;
FI0 L M Q yX::Price price;
FIXE o 3 ] 6 M J H s::ClOrdID clOrdID;
FIX::Account ac8 * Y + h k X { tcount;
message.get( ordType );
if ( ordType != FIXQ X ~ 2 h F::OrdType_LIMIT )
throw FIX::IncorrectTagValue( ordType.getField() );
message.! P x T Y B 3 I 3get( symbol );
message.get(| ; W ~ L I e B * sider C ^ @ . K );
message.get( orderQty );
message.get( price );
message.get( clOrdID )p L Q `;
FIX40::ExecutionReport ex% 6 _ + OecutionReport = FIX40::Execun c K 7  5 3 [tionReport
( FIX::OrderID( genOrderID() ),
FIX::ExecID( genExecID() ),
FIX::ExecTransType( FIX::ExecTransType_NEj q : f PW ),
FIX::OrdStatus( FIX::OrdStatus_FILLED ),
symbol,
side,
orderQty,
FIX::LastShares( orderQty ),
FIX::LastPx( price ),
FIX::Cuma n M v G # @Qty( orderQty ),
FIv a Z o B p p QX::A8 ) n { a B I avgPx( price ) );
executionReport.set( clO#  9 yrdID );
if( message.isSet(account) )
executionReportm l [ 9 s e z.setField( message.get(account) );
try
{
FIX::Session::sendToTarget( executionReport, sessionID );
}
catc/ . l | X { f jh ( FIX::SessionNotFound& ) {}
}
void Application::/ B - R p $ LonMessage( constJ D ^ S i p FIX41::No u C v  f 5 oewOrderSingle&x ~ k ` message,
const FIX::SessionID&a} ? S zmp; sessionID )
{
FIX::Symbol symbol;
FIX::Side side;
FIX::OrdType ordType;
FIX:~ 0 f g 3:OrderQty orderQty;
FIX::Price price;
FIX::ClOrdID clOrdID;
FIX::Account account;
message.get( ordType );
if ( ordType != FIX::O{ s b w , WrdType_LIMITN 5 ; T / P R )
throw FIX::IncorrectTagValue( ordType.getField() );
message.get( sy8 e g - [ Hmbol );
message.get( side );
message.get( orderQty );
meT 7 p z ; Gssage.get( price );
mek ? m Gssage.get( clOrdID );
FIX41::ExecutionReport executionReport = FIX41::ExecutionReport
( FIX::OrderID( genOrderID@ _ s() ),
FIX::ExecID( genExecID() ),
FIX::B m g S , m 2 X jExecTransType( FM 1 M / ( 3 & 9IX::ExecTransType_NEW ),
FIX::ExecTg V % l ayp, J Be( FIX::ExecType_FILL ),
FIX::OrdStatus( FIX::OrdStatus_FILLED ),
sy= ( Wmbol,
side,
o? 8 ] [ 0 ? C ^rderQty,
FIX::LastShares( orderQty ),
FIX::LastPx( price ),
FIX::LeavesQty( 0 ),
FIX::CumQty( o= y d 3 c o O DrderQty ),
FIX::AvgPx( pricX x S { p } 7 Te ) );
executionReport.set( clOrdID );
if( message.isSet(account) )
executionReport.setField( message.get(account) );
try
{
FIX::Session::sendTo[ p ~ FTarget( exeP H = A g wcutionReport, sessionID );
}
catchl :  I  ^ ( FIXD Y )::SessionNotFound& ) {}
}
void Application::onMessage( const FIX42::NewOrderSingle&[ V l; message,
const FIX::SessionID& sessionID )
{
FIX::Symbol symbol;
FIX::Side side;
FIX::OrdType org 1 qdType;
FIX::OrderQty orderQty;
FIX::Price pricd I - ` ye;
FIXq y 2 ` { G ( 2::ClOrdID clOrL ) c g HdID;
FIX::AcH s % g Ccount account;
message.get( ordType );
if ( ordTyp: ] . ( c C ` e != FIX::OrdType_LIMIQ R k , ~T )
thro1 s s i 0w FIX::{ ! } D ? R t S |IncorrectTagValue( ordType.getField() );
meT W 4 + s p r y lssage.get(m % m symbol );
messa7 f e - Sge.get( side );
message.get( orderQt~ 5 i G E d ` X }y );
message.get( price );
message.get( clOrdID );
FIX42::ExecutionReport executionReport = FIX42::ExecutionReport
( FIX::OrderID( genOrderID() ),
FIX::ExecID( genExecID() ),V t _
FIX::ExecTransType( FIX::ExecTransType_NEW ),
FIX::ExecType( FIX::ExecType_FILL ),
FIX::OrdStatus( FIX::* c ] ] hOrdStatus_FILLED ),
symbol,
side,2 _ ( - 7 y X p
FIX::* a f i p 0 ? c 5LeavesQty( 0 ),
FIX::CumQty( orderQty ),
FIX::AvgPx( price ) );
executionReporZ z 3 ?t.set( clOK  U l rdID );
executionReport.seE @ Ot( orderQty );
execution[ L a a  FReport.set( FIX::LastShares( orderQn } p V Gty ) );
executionReport.set( FIX::LastPx( price ) );
if( message.isSet(account) )
executionReport.setField( message.get(account) );
try
{
FIX::Session::sendToTarget( executionReport, sessiL P t M x GonID );
}
catch ( FIX::SessionNotFound&am5 6 S h 2 K n lp; ) {}
}
void Application::onMessage( const FIX43::NewOrderSingle& message,
conF f  X E dst FIX::SessionID& sq 9 E T C hessionID )
{
FIX::Symbol syL % ) $ mmbol;
FIX::Side side;
FIX::Ord[ S C P |Typg 2 4 5 T Ue ordType;
FIX::OrderQty orderQty;
FIX::Price price;
FIX::ClOrdID clOrdI~ p r * ; oD;
FIX::Accountv [ L 6 D account;
message.get( ordType );
if ( ordType != FIX::OrdType_LIMIT )
throw FM B ^ VIX:( } % x _:IncorrectTagValue( ordType.getField() );
message.get( sE & {ymbol );
message.get( side );
message.get( orderQty );
message.get( price );
message.get( cz { , ^lOrdID );
FIX43::Execl { l ` 9 _ . ) -utionReport execd Z P % L N Y OutionReport = FIX43:. , 0 T:ExecutionReport
( FIX::OrderID( genOrderID() ),} Q M M L } I 0 S
FIX::ExecID( genExecID() ),
FIX::Er e F S S o @ 6 &xecType( FIX::ExecType_FILL ),
FIX::OrdStatus( FIX::OrdStatus_FILLED ),
side,
FIX::LeZ H @ 9 L n w javesQty( 0 ),
FIX::C| B BumQty( orderQty ),
FIX::AvgPx(! q  . b W & M N price ) );
executionReport.set( clOrdID );
executionReport.set( symbol );
executionReport.set( orderQty );
e0 Z a G t hxecutionReport.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 ApplicationQ 5 P::onMessage( const FIX44::NewOrderSingle& message,
const FIX::SessionID& sessi1 v s l : ) ; $ ionID )
{
FIX::Symbol symbol;
FIX::Side side;
FIX::OrdType ordType;
FIX::OrderQty orderQty;
FIX::. R V B 6 ( fPrice price;
FIX::ClOrdID clOrdID;
FIX::Account account;
message.get( ordType );
if ( ordType != FIX::OrdType_LIMIT )
throw FIX::IncorrectTagValue( ordType.getField() );
message.get( symbol );
messageZ . } : . p.get( side );
message.ge{ 9 2 -t( orderQty );
message.get( price );
message.get( clOrdID );
FIX44::ExecutionReport executionReport = FIX44::ExecutionReport
( FIX::OrderID( genOrderID() ),
FIX. e k | : i::ExecID( genExecID() ),
FIX::ExecType( FIX::ExecType_TRADE ),
FIX::OrdStatus( FIX::OrdStatus_FILLED] N | ) e W t ),
side,
FIX::Leave| A C i q . 6sQty( 0 ),
FIX::CumQty( orderQty ),
FIX::A/ _ 6vgPx( price ) );
executionReport.set( clOr = Y g d r 2dID );
executionReport.set( symbol );
executionReport.set( orderQty );
executionReport.set( FIX::LastQty( orderQtyv j n f 4 9 ? f ) );
executionReport.set( FIX::LastPx( pr2 y # d 6 G M L ice ) );
if( message.isSet(accw [ H 0 Y Q C # iount) )
executionReport.setField( message.get(account) );
try
{
FIX::Session::sendToTar{  Q Sget( executionReport, sessionID );
}
catch ( FIX:T ^ % j d:SessionNotFound& ) {}
}
void Application::onMessage( const FIX50::NewOrderSingle&Q Y Damp; message,
const FIX::SessionID&a( w } 0 N Nmp; sessio] = F ; P u HnID )
{
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 !i [ u= FIX::OrdType_LIMIT )
t7 M #hrow FIX::IncorrectTagValue( ordType.getK L b L d c C GField(b e Z 0 e) );
message.get( symbol );V 9 ~ g e &
message.get( sidea 5 L I M N );
message.get( orderQty );J ! Z
message.get( price );
message.get( clOrdID );
FIX50::ExecutionReport executionReport = FIX50::ExecutionReport
( FIX::OrderID( genOrderID() ),
FIX::ExecID( genExecID() ),
FIX::ExecType(X E 2 & K 2 D FIX::ExecTyc , o i p Rpe_TRADE ),
FIX::OrdStatus( FIX:~ 2 L Y . 2 5:OrdStatus_FILLED ),
side,
FIX::LeavesQty( 0 ),
FIX::CumQty( orderQty ) );
e? r ;xecutionReport.set( clOrdID );
executionReport.set( symbol )A ^ t ; o d C;
executionReport.set( orderQty );
executionReport.setQ | , j F & g( FIX::LastQty( or% w h G $ % g QderQty ) );
executionReport.set( FIX::LastPx$ u & 7 G s( price ) );
executionRe4 3 D x $ t : R 8port.set( FIX::AvgPx( price ) );
if( messag} q / G } D R ie.isSet(a* * Y j 8ccount) )
executionReporl $ 6 x * Q ~ xt.setField( message.get(account)? m 4 * y );
try
{
FIX::Session::sendToTarget( executionReport, sessionID );
}
catch ( FIX::SessionNotFound& ) {}
}

main.cpp文件:

#incluq C e ; 2 8de * / _"cH K 3 [ L z W xonfig.h"
#include "quickfix/FileStore.h"
#include "quick* 4 J n { N kfix/SocketAc( / *ceptor.h"
#include "quickfix/Log.h"K K  *
#include "quickfix/SessionSettings.h"
#include "Applw _ : H bication.h"
#include <string>
#include <iostream>
#include <fstres @ _ 7 O c Y A 5am>
void+ d $ wait()
{
std{ = E o r 9 8 G &::cout << "Type Ctrl-C to quit" << std::endl;
whiE , _ ~ % 5le(true)
{
FIX::p= n arocess_sleep(1);
}
}
int main( int argc, char** argvM d ~ e )
{
if ( argc <B q G / i g ] a; 2 )
{
std::cout &lS ! 0t;< "usage: " << argv[ 0 ]
<< "S 9 @ q FILE." << std::endl;
return 0;
}
std:o &  { x R 8 y &:string file = argv[ 1 ];
FIX::Acceptor * acceptor = 0;
try
{
FIX::Sess+ v uionSettings settings( file );
App* m o lication application;
FIXa x H C W::FileStoreFactory storeFactory( settings );
FIX::ScreenLogFactory logFas d . n h t pctory( settings );
acceptor = n+ ; B g q Bew FIX::T Z ( eSocketAccepto E $ `or ( application, storeFactory, settings, lo5 I 7 i ,gFactory );
acceptor->start();
wait();
acceptor->stoG  m = F Np();
deletW G j p } l L o 5e acceptor;
r& * E I ueturn 0;
}
catch ( std::exception & e )
{
std::cout << e.what() <&^ Y |lt; std::endl;
delete acceptor;
return 1;
}
}

五、FIX Initiator应用开发

1、FIX Initiator应用简介

FIX Initiator应用通常用于交易客户端,部署在买方侧。

2、FIX Initiator应用创建

(1)创建FIX Session配置对象
FIX::SessionSettings settings(sessionI s B 6File);
(2)创建FIX应用:
Application application;
创建日志工厂:] o W I L ^ k
LogFactory logFactory(settings);
创建消息存储文件工厂:
FIX::FileStoreFactory storeFactoryK O *(settings);
创建Acceptor服务端:
FIX::Initiator* client= new SocketInitia| s s H 4 X ntor(applicatioW X ? i g 5n, storeFactory,settings, logFac` p X 7 -tory);
启动SocketInitiator:
cli~ C Y V f * Hent-&gt;start();

3、FIX Initiator应用示例

tradeclient交易客户端
Application.h文件:

#ifndef TRf m I & A K *ADECLIENT_APPLICATION_H
#define TRADECLIENT_APPLICATION_H
#include "quickfix/Application.` k @ i V Dh"
#include "quickfiQ p E b  )x/MessageCracker.h"
#include "quickfix/Values.h"
#incluq i o s ? 0  q Gde "quickk z o 9fix/Mutex.h"
#incg ~ Q c 7 A Llude "quickfix/fix40/NewOrderSingle.h"
#include "quickfix/fix40/ExecuQ 9 h HtionReport.h"
#include "quic2 k d % + Skfix/fix40/OrderCancelRequest.h"
#include "quickfix/fixR #  5 840/OrderCa@ L ] _ k F k GncelReject.h"
#include "quickfix/H Z g j 0 -fix40/OrderCancelReplaceRequest.h"
#include "quickfix/fix41/NewOrderSingle.h"
#include "quickfix/fix41/Execq a # , 0 ^ Y ? #utionReport.h"
#include "quickfix/fix41/OrderCancel | : 0Requ^ n B _ K ? [ Z Rest.h"
#include "quickfix/fiK y 4  E P ( mx41/OrderCancelReject.h"
#include "quickfix/fi, 7 Px41/OrderC& a G 3ancelReplaceRequest.h"
#include "quick; + )fix/fix42/NewOrderSingle.h"p / = ] M z : ,
#include "quickfix/fix42/ExecutionReport.h"
#includn p  = Be "quickfix/fix42/OrderCancelRequest.h"
#include "quickfix/fix42/OrderCancelReject.h"
#includX n T n B He "quickfix/fix42/OrderCanceu B Z ` * 3lReplaceRequest.h"
#include "quickfix/u + ^ a x X Yfix43/NewOrderSingle.h"
#include "! s ~ o b n S g Iquickfix/f? [ N Dix43/ExecutionReport.h"
#include "quickf$ 5 P 5ix/fo q R ^ H I zix43/OrderCancelRequest.3 N 2 ! T c 3 5h"
#include "quickfix/fix43/OrderCancelReject.h"
#include "quickfix/fix43/OrderCancelReplaceRequest.h"
#include "quickfix/fix43y o S P { j 4 k C/MarketDataRequest.h"
#include "qu Z y J 4 y ;uickfix/fix44/NewOrderSingle.h"
#include "quickfix/fix44/Ex/ } 8 # EecutionReport.h"
#include "quickfix/fix44/OrderCancelRequest.h"
#include "quickfix/fix44/OrderCancelReject.h"
#include "quickfix/fix44/OrderCancelReplaceRequ7 i . q 4 Y q q 6est.h"
#include "quickfix/fix44/MarketDataRequest.h"
#include "quickfix/fix50/NewOrderSingle.h"
#include "quickfix/fix50/Exv ~ ] a g ) X + HecutionReport.h"
#include "quickfix/fir h s & v Jx50/OrderCancelRequest.h"
#include "quickfix/fix50/Or| U U O c uderC9 { % X R p pancelReject.h"
#include "quickfix/fix50/OrderCancelReplaceRequest.h"
#include "quickV ^ @ X U I ] 9 ]fix/fix50/MarketDataRequest.h"
#include <queue>
class Application :
pt 4 T s y ( uublic FIX::AppG s W 8 ( 0 Rlication,
publT = a ? * Hic FIX::MessageCracker
{
public:
vot y [id run();$ [ R ( q T 5 I +
prd ] t _ 8 ; $ b oivate:
void onCreate( const FIX::SessionID& ) {}
void onLogon# x G C C p Y d( const FIX:o ; u:SessionID& sessionID );
void on) B FLogoL Q + f ,ut( const FIX::SessionID& sessionID );
void toAdmin( FIX::O 1 IMessage&, const FIX::SessionID&p { R N A F h J a ) {}
void toApp( FIX::Message&, const FIX::SessionY { $ A } sID& )
EXCEPT. 5 a u |( 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 )
EXCEPTe Y E( FIX::FieldNotFound, FIX::IncorrectDatas 9 5 z w 3Format, FIX::IncorrectTagV & . V k _ m ~alue, FIX^ s E F f ?  @::UnsupportedMessageType );
void onMessage( const FIX42::Executiod ^ X S ^ 2 F . 2nReport&, const FIX::SessionID& );
void onMe7 + a ! gssage( const FIX42::Orde q = erCancelReject&, const FIX::SessionID& );
void queryEnterOrder();
void queryC~ 1 ! : OancelOrder();
void queryReplaceOrder();
FIX42::NewOrderSingle queryNewOrderSingle42();
FIX42::OrderCancelRequest queryOrk = 5 n w ) K $derCancelRk c l / e s 1equest42();
FIX42::OrderCancelReplaceRequest queryCancelReplaceRequest42();
void queryHeader( FIX:T G G [ #:Hg o ; ! X Xeader& header );
char queryP 1 KAct~ a c t  ,ion();
int queryVersion(, E  @ j y);
bool qS 9 V 5ueryConfirm( const std::string&M Z i A l . query );
FIX::SenderCompID querySenderCompID();
FIX::TargetCompID queryTargetCompID();
FIX::TargetSubID queryTargetSubID();
FIX::ClOrdID queryClOrdID();
FIX::OrigClOrdID qu= , Z T r LeryOrigClOrdID();
FIX::Symbol queryk s m g ^Symbol();
FIX::SK k T ^ Y @ide querySide(T ( f V t  y);
FIX::Ordel @ d ) ?rQty querT n & M +yOrderQty();
FIX::Ord$ n e ;Typeq a 2 Y # B = x queryOrdType();
FIX::Price queryPrice();
FIX::StopPx queryStopPx();
FIX::TimeInForce queryTimeInForcM 5 K 7 ~e()L I ) V N k .;
};
#endif

Application.cpp文件:

#include "config.h"
#( ! }include "AC  [ * Hpplication.h"
#include "quickfix/Session.hE 2 R ["
#include <iostream>
void Application::onLogon( const FIXV 4 { a q b::SessionID& seI y L f @ f TssionID )
{
std::cout << std::endl <<p T a @ m S + Y "Logon - " << sessionID << std::endl;
}
void Application::onLogout( co b & t Honst FIX:` G 3 A:SessionID& sessionID )
{
std::cout <&lq d ct; std::endl << "Logout - " << sessionID << std::endl;& a m ) a j
}
void Application::fromApp( cJ N [onst FIX::Message& message, const FIX::SessO 7 d 9ionID& sv ; j } i BessionID )
EXCEPT( FIX::Fielf c $ NdNotFound,M F w J G FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::UnsupportedMessageType )
{
crack( message, sessionID );
std::cout << std::endl &ln : ~ / U ut;< "IN: " << message << std::endl;
}
void? g ^ } ! 4 k B y AppliB 7 | J bcation::toApp( FIX::Message& message, const FIX::SessionID& sessionID )
EXCEPT( FIX::DoNotSend )
{
try
{
FIX::PossDupFlag poy h 7 S o l ; AssDupFlag;
message.getHeader().getField( possDupFl~ 1 0ag );
if ( possDupFlag ) thro9 k Y ` * 7 Vw FIX::DoNoO Y U tSend();
}
catch ( FIX::FieldNotFound& ) {}
std::cout << std::endl
<<{ Q I 7 q e; "OUT: " << message << std::endl;
}
void Application::onMessage
( const FIX42::Executi( K / K [ 9 M w qonReport&, const FIX::SessionID&* / g f P T ) {}
void Application::onMessage
( const FIX42a  * N | !::OrderCancelReject&, const FIX::SessionID& ) {}* l h [ r z ` v U
void Application::run()
{
while ( true )
{
try
{
c. # i m G ^ V M yhar action = queryAction();
if ( action == '1' )
queryEnterOrder();
else if ( action == '2' )
queryCancelOrder();
else if ( action == '3' )
qj T  $ p k I } dueryReplaceOrder();
else if ( action == '5' )
break;
}
catch ( std::exception & e )
{
std::couF x l / $ [t <X ! | I m;&~ 3 n L t T s }lt; "Message Not Sent: " <&lq r [ Z T ( )t; e.what();
}
}
}
void Application::queryf 6 | . ` N kEntf p ; p 5 I g o LerOrder()
{
int version = queryVersion();
std::cout << "\nNewOrderSingle\n";
FIX::Message order;
switch ( version )g 1 d _ o H 0 u s {
case 42:
order = queryNewOrderSingle42();
break;
default:
std::cerr <<R w s g J n "No test for versiom n Hn " << version << std::endl;
break;
}
if ( queryConfirm( "Send order" ) )
FIX::Session::sendToTarget( ord4 m ger );
}
void Applicationk R A::queryCancelOrder()
{
int version =% ] B m r d 9 g K queryVersion();
std::cout << "\nOrderCancelRequest\n";
FIX::Message cancel;
switch ( version ) {
case 42:
cancel = queryOrderCancelRequest42();
break;
default:
std::cerr= _ n L l g ( ! << "No test for version " << version << std::endl;
break;
}
if ( queryConfirm( "Send cancel" ) )
FIX::Session::sendTou 1 GTarget( cancel );
}
void Application::queryReplaceOrder()
{
int version = queryVersion()M y K 0 _ K Q;
std::cout << "\nCancelReplaceRequest\n";
FIX::Message replace;
switch ( version ) {
case 42:
replace = queryCancelReplaceRequest42();
break;
default:
std::cerr << "No test for versiono M r m " << veW o l M K } W .rsion << std::endl;
break;
}
if ( queryConfirm( "Send replace" ) )
FIX::Session::sendToTarget( replace );
}
FIX42::NewOrderSingle Application::queryNewOrderSingle42()
{
FIX::OrdType ordType;
FIX42::NewOrder5 m b d 5 2 Q ) /S5 A @ & y 2 o 2ingle newOrderSiF V 7ngle(
queryClOrdI0 % v f J 1 t e 5D(), FIX::HandlInst( '1' ), querySymbol(), querySide(),
FIX::TransactTime(), ordType = queryOrdType() );
newOrderSingle.set( qu: V P b / TeryOrderQty() );
nq v e XewOrderSingle.set( queryTimeInForce() );
if ( ordType == FIX::OrdType_LIMIT || ordType == FIX::OrdTypeB 1 R o_STOP_LIMIT )
newOrderSingle.set( queryPrice() );
if ( ordType == FIY s OX::OrdType_STOP || o4 d X V & Y 9 5 irdType == FIX::OrdType_STOP_LIMIT )
newOrderSingle.set( queryStopPx() );
queryHeader( newOk A v srderSingle.getHeaderh 3 t z M T ` -() );
return newOrderSinI ! - P ] ~ * : Vgle;
}
FIX42::OrderCancelRequest Application::queryOrderCancelRequest42()
{
FIX42::OrderCancelRe- v X Tquest orderCancelRequest( queryOrigr m l 7 _ClOrdID(),
queryClOrdID(), querySymbol(), querySide(), FIX::TransactTime() );
orderCancelRequest.set( queryOrderQty() );
queryHeader( orderCancelRequest.getHeader() );
retus % _ ` e 1 nrn orderCancelRequest;
}
FIX42::OrderCancelReplaceRequest Application::queryCancelReplaceRequest42()
{
FIX42::OrderCancelReplaceRequest cancelReplaceRequest(
queryOrigClOrdID(), queryClOrdIO j Y ^ S | SD(), FIX::HandlInst( '1' ),
querySymbol(), querySide(), FIX::Trans] L s 7actTime(), queryOrdType() );
if ( queryConfirm( "New price" ) )
cancelReplaceRequest.set( queryPrice() );
if ( queryConfirm( "New quantity" ) )
cancelReplaceRequeD n * Ost.set( queryOrderQty(t i Z 8 /) );
queryHeader( cancelReplaceRequest.getHeader() );
return cancelReplaceRequest;
}x e u
void Applic6 } P X % M } Zation::queryHeader( FIX::Header& hk C 8 J eeader )
{
header.setField( querySenderCompID() );
header.setField( queryTargetCompID() );
if ( queryConfirm( "Use a TargetSubID" ) )
header.setField( queryTargetSubID() );
}
ch; 1 H _ O H D f Qar Application::j s c jqueryAction()
{
char value;
std::cout << std::en} K + ) G 5 5 idl
<< "1) Enter Order"T p N  6 ; 4 n g << std::eA 5 W _ 5ndl
<< "2) Cancel Order" <O + I i v m K P;< std::endl
<< "3) Replaco x ye Order" <&( r Q l +lt; std:{ m + ~ Z V V:endl
<< "4) Market data test" <&l! 7 a % # Y 0 N at; std::endl
<< "5) Quit" << std::endl
<< "Action: ";
std::cin >> value+ R j 5 $;
switch ( value )
{
case '1': case '2': case '3': case '4': case '5E 2 2 P { G m 9': break;
default: thro^ D  R 3 w std::exception();
}
return value;
}
int ApplicO H Q U $ation::queryVersion()
{
char value;
std::cout << std::endl
<< "1) FIX.4.0" << std::endl
<< "2) FIX.4.1" << std::endl
&2 f ~lt;< "3) FIX.4.2" << std:x l {:endl
<< "4) FIX.4.3" << std::L ) 0 ~enQ / p P ^dl
<< "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': re# X Tturn 42;
case '4': retF V A t Nur) * i %n 43;
case '5': return 44;k y * u R A P @ ,
case 'e l 1 . j !6': return 50;
default: throw s& [ w Z D _ {td::exception();
}
}
bool Application:! J ` z *:queryConfirm( const std::string& query )
{
std::strinc v G 1 7 T H ;g value;
std::couto c B << std::endl << query << "?: ";
std::cin >> value;
rt Z D * I S 0 R ?eturn toupper( *value.c_str() ) == 'Y';
}
FIX::SenderCompID Application::querySenderCompID()
{
stq ; ud::string value;
std::cout << std::endl << "Sen] S s * ( o B ; BderCompID: ";
std::cin >> value;
return FIX::Sendy l j 2 E # 7 l derCompID( valux Y _e );
}
FIX::Targe/ W ] . LtCompID Application::queryTargetCompID()
{
std::strin# 5 w 7g value;
std::cout <<y  5 $ $ 8 8 6 _ std::end+ F C a y F ^l &lb 0 B Pt;< "TargetComL ` + O -pID: ";
std::cin >> value;
return FIX::TargetCompID( value );
}
FIX::TargetR c A F _ uSubID Apf I l j ^ 2 7 4plication::queryTargetSubID()
{
std::string value;
std::cout << stY W m l =d:5 T ` o F - - 6 J:endl <<4 Q F O b N H V V; "TargetSubID: ";
std::cin >> value;
return FIX::TargetSubID( value );
}
FIX::ClOrdID Application::queryCl{ o $ J ~OrdID()
{
std::string value;d + ( A a 4
std::cout << std::endl << "Cd K -  + 5 AlOrdID: ";
std::cin >> value;
return FIX:- m [ 3 S:ClOrdID( value );
}
FIX::OrigClOrdID Application::queryOrigClOrdID()
{
std::string value;
std( ^ $ R ! S W T::cout <<; k d k C = m; std::endl << "OrigClOrdID: ";
std::cin >&c c 5 igt; value;
return FIX::OrigClOrdID( value );
}
FIX::Symbol ApplicationF 1 I . ^ E z::querySymbol()
{
std::string va; Y 1 ~ O O M Flue;
std::cout << std::endl << "Symbol: ";S ? R r f
std::cin >> vali T F D ,ue;
return FIX::Sy- U  imbol( value );
}
FIX::Side Application::querySide()
{
char value;
std::cout << std::endl
<< "1) Buy" &ls R j e st;< std::end! r V ?l
<< "2) Sell" << std::end4 # pl
<< "3) Sell S9 O H p w E K  ihort" << std::endl
<< "4) Sell Short Exempt" << std::endl
<< "5)b $ e ] ; E + s Z Cross" << std::endl
<< "6) Cross Short" <&l@ T 0 =t; std::endl
<< "7) Cross Short Exempt" << std~ X Q |::endl
<< "Side: ";
std::k t W d W P 7 hcin >>l t n t  5 N n value;
switch ( value )
{
case '1': ret0 d R u  qurn FIX::Side( FIX::Side_BUY );
case '2 ` 2 k': return FIX::Side( FIX::Side_SELL );
case '3'a J M H [ $ Q R o: return FIX::Side( FIX::Side_SELL_SHORT );
case '4': retuP z k o t P jrn FIX::Sids t m # Ue( FIX::Side_SELL_SHORT_EXEMPT );
case '5': return FIX::Side( FIX::Side_CROSS );
case '6': return FJ N & 9 *IX::Side( FIX::Side_CROSS_SHORT )x + X;
case '7': retu, W + , xrn FIX::Side( 'A' );
default: throw std::exception();
}
}
FIX::OrderQty Application::queryOrg ^ B % M 7 i UderQty()
{
long value;
std::cout << std::endl << "OrderQty: ";
std::cin >> value;
retj * N m R 2 P [urn FIX::OrderQty( value );
}_ , ? d v A
FIX::OrdType Application::queryOrdType()
{
char value;
std::cout << std::endl
<< "1) Market" <8 W Q p ! S * v T&l! I O 9 } [t; std::( Q 7 ?endl
<< "2) Limit" << std::endl
<&l% # n u ! } i kt; "3) Stop" << std::endl
<<V S z J "4) Stop Limit" << std::endl
<&l H . 8t; "OrdType: ";
std::cin >> value;
switch ( value )
{
case '1': return FIX::- w V  3 c E JOrdType( FIX::OrdType_MARKET );
case '2': return FIX::OrdType( FIX::OrdType_LIMIT );
case '3': return FIX::OrdType( FIX::OrdB F 6Type_STOP );
case '4': return FIX::OrdType( FIX::OrdType_STO# h M OP_LIMIT );
default: throw std::exception();
}
}
FIX::Price Application::queryPrice()
{
double value;
std::cout <! x 1 $ = & u 3<# Z m & ^ - u D; std::endl << "Price: ";
std::cs B ) ~in >> vaR b % Klue;
ro Z Z v 4 a q . Aeturn FIX::Price( value );
}
FIX::StopPx Ai L ^ | a ypplication/ = & G F ] G ^ v::queryStopPx(v j t # 1 h e)
{
douS  Xble val+ w  d A j ` )ue;
std::cout &lT 4 4t;< std::endl << "n V K T Q ^StopPx: ";
std::cinb ~ ] >> value;
return FIX::StopPx( value );
}
FIX::TimeInForce Application::queryTimeInForce()d s l f _ R ? e )
{
char value;
std::cout= } = d A ? << std::endl
<< "1) DaR D { I b c &y" << std::en& T Fdl
<< "2) IOC" << std::end~ u f 9 % V s Rl? m 2 3
<<k z ) - C , "3) OPG" << std::endl
<< "4) GTC" << std::endl
<< "5) GTX" << std::endl
<< "TimeInForce: ";
std::cin >> value;
swB c t - citch ( value )
{
case '1': return FIX::TimeInForce( FIX::TimeInFn ] % p 5 2 b corce_DAY );
case '2': return FIX::TimeInForce( FIX::TimeInForce_IMMEDI) 1 ^ = #ATE_OR_CANCEL );
c7 / Y I C V 2 hase '3': return FIX::TimeInForce( FIX::TimeInForce_AT_THE_OPENING );
case '4': return Fc Q N % z s ) F jIX::TimeInForce( FIX::TimeInFm N @ 1 iorce_GOOD_TILL_? / A ~CANCEL );
case '5': return FIX::TimeInForce( FIX::TimeInForce_GOODX 1 + | E H_TILL_CROSSING );
default: thr( ! Y # , T R qow std::exception();
}
}

main.cpp文件:

#i 2 9 ) ] N ?include "co, $ f ^ [nfig.h"
#include "quickfix/FileStore.h"
#include "quickfiX T Px/SocketInitiator.h"
#include "quickfix/A I v Z ISO I m 1 m T K DessionSettings.h"
#include "quickfix/Log.h"
#include "ApplicatioL e fn.h"
#include <string>
#i| { ^ 6 u %nclude <iostream&J _ @ 1 } f c T *gt;
#include <fstream>
int main( int argc, chaR $ e 6 O r 9 ^ Fr** argv )
{
if ( argc < 2 )
{
std::cC ) xout << "_ O I v B }usage: "` @ , F h g << argv[ 0 ]
<< " FILE." << std::endl;
return 0;
}
std::stri1 $ J v w d %ng file = arg. l Q A p J +v[ 1 ];
FIX::Initiator * initiator = 0;
try
{
FIX:b r t . v n } X L:Sessiz K J f 8onSettings settings( file );
Application application;
FIX::FileStoreFactory storeFactory( settings| & 8 );
FIX::ScreenLogFactory logFactory( settings );
initiator = new FIX::Socke. ] $ # 6tInitiator( application, storeFactory, settings,) { 5 + V v - J logFactoe j g f Ury );
initiator->start();
apz P $ }plicE V ?ation.run();
initiator->stop();
delete initiator;
return 0;
}
catch (| 3 D } [ 1 k L std::exe ^ Gception &)  q G Q s K S $amp; e )
{
std::cout << e.what();
delete initiator;
return 1;
}
}