QuickFIX源码解析
一、QuickFIX源码目录
QuickFIX主要目录如下:
doc:QuickFIX说明和简要HTML文件。
example:QuickFIX示例程序。
spec:存放FIX数据字典。
UnitTest++:单元测试框架。
test:测试脚本。
src:源代码目录。
src/C++:C++实现代码。
src/python:Python实现。
src/python2:Python2实现。
src/python3:Python3实现。
src/ruby:Ruby实现。
二、C++实现
1、C++实现简介
QuickFIX的C++实现代码位于src/C++目录,C++目录下的代码为QuickFIX实现的通用代码,使用FIX命名空间进行限定,不同FIX协议的实现放在C++目录下的不同目录,并使用相应的FIX协议版本命名空间进行限定,如FIX42协议实现目录为fix42,命名空间为FIX42。
2、XML解析
QuickFIX在pugixml parser基础上封装了PUGIXML_DOMAttributes、PUGIXML_DOMNode、PUGIXML_DOMDocument三个类,用于解析XML文件,定义在在头文件PUGIXML_DOMDocument.h中。
#ifndef FIX_PUGIXMLDOMDOCUMENT_H #define FIX_PUGIXMLDOMDOCUMENT_H #include "DOMDocument.h" #include "Exceptions.h" #include "pugixml.hpp" namespace FIX { /// XML attribute as represented by pugixml. class PUGIXML_DOMAttributes : public DOMAttributes { public: PUGIXML_DOMAttributes( pugi::xml_node pNode ) : m_pNode(pNode) {} bool get( const std::string&, std::string& ); DOMAttributes::map toMap(); private: pugi::xml_node m_pNode; }; /// XML node as represented by pugixml. class PUGIXML_DOMNode : public DOMNode { public: PUGIXML_DOMNode( pugi::xml_node pNode ) : m_pNode(pNode) {} ~PUGIXML_DOMNode() {} DOMNodePtr getFirstChildNode(); DOMNodePtr getNextSiblingNode(); DOMAttributesPtr getAttributes(); std::string getName(); std::string getText(); private: pugi::xml_node m_pNode; }; /// XML document as represented by pugixml. class PUGIXML_DOMDocument : public DOMDocument { public: PUGIXML_DOMDocument() EXCEPT ( ConfigError ); ~PUGIXML_DOMDocument(); bool load( std::istream& ); bool load( const std::string& ); bool xml( std::ostream& ); DOMNodePtr getNode( const std::string& ); private: pugi::xml_document m_pDoc; }; } #endif
开发者只需要关心PUGIXML_DOMDocument类的load()函数,用于加载XML文件。
3、数据字典解析
DataDictionary类用于解析FIX数据字典。
void DataDictionary::readFromURL( const std::string& url ) EXCEPT ( ConfigError ) { DOMDocumentPtr pDoc(new PUGIXML_DOMDocument()); if(!pDoc->load(url)) throw ConfigError(url + ": Could not parse data dictionary file"); try { readFromDocument( pDoc ); } catch( ConfigError& e ) { throw ConfigError( url + ": " + e.what() ); } } void DataDictionary::readFromDocument( const DOMDocumentPtr &pDoc ) EXCEPT ( ConfigError ) { // VERSION DOMNodePtr pFixNode = pDoc->getNode("/fix"); if(!pFixNode.get()) throw ConfigError("Could not parse data dictionary file" ", or no <fix> node found at root"); DOMAttributesPtr attrs = pFixNode->getAttributes(); std::string type = "FIX"; if(attrs->get("type", type)) { if(type != "FIX" && type != "FIXT") throw ConfigError("type attribute must be FIX or FIXT"); } std::string major; if(!attrs->get("major", major)) throw ConfigError("major attribute not found on <fix>"); std::string minor; if(!attrs->get("minor", minor)) throw ConfigError("minor attribute not found on <fix>"); setVersion(type + "." + major + "." + minor); // FIELDS DOMNodePtr pFieldsNode = pDoc->getNode("/fix/fields"); if(!pFieldsNode.get()) throw ConfigError("<fields> section not found in data dictionary"); DOMNodePtr pFieldNode = pFieldsNode->getFirstChildNode(); if(!pFieldNode.get()) throw ConfigError("No fields defined"); while(pFieldNode.get()) { if(pFieldNode->getName() == "field") { DOMAttributesPtr attrs = pFieldNode->getAttributes(); std::string name; if(!attrs->get("name", name)) throw ConfigError("<field> does not have a name attribute"); std::string number; if(!attrs->get("number", number)) throw ConfigError("<field> " + name + " does not have a number attribute"); int num = atoi(number.c_str()); std::string type; if(!attrs->get("type", type)) throw ConfigError("<field> " + name + " does not have a type attribute"); addField(num); addFieldType(num, XMLTypeToType(type)); addFieldName(num, name); DOMNodePtr pFieldValueNode = pFieldNode->getFirstChildNode(); while(pFieldValueNode.get()) { if(pFieldValueNode->getName() == "value") { DOMAttributesPtr attrs = pFieldValueNode->getAttributes(); std::string enumeration; if(!attrs->get("enum", enumeration)) throw ConfigError("<value> does not have enum attribute in field " + name); addFieldValue(num, enumeration); std::string description; if(attrs->get("description", description)) addValueName(num, enumeration, description); } RESET_AUTO_PTR(pFieldValueNode, pFieldValueNode->getNextSiblingNode()); } } RESET_AUTO_PTR(pFieldNode, pFieldNode->getNextSiblingNode()); } // HEADER if( type == "FIXT" || (type == "FIX" && major < "5") ) { DOMNodePtr pHeaderNode = pDoc->getNode("/fix/header"); if(!pHeaderNode.get()) throw ConfigError("<header> section not found in data dictionary"); DOMNodePtr pHeaderFieldNode = pHeaderNode->getFirstChildNode(); if(!pHeaderFieldNode.get()) throw ConfigError("No header fields defined"); while(pHeaderFieldNode.get()) { if(pHeaderFieldNode->getName() == "field" || pHeaderFieldNode->getName() == "group" ) { DOMAttributesPtr attrs = pHeaderFieldNode->getAttributes(); std::string name; if(!attrs->get("name", name)) throw ConfigError("<field> does not have a name attribute"); std::string required = "false"; attrs->get("required", required); addHeaderField(lookupXMLFieldNumber(pDoc.get(), name), required == "true"); } if(pHeaderFieldNode->getName() == "group") { DOMAttributesPtr attrs = pHeaderFieldNode->getAttributes(); std::string required; attrs->get("required", required); bool isRequired = (required == "Y" || required == "y"); addXMLGroup(pDoc.get(), pHeaderFieldNode.get(), "_header_", *this, isRequired); } RESET_AUTO_PTR(pHeaderFieldNode, pHeaderFieldNode->getNextSiblingNode()); } } // TRAILER if( type == "FIXT" || (type == "FIX" && major < "5") ) { DOMNodePtr pTrailerNode = pDoc->getNode("/fix/trailer"); if(!pTrailerNode.get()) throw ConfigError("<trailer> section not found in data dictionary"); DOMNodePtr pTrailerFieldNode = pTrailerNode->getFirstChildNode(); if(!pTrailerFieldNode.get()) throw ConfigError("No trailer fields defined"); while(pTrailerFieldNode.get()) { if(pTrailerFieldNode->getName() == "field" || pTrailerFieldNode->getName() == "group" ) { DOMAttributesPtr attrs = pTrailerFieldNode->getAttributes(); std::string name; if(!attrs->get("name", name)) throw ConfigError("<field> does not have a name attribute"); std::string required = "false"; attrs->get("required", required); addTrailerField(lookupXMLFieldNumber(pDoc.get(), name), required == "true"); } if(pTrailerFieldNode->getName() == "group") { DOMAttributesPtr attrs = pTrailerFieldNode->getAttributes(); std::string required; attrs->get("required", required); bool isRequired = (required == "Y" || required == "y"); addXMLGroup(pDoc.get(), pTrailerFieldNode.get(), "_trailer_", *this, isRequired); } RESET_AUTO_PTR(pTrailerFieldNode, pTrailerFieldNode->getNextSiblingNode()); } } // MSGTYPE DOMNodePtr pMessagesNode = pDoc->getNode("/fix/messages"); if(!pMessagesNode.get()) throw ConfigError("<messages> section not found in data dictionary"); DOMNodePtr pMessageNode = pMessagesNode->getFirstChildNode(); if(!pMessageNode.get()) throw ConfigError("No messages defined"); while(pMessageNode.get()) { if(pMessageNode->getName() == "message") { DOMAttributesPtr attrs = pMessageNode->getAttributes(); std::string msgtype; if(!attrs->get("msgtype", msgtype)) throw ConfigError("<message> does not have a msgtype attribute"); addMsgType(msgtype); std::string name; if(attrs->get("name", name)) addValueName( 35, msgtype, name ); DOMNodePtr pMessageFieldNode = pMessageNode->getFirstChildNode(); while( pMessageFieldNode.get() ) { if(pMessageFieldNode->getName() == "field" || pMessageFieldNode->getName() == "group") { DOMAttributesPtr attrs = pMessageFieldNode->getAttributes(); std::string name; if(!attrs->get("name", name)) throw ConfigError("<field> does not have a name attribute"); int num = lookupXMLFieldNumber(pDoc.get(), name); addMsgField(msgtype, num); std::string required; if(attrs->get("required", required) && (required == "Y" || required == "y")) { addRequiredField(msgtype, num); } } else if(pMessageFieldNode->getName() == "component") { DOMAttributesPtr attrs = pMessageFieldNode->getAttributes(); std::string required; attrs->get("required", required); bool isRequired = (required == "Y" || required == "y"); addXMLComponentFields(pDoc.get(), pMessageFieldNode.get(), msgtype, *this, isRequired); } if(pMessageFieldNode->getName() == "group") { DOMAttributesPtr attrs = pMessageFieldNode->getAttributes(); std::string required; attrs->get("required", required); bool isRequired = (required == "Y" || required == "y"); addXMLGroup(pDoc.get(), pMessageFieldNode.get(), msgtype, *this, isRequired); } RESET_AUTO_PTR(pMessageFieldNode, pMessageFieldNode->getNextSiblingNode()); } } RESET_AUTO_PTR(pMessageNode, pMessageNode->getNextSiblingNode()); } }
4、FIX消息解析
QuickFIX中使用Message类处理FIX消息,在Message.h如下:
class Header : public FieldMap { enum { REQUIRED_FIELDS = 8 }; public: Header() : FieldMap( message_order( message_order::header ), REQUIRED_FIELDS ) {} Header(const message_order & order) : FieldMap(order) {} void addGroup( const FIX::Group& group ) { FieldMap::addGroup( group.field(), group ); } void replaceGroup( unsigned num, const FIX::Group& group ) { FieldMap::replaceGroup( num, group.field(), group ); } Group& getGroup( unsigned num, FIX::Group& group ) const EXCEPT ( FieldNotFound ) { group.clear(); return static_cast < Group& > ( FieldMap::getGroup( num, group.field(), group ) ); } void removeGroup( unsigned num, const FIX::Group& group ) { FieldMap::removeGroup( num, group.field() ); } void removeGroup( const FIX::Group& group ) { FieldMap::removeGroup( group.field() ); } bool hasGroup( const FIX::Group& group ) const { return FieldMap::hasGroup( group.field() ); } bool hasGroup( unsigned num, const FIX::Group& group ) const { return FieldMap::hasGroup( num, group.field() ); } }; class Trailer : public FieldMap { enum { REQUIRED_FIELDS = 1 }; public: Trailer() : FieldMap( message_order( message_order::trailer ), REQUIRED_FIELDS ) {} Trailer(const message_order & order) : FieldMap(order) {} void addGroup( const FIX::Group& group ) { FieldMap::addGroup( group.field(), group ); } void replaceGroup( unsigned num, const FIX::Group& group ) { FieldMap::replaceGroup( num, group.field(), group ); } Group& getGroup( unsigned num, FIX::Group& group ) const EXCEPT ( FieldNotFound ) { group.clear(); return static_cast < Group& > ( FieldMap::getGroup( num, group.field(), group ) ); } void removeGroup( unsigned num, const FIX::Group& group ) { FieldMap::removeGroup( num, group.field() ); } void removeGroup( const FIX::Group& group ) { FieldMap::removeGroup( group.field() ); } bool hasGroup( const FIX::Group& group ) const { return FieldMap::hasGroup( group.field() ); } bool hasGroup( unsigned num, const FIX::Group& group ) const { return FieldMap::hasGroup( num, group.field() ); } }; /** * Base class for all %FIX messages. * * A message consists of three field maps. One for the header, the body, * and the trailer. */ class Message : public FieldMap { friend class DataDictionary; friend class Session; enum field_type { header, body, trailer }; public: Message(); /// Construct message with a specified order of fields Message( const message_order& hdrOrder, const message_order& trlOrder, const message_order& order); /// Construct a message from a string Message( const std::string& string, bool validate = true ) EXCEPT ( InvalidMessage ); /// Construct a message from a string using a data dictionary Message( const std::string& string, const FIX::DataDictionary& dataDictionary, bool validate = true ) EXCEPT ( InvalidMessage ); /// Construct a message from a string using a session and application data dictionary Message( const std::string& string, const FIX::DataDictionary& sessionDataDictionary, const FIX::DataDictionary& applicationDataDictionary, bool validate = true ) EXCEPT ( InvalidMessage ); /// Construct a message from a string using a data dictionary Message( const message_order& hdrOrder, const message_order& trlOrder, const message_order& order, const std::string& string, const FIX::DataDictionary& dataDictionary, bool validate = true ) EXCEPT ( InvalidMessage ); /// Construct a message from a string using a session and application data dictionary Message( const message_order& hdrOrder, const message_order& trlOrder, const message_order& order, const std::string& string, const FIX::DataDictionary& sessionDataDictionary, const FIX::DataDictionary& applicationDataDictionary, bool validate = true ) EXCEPT ( InvalidMessage ); Message( const Message& copy ); ~Message(); /// Set global data dictionary for encoding messages into XML static bool InitializeXML( const std::string& string ); void addGroup( const FIX::Group& group ) { FieldMap::addGroup( group.field(), group ); } void replaceGroup( unsigned num, const FIX::Group& group ) { FieldMap::replaceGroup( num, group.field(), group ); } Group& getGroup( unsigned num, FIX::Group& group ) const EXCEPT ( FieldNotFound ) { group.clear(); return static_cast < Group& > ( FieldMap::getGroup( num, group.field(), group ) ); } void removeGroup( unsigned num, const FIX::Group& group ) { FieldMap::removeGroup( num, group.field() ); } void removeGroup( const FIX::Group& group ) { FieldMap::removeGroup( group.field() ); } bool hasGroup( const FIX::Group& group ) const { return FieldMap::hasGroup( group.field() ); } bool hasGroup( unsigned num, const FIX::Group& group ) const { return FieldMap::hasGroup( num, group.field() ); } protected: // Constructor for derived classes Message( const BeginString& beginString, const MsgType& msgType ); public: /// Get a string representation of the message std::string toString( int beginStringField = FIELD::BeginString, int bodyLengthField = FIELD::BodyLength, int checkSumField = FIELD::CheckSum ) const; /// Get a string representation without making a copy std::string& toString( std::string&, int beginStringField = FIELD::BeginString, int bodyLengthField = FIELD::BodyLength, int checkSumField = FIELD::CheckSum ) const; /// Get a XML representation of the message std::string toXML() const; /// Get a XML representation without making a copy std::string& toXML( std::string& ) const; /** * Add header informations depending on a source message. * This can be used to add routing informations like OnBehalfOfCompID * and DeliverToCompID to a message. */ void reverseRoute( const Header& ); /** * Set a message based on a string representation * This will fill in the fields on the message by parsing out the string * that is passed in. It will return true on success and false * on failure. */ void setString( const std::string& string ) EXCEPT ( InvalidMessage ) { setString(string, true); } void setString( const std::string& string, bool validate ) EXCEPT ( InvalidMessage ) { setString(string, validate, 0); } void setString( const std::string& string, bool validate, const FIX::DataDictionary* pDataDictionary ) EXCEPT ( InvalidMessage ) { setString(string, validate, pDataDictionary, pDataDictionary); } void setString( const std::string& string, bool validate, const FIX::DataDictionary* pSessionDataDictionary, const FIX::DataDictionary* pApplicationDataDictionary ) EXCEPT ( InvalidMessage ); void setGroup( const std::string& msg, const FieldBase& field, const std::string& string, std::string::size_type& pos, FieldMap& map, const DataDictionary& dataDictionary ); /** * Set a messages header from a string * This is an optimization that can be used to get useful information * from the header of a FIX string without parsing the whole thing. */ bool setStringHeader( const std::string& string ); /// Getter for the message header const Header& getHeader() const { return m_header; } /// Mutable getter for the message header Header& getHeader() { return m_header; } /// Getter for the message trailer const Trailer& getTrailer() const { return m_trailer; } /// Mutable getter for the message trailer Trailer& getTrailer() { return m_trailer; } bool hasValidStructure(int& tag) const { tag = m_tag; return m_validStructure; } int bodyLength( int beginStringField = FIELD::BeginString, int bodyLengthField = FIELD::BodyLength, int checkSumField = FIELD::CheckSum ) const { return m_header.calculateLength(beginStringField, bodyLengthField, checkSumField) + calculateLength(beginStringField, bodyLengthField, checkSumField) + m_trailer.calculateLength(beginStringField, bodyLengthField, checkSumField); } int checkSum( int checkSumField = FIELD::CheckSum ) const { return ( m_header.calculateTotal(checkSumField) + calculateTotal(checkSumField) + m_trailer.calculateTotal(checkSumField) ) % 256; } bool isAdmin() const { MsgType msgType; if( m_header.getFieldIfSet( msgType ) ) return isAdminMsgType( msgType ); return false; } bool isApp() const { MsgType msgType; if( m_header.getFieldIfSet( msgType ) ) return !isAdminMsgType( msgType ); return false; } bool isEmpty() { return m_header.isEmpty() && FieldMap::isEmpty() && m_trailer.isEmpty(); } void clear() { m_tag = 0; m_validStructure = true; m_header.clear(); FieldMap::clear(); m_trailer.clear(); } static bool isAdminMsgType( const MsgType& msgType ) { if ( msgType.getValue().length() != 1 ) return false; return strchr ( "0A12345", msgType.getValue().c_str() [ 0 ] ) != 0; } static ApplVerID toApplVerID(const BeginString& value) { if( value == BeginString_FIX40 ) return ApplVerID(ApplVerID_FIX40); if( value == BeginString_FIX41 ) return ApplVerID(ApplVerID_FIX41); if( value == BeginString_FIX42 ) return ApplVerID(ApplVerID_FIX42); if( value == BeginString_FIX43 ) return ApplVerID(ApplVerID_FIX43); if( value == BeginString_FIX44 ) return ApplVerID(ApplVerID_FIX44); if( value == BeginString_FIX50 ) return ApplVerID(ApplVerID_FIX50); if( value == "FIX.5.0SP1" ) return ApplVerID(ApplVerID_FIX50SP1); if( value == "FIX.5.0SP2" ) return ApplVerID(ApplVerID_FIX50SP2); return ApplVerID(ApplVerID(value)); } static BeginString toBeginString( const ApplVerID& applVerID ) { if( applVerID == ApplVerID_FIX40 ) return BeginString(BeginString_FIX40); else if( applVerID == ApplVerID_FIX41 ) return BeginString(BeginString_FIX41); else if( applVerID == ApplVerID_FIX42 ) return BeginString(BeginString_FIX42); else if( applVerID == ApplVerID_FIX43 ) return BeginString(BeginString_FIX43); else if( applVerID == ApplVerID_FIX44 ) return BeginString(BeginString_FIX44); else if( applVerID == ApplVerID_FIX50 ) return BeginString(BeginString_FIX50); else if( applVerID == ApplVerID_FIX50SP1 ) return BeginString(BeginString_FIX50); else if( applVerID == ApplVerID_FIX50SP2 ) return BeginString(BeginString_FIX50); else return BeginString(""); } static bool isHeaderField( int field ); static bool isHeaderField( const FieldBase& field, const DataDictionary* pD = 0 ); static bool isHeaderField( int field, const DataDictionary* pD ); static bool isTrailerField( int field ); static bool isTrailerField( const FieldBase& field, const DataDictionary* pD = 0 ); static bool isTrailerField( int field, const DataDictionary* pD ); /// Returns the session ID of the intended recipient SessionID getSessionID( const std::string& qualifier = "" ) const EXCEPT ( FieldNotFound ); /// Sets the session ID of the intended recipient void setSessionID( const SessionID& sessionID ); #ifdef HAVE_EMX void setSubMessageType(const std::string & subMsgType) { m_subMsgType.assign(subMsgType); } const std::string & getSubMessageType() const { return m_subMsgType; } #endif private: FieldBase extractField( const std::string& string, std::string::size_type& pos, const DataDictionary* pSessionDD = 0, const DataDictionary* pAppDD = 0, const Group* pGroup = 0) const; static bool IsDataField( int field, const DataDictionary* pSessionDD, const DataDictionary* pAppDD ) { if( (pSessionDD && pSessionDD->isDataField( field )) || (pAppDD && pAppDD != pSessionDD && pAppDD->isDataField( field )) ) { return true; } return false; } void validate() const; std::string toXMLFields(const FieldMap& fields, int space) const; protected: mutable Header m_header; mutable Trailer m_trailer; bool m_validStructure; int m_tag; #ifdef HAVE_EMX std::string m_subMsgType; #endif static SmartPtr<DataDictionary> s_dataDictionary; }; /*! @} */ inline std::ostream& operator << ( std::ostream& stream, const Message& message ) { std::string str; stream << message.toString( str ); return stream; } /// Parse the type of a message from a string. inline MsgType identifyType( const std::string& message ) EXCEPT ( MessageParseError ) { std::string::size_type pos = message.find( "\001" "35=" ); if ( pos == std::string::npos ) throw MessageParseError(); std::string::size_type startValue = pos + 4; std::string::size_type soh = message.find_first_of( '\001', startValue ); if ( soh == std::string::npos ) throw MessageParseError(); std::string value = message.substr( startValue, soh - startValue ); return MsgType( value ); }
Message.h中定义的Message类继承自类FieldMap,是不同FIX协议版本实现的Message基类,并且包含3个FiledMap,分别为消息头、消息体、消息尾。
FieldMap类是Message类的基类,用于存储和组织FIX消息字段集合,如消息头、消息体、消息尾。
5、不同FIX协议实现
src/C++目录中fix40、fix41、fix42、fix43、fix44、fix50、fix50sp1、fix50sp2、fixt11是针对不同FIX协议版本的实现,其代码使用不同命名空间进行限定。FIX42的Message.h文件如下:
namespace FIX42 { class Header : public FIX::Header { public: FIELD_SET(*this, FIX::BeginString); FIELD_SET(*this, FIX::BodyLength); FIELD_SET(*this, FIX::MsgType); FIELD_SET(*this, FIX::SenderCompID); FIELD_SET(*this, FIX::TargetCompID); FIELD_SET(*this, FIX::OnBehalfOfCompID); FIELD_SET(*this, FIX::DeliverToCompID); FIELD_SET(*this, FIX::SecureDataLen); FIELD_SET(*this, FIX::SecureData); FIELD_SET(*this, FIX::MsgSeqNum); FIELD_SET(*this, FIX::SenderSubID); FIELD_SET(*this, FIX::SenderLocationID); FIELD_SET(*this, FIX::TargetSubID); FIELD_SET(*this, FIX::TargetLocationID); FIELD_SET(*this, FIX::OnBehalfOfSubID); FIELD_SET(*this, FIX::OnBehalfOfLocationID); FIELD_SET(*this, FIX::DeliverToSubID); FIELD_SET(*this, FIX::DeliverToLocationID); FIELD_SET(*this, FIX::PossDupFlag); FIELD_SET(*this, FIX::PossResend); FIELD_SET(*this, FIX::SendingTime); FIELD_SET(*this, FIX::OrigSendingTime); FIELD_SET(*this, FIX::XmlDataLen); FIELD_SET(*this, FIX::XmlData); FIELD_SET(*this, FIX::MessageEncoding); FIELD_SET(*this, FIX::LastMsgSeqNumProcessed); FIELD_SET(*this, FIX::OnBehalfOfSendingTime); }; class Trailer : public FIX::Trailer { public: FIELD_SET(*this, FIX::SignatureLength); FIELD_SET(*this, FIX::Signature); FIELD_SET(*this, FIX::CheckSum); }; class Message : public FIX::Message { public: Message( const FIX::MsgType& msgtype ) : FIX::Message( FIX::BeginString("FIX.4.2"), msgtype ) {} Message(const FIX::Message& m) : FIX::Message(m) {} Message(const Message& m) : FIX::Message(m) {} Header& getHeader() { return (Header&)m_header; } const Header& getHeader() const { return (Header&)m_header; } Trailer& getTrailer() { return (Trailer&)m_trailer; } const Trailer& getTrailer() const { return (Trailer&)m_trailer; } }; }
FIX42协议解析的MessageCracker类定义如下:
namespace FIX42 { class MessageCracker { public: virtual ~MessageCracker() {} virtual void onMessage( const Message&, const FIX::SessionID& ) { throw FIX::UnsupportedMessageType(); } virtual void onMessage( Message&, const FIX::SessionID& ) { throw FIX::UnsupportedMessageType(); } virtual void onMessage( const Heartbeat&, const FIX::SessionID& ) {} virtual void onMessage( const TestRequest&, const FIX::SessionID& ) {} virtual void onMessage( const ResendRequest&, const FIX::SessionID& ) {} virtual void onMessage( const Reject&, const FIX::SessionID& ) {} virtual void onMessage( const SequenceReset&, const FIX::SessionID& ) {} virtual void onMessage( const Logout&, const FIX::SessionID& ) {} virtual void onMessage( const ExecutionReport&, const FIX::SessionID& ) { throw FIX::UnsupportedMessageType(); } virtual void onMessage( const OrderCancelReject&, const FIX::SessionID& ) { throw FIX::UnsupportedMessageType(); } virtual void onMessage( const Logon&, const FIX::SessionID& ) {} virtual void onMessage( const NewOrderSingle&, const FIX::SessionID& ) { throw FIX::UnsupportedMessageType(); } virtual void onMessage( const OrderCancelRequest&, const FIX::SessionID& ) { throw FIX::UnsupportedMessageType(); } virtual void onMessage( const OrderStatusRequest&, const FIX::SessionID& ) { throw FIX::UnsupportedMessageType(); } virtual void onMessage( Heartbeat&, const FIX::SessionID& ) {} public: void crack( const Message& message, const FIX::SessionID& sessionID ) { const std::string& msgTypeValue = message.getHeader().getField( FIX::FIELD::MsgType ); if( msgTypeValue == "0" ) onMessage( (const Heartbeat&)message, sessionID ); else if( msgTypeValue == "1" ) onMessage( (const TestRequest&)message, sessionID ); else if( msgTypeValue == "2" ) onMessage( (const ResendRequest&)message, sessionID ); else if( msgTypeValue == "3" ) onMessage( (const Reject&)message, sessionID ); else if( msgTypeValue == "4" ) onMessage( (const SequenceReset&)message, sessionID ); else if( msgTypeValue == "5" ) onMessage( (const Logout&)message, sessionID ); else if( msgTypeValue == "6" ) onMessage( (const IOI&)message, sessionID ); else if( msgTypeValue == "7" ) onMessage( (const Advertisement&)message, sessionID ); else if( msgTypeValue == "8" ) onMessage( (const ExecutionReport&)message, sessionID ); else if( msgTypeValue == "9" ) onMessage( (const OrderCancelReject&)message, sessionID ); else if( msgTypeValue == "A" ) onMessage( (const Logon&)message, sessionID ); else if( msgTypeValue == "B" ) onMessage( (const News&)message, sessionID ); else if( msgTypeValue == "C" ) onMessage( (const Email&)message, sessionID ); else if( msgTypeValue == "D" ) onMessage( (const NewOrderSingle&)message, sessionID ); else if( msgTypeValue == "E" ) onMessage( (const NewOrderList&)message, sessionID ); else if( msgTypeValue == "F" ) onMessage( (const OrderCancelRequest&)message, sessionID ); else if( msgTypeValue == "G" ) onMessage( (const OrderCancelReplaceRequest&)message, sessionID ); else if( msgTypeValue == "H" ) onMessage( (const OrderStatusRequest&)message, sessionID ); else if( msgTypeValue == "J" ) onMessage( (const Allocation&)message, sessionID ); else if( msgTypeValue == "K" ) onMessage( (const ListCancelRequest&)message, sessionID ); else if( msgTypeValue == "L" ) onMessage( (const ListExecute&)message, sessionID ); else if( msgTypeValue == "M" ) onMessage( (const ListStatusRequest&)message, sessionID ); else if( msgTypeValue == "N" ) onMessage( (const ListStatus&)message, sessionID ); else if( msgTypeValue == "P" ) onMessage( (const AllocationInstructionAck&)message, sessionID ); else if( msgTypeValue == "Q" ) onMessage( (const DontKnowTrade&)message, sessionID ); else if( msgTypeValue == "R" ) onMessage( (const QuoteRequest&)message, sessionID ); else if( msgTypeValue == "S" ) onMessage( (const Quote&)message, sessionID ); else if( msgTypeValue == "T" ) onMessage( (const SettlementInstructions&)message, sessionID ); else if( msgTypeValue == "V" ) onMessage( (const MarketDataRequest&)message, sessionID ); else if( msgTypeValue == "W" ) onMessage( (const MarketDataSnapshotFullRefresh&)message, sessionID ); else if( msgTypeValue == "X" ) onMessage( (const MarketDataIncrementalRefresh&)message, sessionID ); else if( msgTypeValue == "Y" ) onMessage( (const MarketDataRequestReject&)message, sessionID ); else if( msgTypeValue == "Z" ) onMessage( (const QuoteCancel&)message, sessionID ); else if( msgTypeValue == "a" ) onMessage( (const QuoteStatusRequest&)message, sessionID ); else if( msgTypeValue == "b" ) onMessage( (const QuoteAcknowledgement&)message, sessionID ); else if( msgTypeValue == "c" ) onMessage( (const SecurityDefinitionRequest&)message, sessionID ); else if( msgTypeValue == "d" ) onMessage( (const SecurityDefinition&)message, sessionID ); else if( msgTypeValue == "e" ) onMessage( (const SecurityStatusRequest&)message, sessionID ); else if( msgTypeValue == "f" ) onMessage( (const SecurityStatus&)message, sessionID ); else if( msgTypeValue == "g" ) onMessage( (const TradingSessionStatusRequest&)message, sessionID ); else if( msgTypeValue == "h" ) onMessage( (const TradingSessionStatus&)message, sessionID ); else if( msgTypeValue == "i" ) onMessage( (const MassQuote&)message, sessionID ); else if( msgTypeValue == "j" ) onMessage( (const BusinessMessageReject&)message, sessionID ); else if( msgTypeValue == "k" ) onMessage( (const BidRequest&)message, sessionID ); else if( msgTypeValue == "l" ) onMessage( (const BidResponse&)message, sessionID ); else if( msgTypeValue == "m" ) onMessage( (const ListStrikePrice&)message, sessionID ); else onMessage( message, sessionID ); } void crack( Message& message, const FIX::SessionID& sessionID ) { FIX::MsgType msgType; message.getHeader().getField(msgType); std::string msgTypeValue = msgType.getValue(); if( msgTypeValue == "0" ) onMessage( (Heartbeat&)message, sessionID ); else if( msgTypeValue == "1" ) onMessage( (TestRequest&)message, sessionID ); else if( msgTypeValue == "2" ) onMessage( (ResendRequest&)message, sessionID ); else if( msgTypeValue == "3" ) onMessage( (Reject&)message, sessionID ); else if( msgTypeValue == "4" ) onMessage( (SequenceReset&)message, sessionID ); else if( msgTypeValue == "5" ) onMessage( (Logout&)message, sessionID ); else if( msgTypeValue == "6" ) onMessage( (IOI&)message, sessionID ); else if( msgTypeValue == "7" ) onMessage( (Advertisement&)message, sessionID ); else if( msgTypeValue == "8" ) onMessage( (ExecutionReport&)message, sessionID ); else if( msgTypeValue == "9" ) onMessage( (OrderCancelReject&)message, sessionID ); else if( msgTypeValue == "A" ) onMessage( (Logon&)message, sessionID ); else if( msgTypeValue == "B" ) onMessage( (News&)message, sessionID ); else if( msgTypeValue == "C" ) onMessage( (Email&)message, sessionID ); else if( msgTypeValue == "D" ) onMessage( (NewOrderSingle&)message, sessionID ); else if( msgTypeValue == "E" ) onMessage( (NewOrderList&)message, sessionID ); else if( msgTypeValue == "F" ) onMessage( (OrderCancelRequest&)message, sessionID ); else if( msgTypeValue == "G" ) onMessage( (OrderCancelReplaceRequest&)message, sessionID ); else if( msgTypeValue == "H" ) onMessage( (OrderStatusRequest&)message, sessionID ); else if( msgTypeValue == "J" ) onMessage( (Allocation&)message, sessionID ); else if( msgTypeValue == "K" ) onMessage( (ListCancelRequest&)message, sessionID ); else if( msgTypeValue == "L" ) onMessage( (ListExecute&)message, sessionID ); else if( msgTypeValue == "M" ) onMessage( (ListStatusRequest&)message, sessionID ); else if( msgTypeValue == "N" ) onMessage( (ListStatus&)message, sessionID ); else if( msgTypeValue == "P" ) onMessage( (AllocationInstructionAck&)message, sessionID ); else if( msgTypeValue == "Q" ) onMessage( (DontKnowTrade&)message, sessionID ); else if( msgTypeValue == "R" ) onMessage( (QuoteRequest&)message, sessionID ); else if( msgTypeValue == "S" ) onMessage( (Quote&)message, sessionID ); else if( msgTypeValue == "T" ) onMessage( (SettlementInstructions&)message, sessionID ); else if( msgTypeValue == "V" ) onMessage( (MarketDataRequest&)message, sessionID ); else if( msgTypeValue == "W" ) onMessage( (MarketDataSnapshotFullRefresh&)message, sessionID ); else if( msgTypeValue == "X" ) onMessage( (MarketDataIncrementalRefresh&)message, sessionID ); else if( msgTypeValue == "Y" ) onMessage( (MarketDataRequestReject&)message, sessionID ); else if( msgTypeValue == "Z" ) onMessage( (QuoteCancel&)message, sessionID ); else if( msgTypeValue == "a" ) onMessage( (QuoteStatusRequest&)message, sessionID ); else if( msgTypeValue == "b" ) onMessage( (QuoteAcknowledgement&)message, sessionID ); else if( msgTypeValue == "c" ) onMessage( (SecurityDefinitionRequest&)message, sessionID ); else if( msgTypeValue == "d" ) onMessage( (SecurityDefinition&)message, sessionID ); else if( msgTypeValue == "e" ) onMessage( (SecurityStatusRequest&)message, sessionID ); else if( msgTypeValue == "f" ) onMessage( (SecurityStatus&)message, sessionID ); else if( msgTypeValue == "g" ) onMessage( (TradingSessionStatusRequest&)message, sessionID ); else if( msgTypeValue == "h" ) onMessage( (TradingSessionStatus&)message, sessionID ); else if( msgTypeValue == "i" ) onMessage( (MassQuote&)message, sessionID ); else if( msgTypeValue == "j" ) onMessage( (BusinessMessageReject&)message, sessionID ); else if( msgTypeValue == "k" ) onMessage( (BidRequest&)message, sessionID ); else if( msgTypeValue == "l" ) onMessage( (BidResponse&)message, sessionID ); else if( msgTypeValue == "m" ) onMessage( (ListStrikePrice&)message, sessionID ); else onMessage( message, sessionID ); } }; }
6、TCP Socket封装
SocketConnection类封装了TCP Socket客户端连接的相关操作,IO操作使用Select,SocketConnection类定义如下:
/// Encapsulates a socket file descriptor (single-threaded). class SocketConnection : Responder { public: typedef std::set<SessionID> Sessions; SocketConnection( socket_handle s, Sessions sessions, SocketMonitor* pMonitor ); SocketConnection( SocketInitiator&, const SessionID&, socket_handle, SocketMonitor* ); virtual ~SocketConnection(); socket_handle getSocket() const { return m_socket; } Session* getSession() const { return m_pSession; } bool read( SocketConnector& s ); bool read( SocketAcceptor&, SocketServer& ); bool processQueue(); void signal() { Locker l( m_mutex ); if( m_sendQueue.size() == 1 ) m_pMonitor->signal( m_socket ); } void unsignal() { Locker l( m_mutex ); if( m_sendQueue.size() == 0 ) m_pMonitor->unsignal( m_socket ); } void onTimeout(); private: typedef std::deque<std::string, ALLOCATOR<std::string> > Queue; bool isValidSession(); void readFromSocket() EXCEPT ( SocketRecvFailed ); bool readMessage( std::string& msg ); void readMessages( SocketMonitor& s ); bool send( const std::string& ); void disconnect(); socket_handle m_socket; char m_buffer[BUFSIZ]; Parser m_parser; Queue m_sendQueue; unsigned m_sendLength; Sessions m_sessions; Session* m_pSession; SocketMonitor* m_pMonitor; Mutex m_mutex; fd_set m_fds; };
ThreadedSocketConnection类封装了支持多线程的TCP Socket客户端连接的相关操作,IO操作使用Select;SSLSocketConnection类封装了支持SSL的TCP Socket客户端连接的相关操作,IO操作使用Select;ThreadedSSLSocketConnection类封装了支持SSL以及多线程支持的TCP Socket客户端连接的相关操作,IO操作使用Select。
SocketConnector类封装了Socket连接远程服务端的操作。
SocketMonitor类封装了对Socket连接集合的事件的监听操作。
/// Monitors events on a collection of sockets. class SocketMonitor { public: class Strategy; SocketMonitor( int timeout = 0 ); virtual ~SocketMonitor(); bool addConnect(socket_handle socket ); bool addRead(socket_handle socket ); bool addWrite(socket_handle socket ); bool drop(socket_handle socket ); void signal(socket_handle socket ); void unsignal(socket_handle socket ); void block( Strategy& strategy, bool poll = 0, double timeout = 0.0 ); size_t numSockets() { return m_readSockets.size() - 1; } private: typedef std::set < socket_handle > Sockets; typedef std::queue < socket_handle > Queue; void setsockopt(); bool bind(); bool listen(); void buildSet( const Sockets&, fd_set& ); inline timeval* getTimeval( bool poll, double timeout ); inline bool sleepIfEmpty( bool poll ); void processReadSet( Strategy&, fd_set& ); void processWriteSet( Strategy&, fd_set& ); void processExceptSet( Strategy&, fd_set& ); int m_timeout; timeval m_timeval; #ifndef SELECT_DECREMENTS_TIME clock_t m_ticks; #endif socket_handle m_signal; socket_handle m_interrupt; Sockets m_connectSockets; Sockets m_readSockets; Sockets m_writeSockets; Queue m_dropped; public: class Strategy { public: virtual ~Strategy() {} virtual void onConnect( SocketMonitor&, socket_handle socket ) = 0; virtual void onEvent( SocketMonitor&, socket_handle socket ) = 0; virtual void onWrite( SocketMonitor&, socket_handle socket ) = 0; virtual void onError( SocketMonitor&, socket_handle socket ) = 0; virtual void onError( SocketMonitor& ) = 0; virtual void onTimeout( SocketMonitor& ) {} } ; };
SocketServer类封装了Socket服务端实现的相关操作,SocketServer类定义如下:
/// Listens for and accepts incoming socket connections on a port. class SocketServer { public: class Strategy; SocketServer( int timeout = 0 ); socket_handle add( int port, bool reuse = false, bool noDelay = false, int sendBufSize = 0, int rcvBufSize = 0 ) EXCEPT( SocketException& ); socket_handle accept(socket_handle socket ); void close(); bool block( Strategy& strategy, bool poll = 0, double timeout = 0.0 ); size_t numConnections() { return m_monitor.numSockets() - 1; } SocketMonitor& getMonitor() { return m_monitor; } int socketToPort(socket_handle socket ); socket_handle portToSocket( int port ); private: typedef std::map<socket_handle, SocketInfo> SocketToInfo; typedef std::map<int, SocketInfo> PortToInfo; SocketToInfo m_socketToInfo; PortToInfo m_portToInfo; SocketMonitor m_monitor; public: class Strategy { public: virtual ~Strategy() {} virtual void onConnect( SocketServer&, socket_handle acceptSocket, socket_handle socket ) = 0; virtual void onWrite( SocketServer&, socket_handle socket ) = 0; virtual bool onData( SocketServer&, socket_handle socket ) = 0; virtual void onDisconnect( SocketServer&, socket_handle socket ) = 0; virtual void onError( SocketServer& ) = 0; virtual void onTimeout( SocketServer& ) {}; }; };
7、FIX Session配置解析
SessionSettings类实现了FIX Session配置文件解析,SessionSettings.h如下:
class SessionSettings { public: SessionSettings() { m_resolveEnvVars = false; } SessionSettings( std::istream& stream, bool resolveEnvVars = false ) EXCEPT ( ConfigError ); SessionSettings( const std::string& file, bool resolveEnvVars = false ) EXCEPT ( ConfigError ); /// Check if session setings are present const bool has( const SessionID& ) const; /// Get a dictionary for a session. const Dictionary& get( const SessionID& ) const EXCEPT ( ConfigError ); /// Set a dictionary for a session void set( const SessionID&, Dictionary ) EXCEPT ( ConfigError ); /// Get global default settings const Dictionary& get() const { return m_defaults; } /// Set global default settings void set( const Dictionary& defaults ) EXCEPT ( ConfigError ); /// Number of session settings size_t size() const { return m_settings.size(); } typedef std::map < SessionID, Dictionary > Dictionaries; std::set < SessionID > getSessions() const; private: void validate( const Dictionary& ) const EXCEPT ( ConfigError ); Dictionaries m_settings; Dictionary m_defaults; bool m_resolveEnvVars; // while reading, replace $var, $(var) and ${var} by environment variable var friend std::istream& operator>>( std::istream&, SessionSettings& ) EXCEPT ( ConfigError ); friend std::ostream& operator<<( std::ostream&, const SessionSettings& ); };
8、FIX Session封装
FIX::Session提供了FIX Session的相关操作,常用的sendToTarget方法声明如下:
static bool FIX::Session::sendToTarget( Message& message, const std::string& qualifier = "" ) EXCEPT ( SessionNotFound ); static bool FIX::Session::sendToTarget( Message& message, const SessionID& sessionID ) EXCEPT ( SessionNotFound ); static bool FIX::Session::sendToTarget( Message&, const SenderCompID& senderCompID, const TargetCompID& targetCompID, const std::string& qualifier = "" ) EXCEPT ( SessionNotFound ); static bool FIX::Session::sendToTarget( Message& message, const std::string& senderCompID, const std::string& targetCompID, const std::string& qualifier = "" ) EXCEPT ( SessionNotFound );
9、SocketInitiator
QuickFIX中,Initiator客户端基于SocketConnection客户端连接实现,SocketInitiator类定义如下:
/// Socket implementation of Initiator. class SocketInitiator : public Initiator, SocketConnector::Strategy { public: SocketInitiator( Application&, MessageStoreFactory&, const SessionSettings& ) EXCEPT ( ConfigError ); SocketInitiator( Application&, MessageStoreFactory&, const SessionSettings&, LogFactory& ) EXCEPT ( ConfigError ); virtual ~SocketInitiator(); private: typedef std::map < socket_handle, SocketConnection* > SocketConnections; typedef std::map < SessionID, int > SessionToHostNum; void onConfigure( const SessionSettings& ) EXCEPT ( ConfigError ); void onInitialize( const SessionSettings& ) EXCEPT ( RuntimeError ); void onStart(); bool onPoll( double timeout ); void onStop(); void doConnect( const SessionID&, const Dictionary& d ); void onConnect( SocketConnector&, socket_handle); void onWrite( SocketConnector&, socket_handle); bool onData( SocketConnector&, socket_handle); void onDisconnect( SocketConnector&, socket_handle); void onError( SocketConnector& ); void onTimeout( SocketConnector& ); void getHost( const SessionID&, const Dictionary&, std::string&, short&, std::string&, short& ); SessionSettings m_settings; SessionToHostNum m_sessionToHostNum; SocketConnector m_connector; SocketConnections m_pendingConnections; SocketConnections m_connections; time_t m_lastConnect; int m_reconnectInterval; bool m_noDelay; int m_sendBufSize; int m_rcvBufSize; };
SSLSocketInitiator是支持SSL的Initiator客户端实现。
ThreadedSocketInitiator是支持多线程的Initiator客户端实现。
ThreadedSSLSocketInitiator是支持SSL和多线程的Initiator客户端实现。
10、SocketAcceptor
QuickFIX中,Acceptor服务端基于SocketServer实现。SocketAcceptor类定义如下:
/// Socket implementation of Acceptor. class SocketAcceptor : public Acceptor, SocketServer::Strategy { friend class SocketConnection; public: SocketAcceptor( Application&, MessageStoreFactory&, const SessionSettings& ) EXCEPT ( ConfigError ); SocketAcceptor( Application&, MessageStoreFactory&, const SessionSettings&, LogFactory& ) EXCEPT ( ConfigError ); virtual ~SocketAcceptor(); private: bool readSettings( const SessionSettings& ); typedef std::set < SessionID > Sessions; typedef std::map < int, Sessions > PortToSessions; typedef std::map < socket_handle, SocketConnection* > SocketConnections; void onConfigure( const SessionSettings& ) EXCEPT ( ConfigError ); void onInitialize( const SessionSettings& ) EXCEPT ( RuntimeError ); void onStart(); bool onPoll( double timeout ); void onStop(); void onConnect( SocketServer&, socket_handle, socket_handle ); void onWrite( SocketServer&, socket_handle ); bool onData( SocketServer&, socket_handle ); void onDisconnect( SocketServer&, socket_handle ); void onError( SocketServer& ); void onTimeout( SocketServer& ); SocketServer* m_pServer; PortToSessions m_portToSessions; SocketConnections m_connections; };
SSLSocketAcceptor是支持SSL的Acceptor应用实现。
ThreadedSocketAcceptor是支持多线程的Acceptor应用实现。
ThreadedSSLSocketAcceptor是支持SSL和多线程的Acceptor应用实现。
11、Fix Application
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; };
对于FIX应用开发,除了实现FIX::Application接口,还需要重新实现FIX::MessageCracker从具体的FIX协议版本实现继承而来的onMessage方法,如FIX42::MessageCracker部分接口如下:
class MessageCracker { public: virtual ~MessageCracker() {} virtual void onMessage( const Message&, const FIX::SessionID& ) { throw FIX::UnsupportedMessageType(); } virtual void onMessage( Message&, const FIX::SessionID& ) { throw FIX::UnsupportedMessageType(); } virtual void onMessage( const Heartbeat&, const FIX::SessionID& ){} virtual void onMessage( const TestRequest&, const FIX::SessionID& ){} virtual void onMessage( const ResendRequest&, const FIX::SessionID& ){} virtual void onMessage( const Reject&, const FIX::SessionID& ){} virtual void onMessage( const SequenceReset&, const FIX::SessionID& ){} virtual void onMessage( const Logout&, const FIX::SessionID& ){} virtual void onMessage( const ExecutionReport&, const FIX::SessionID& ) { throw FIX::UnsupportedMessageType(); } virtual void onMessage( const OrderCancelReject&, const FIX::SessionID& ) { throw FIX::UnsupportedMessageType(); } virtual void onMessage( const Logon&, const FIX::SessionID& ){} virtual void onMessage( const NewOrderSingle&, const FIX::SessionID& ) { throw FIX::UnsupportedMessageType(); } virtual void onMessage( const OrderCancelRequest&, const FIX::SessionID& ) { throw FIX::UnsupportedMessageType(); } virtual void onMessage( const OrderStatusRequest&, const FIX::SessionID& ) { throw FIX::UnsupportedMessageType(); } virtual void onMessage( const BusinessMessageReject&, const FIX::SessionID& ){} virtual void onMessage( Heartbeat&, const FIX::SessionID& ) {} virtual void onMessage( TestRequest&, const FIX::SessionID& ) {} virtual void onMessage( ResendRequest&, const FIX::SessionID& ) {} virtual void onMessage( Reject&, const FIX::SessionID& ) {} virtual void onMessage( SequenceReset&, const FIX::SessionID& ) {} virtual void onMessage( Logout&, const FIX::SessionID& ) {} virtual void onMessage( ExecutionReport&, const FIX::SessionID& ) {} virtual void onMessage( OrderCancelReject&, const FIX::SessionID& ) {} virtual void onMessage( Logon&, const FIX::SessionID& ) {} virtual void onMessage( NewOrderSingle&, const FIX::SessionID& ) {} virtual void onMessage( OrderCancelRequest&, const FIX::SessionID& ) {} virtual void onMessage( OrderStatusRequest&, const FIX::SessionID& ) {} };
三、示例程序
1、示例程序简介
QuickFIX示例程序位于quickfix/examples目录。
ordermatch:FIX交易网关服务,撮合限价单。
tradeclient :控制台交易客户端。
tradeclientgui:Java GUI交易客户端。
executor:对接收的限价单申报返回成交回报。
2、ordermatch
ordermatch示例包含IDGenerator、Order、OrderMatcher、Market、ordermatch、Application。
IDGenerator:ID生成器
Order:订单类
OrderMatcher:撮合引擎
Market:订单簿
Application:FIX Application
ordermatch:程序入口
IDGenerator.h文件:
#ifndef IDGENERATOR_H #define IDGENERATOR_H #include <string> #include <sstream> class IDGenerator { public: IDGenerator() : m_orderID(0), m_executionID(0) { } std::string genOrderID() { m_stream.clear(); m_stream.str(""); m_stream << ++m_orderID; return m_stream.str(); } std::string genExecutionID() { m_stream.clear(); m_stream.str(""); m_stream << ++m_executionID; return m_stream.str(); } private: long m_orderID; long m_executionID; std::stringstream m_stream; }; #endif
Order.h文件:
#ifndef ORDER_H #define ORDER_H #include <string> #include <iomanip> #include <ostream> class Order { friend std::ostream& operator<<( std::ostream&, const Order& ); public: enum Side { buy, sell }; enum Type { market, limit }; Order( const std::string& clientId, const std::string& symbol, const std::string& owner, const std::string& target, Side side, Type type, double price, long quantity ) : m_clientId( clientId ), m_symbol( symbol ), m_owner( owner ),m_target( target ), m_side( side ), m_type( type ), m_price( price ),m_quantity( quantity ) { m_openQuantity = m_quantity; m_executedQuantity = 0; m_avgExecutedPrice = 0; m_lastExecutedPrice = 0; m_lastExecutedQuantity = 0; } const std::string& getClientID() const { return m_clientId; } const std::string& getSymbol() const { return m_symbol; } const std::string& getOwner() const { return m_owner; } const std::string& getTarget() const { return m_target; } Side getSide() const { return m_side; } Type getType() const { return m_type; } double getPrice() const { return m_price; } long getQuantity() const { return m_quantity; } long getOpenQuantity() const { return m_openQuantity; } long getExecutedQuantity() const { return m_executedQuantity; } double getAvgExecutedPrice() const { return m_avgExecutedPrice; } double getLastExecutedPrice() const { return m_lastExecutedPrice; } long getLastExecutedQuantity() const { return m_lastExecutedQuantity; } bool isFilled() const { return m_quantity == m_executedQuantity; } bool isClosed() const { return m_openQuantity == 0; } void execute( double price, long quantity ) { m_avgExecutedPrice = ( ( quantity * price ) + ( m_avgExecutedPrice * m_executedQuantity ) ) / ( quantity + m_executedQuantity ); m_openQuantity -= quantity; m_executedQuantity += quantity; m_lastExecutedPrice = price; m_lastExecutedQuantity = quantity; } void cancel() { m_openQuantity = 0; } private: std::string m_clientId;// 客户端ID std::string m_symbol;// Ticker std::string m_owner;// 本地端 std::string m_target;// 目标端 Side m_side;// 买卖方向 Type m_type;// 订单类型 double m_price;// 委托价格 long m_quantity;// 委托数量 long m_openQuantity; long m_executedQuantity; double m_avgExecutedPrice; double m_lastExecutedPrice; long m_lastExecutedQuantity; }; inline std::ostream& operator<<( std::ostream& ostream, const Order& order ) { return ostream << "ID: " << order.getClientID() << " Ticker: " << order.getSymbol() << " OWNER: " << order.getOwner() << " PRICE: " << order.getPrice() << " OPENQUANTITY: " << order.getOpenQuantity(); } #endif
Market.h文件:
#ifndef MARKET_H #define MARKET_H #include "Order.h" #include <map> #include <queue> #include <string> #include <functional> class Market { public: // 插入新订单到订单队列 bool insert( const Order& order ); // 从订单队列中删除订单 void erase( const Order& order ); // 查找订单 Order& find( Order::Side side, std::string id ); // 撮合成交 bool match( std::queue < Order > & ); void display() const; protected: void match( Order& bid, Order& ask ); private: // 买单,降序排列 typedef std::multimap < double, Order, std::greater < double > > BidOrders; // 卖单,升序排序 typedef std::multimap < double, Order, std::less < double > > AskOrders; BidOrders m_bidOrders;// 订单簿:买单队列 AskOrders m_askOrders;// 订单簿:卖单队列 }; #endif
Market.cpp文件:
#include "Market.h" #include <iostream> bool Market::insert( const Order& order ) { // 买单 if ( order.getSide() == Order::buy ) m_bidOrders.insert( BidOrders::value_type( order.getPrice(), order ) ); else m_askOrders.insert( AskOrders::value_type( order.getPrice(), order ) ); return true; } void Market::erase( const Order& order ) { std::string id = order.getClientID(); // 买单 if ( order.getSide() == Order::buy ) { BidOrders::iterator i; for ( i = m_bidOrders.begin(); i != m_bidOrders.end(); ++i ) if ( i->second.getClientID() == id ) { m_bidOrders.erase( i ); return ; } } // 卖单 else if ( order.getSide() == Order::sell ) { AskOrders::iterator i; for ( i = m_askOrders.begin(); i != m_askOrders.end(); ++i ) if ( i->second.getClientID() == id ) { m_askOrders.erase( i ); return ; } } } bool Market::match( std::queue < Order > & orders ) { while ( true ) { if ( !m_bidOrders.size() || !m_askOrders.size() ) return orders.size() != 0; BidOrders::iterator iBid = m_bidOrders.begin(); AskOrders::iterator iAsk = m_askOrders.begin(); // 买单队列的第一档的价格大于等于卖单队列第一档价格 if ( iBid->second.getPrice() >= iAsk->second.getPrice() ) { Order & bid = iBid->second; Order& ask = iAsk->second; match( bid, ask ); orders.push( bid ); orders.push( ask ); if ( bid.isClosed() ) m_bidOrders.erase( iBid ); if ( ask.isClosed() ) m_askOrders.erase( iAsk ); } else return orders.size() != 0; } } Order& Market::find( Order::Side side, std::string id ) { // 买单 if ( side == Order::buy ) { BidOrders::iterator i; for ( i = m_bidOrders.begin(); i != m_bidOrders.end(); ++i ) if ( i->second.getClientID() == id ) return i->second; } // 卖单 else if ( side == Order::sell ) { AskOrders::iterator i; for ( i = m_askOrders.begin(); i != m_askOrders.end(); ++i ) if ( i->second.getClientID() == id ) return i->second; } throw std::exception(); } void Market::match( Order& bid, Order& ask ) { double price = ask.getPrice(); long quantity = 0; if ( bid.getOpenQuantity() > ask.getOpenQuantity() ) quantity = ask.getOpenQuantity(); else quantity = bid.getOpenQuantity(); bid.execute( price, quantity ); ask.execute( price, quantity ); } void Market::display() const { BidOrders::const_iterator iBid; AskOrders::const_iterator iAsk; std::cout << "BIDS:" << std::endl; for ( iBid = m_bidOrders.begin(); iBid != m_bidOrders.end(); ++iBid ) std::cout << iBid->second << std::endl; std::cout << std::endl << std::endl; std::cout << "ASKS:" << std::endl; for ( iAsk = m_askOrders.begin(); iAsk != m_askOrders.end(); ++iAsk ) std::cout << iAsk->second << std::endl; }
OrderMatch.h文件:
#ifndef ORDERMATCHER_H #define ORDERMATCHER_H #include "Market.h" #include <map> #include <iostream> class OrderMatcher { typedef std::map < std::string, Market > Markets; public: // 插入订单 bool insert( const Order& order ) { Markets::iterator i = m_markets.find( order.getSymbol() ); if ( i == m_markets.end() ) i = m_markets.insert( std::make_pair( order.getSymbol(), Market() ) ).first; return i->second.insert( order ); } // 删除订单 void erase( const Order& order ) { Markets::iterator i = m_markets.find( order.getSymbol() ); if ( i == m_markets.end() ) return ; i->second.erase( order ); } // 订单查找 Order& find(const std::string symbol, Order::Side side, std::string id ) { Markets::iterator i = m_markets.find( symbol ); if ( i == m_markets.end() ) throw std::exception(); return i->second.find( side, id ); } // 撮合成交 bool match( const std::string symbol, std::queue < Order > & orders ) { Markets::iterator i = m_markets.find( symbol ); if ( i == m_markets.end() ) return false; return i->second.match( orders ); } bool match( std::queue < Order > & orders ) { Markets::iterator i; for ( i = m_markets.begin(); i != m_markets.end(); ++i ) i->second.match( orders ); return orders.size() != 0; } void display( std::string symbol ) const { Markets::const_iterator i = m_markets.find( symbol ); if ( i == m_markets.end() ) return ; i->second.display(); } void display() const { std::cout << "SYMBOLS:" << std::endl; std::cout << "--------" << std::endl; Markets::const_iterator i; for ( i = m_markets.begin(); i != m_markets.end(); ++i ) { i->second.display(); } } private: Markets m_markets;// 全市场订单簿 }; #endif
Application.h文件:
#ifndef APPLICATION_H #define APPLICATION_H #include "IDGenerator.h" #include "OrderMatcher.h" #include "Order.h" #include <queue> #include <iostream> #include "quickfix/Application.h" #include "quickfix/MessageCracker.h" #include "quickfix/Values.h" #include "quickfix/Utility.h" #include "quickfix/Mutex.h" #include "quickfix/fix42/NewOrderSingle.h" #include "quickfix/fix42/OrderCancelRequest.h" #include "quickfix/fix42/MarketDataRequest.h" #include "quickfix/fix43/MarketDataRequest.h" class Application : public FIX::Application, public FIX::MessageCracker { public: const OrderMatcher& orderMatcher() { return m_orderMatcher; } protected: // 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 ); protected: // MessageCracker overloads void onMessage( const FIX42::NewOrderSingle&, const FIX::SessionID& ); void onMessage( const FIX42::OrderCancelRequest&, const FIX::SessionID& ); void onMessage( const FIX42::MarketDataRequest&, const FIX::SessionID& ); void onMessage( const FIX43::MarketDataRequest&, const FIX::SessionID& ); protected: // 订单处理 void processOrder( const Order& ); // 撤单处理 void processCancel( const std::string& id, const std::string& symbol, Order::Side ); // 订单成交回报 void updateOrder( const Order&, char status ); // 拒单处理 void rejectOrder( const Order& order ) { updateOrder( order, FIX::OrdStatus_REJECTED ); } // 委托ACK回报 void acceptOrder( const Order& order ) { updateOrder( order, FIX::OrdStatus_NEW ); } // 成交回报 void fillOrder( const Order& order ) { updateOrder( order, order.isFilled() ? FIX::OrdStatus_FILLED : FIX::OrdStatus_PARTIALLY_FILLED ); } // 撤单回报 void cancelOrder( const Order& order ) { updateOrder( order, FIX::OrdStatus_CANCELED ); } // 拒单回报 void rejectOrder( const FIX::SenderCompID&, const FIX::TargetCompID&, const FIX::ClOrdID& clOrdID, const FIX::Symbol& symbol, const FIX::Side& side, const std::string& message ); // 将FIX消息的买卖方向转换为订单的买卖方向 Order::Side convert( const FIX::Side& ); // 将订单的买卖方向转换为FIX消息的买卖方向 FIX::Side convert( Order::Side ); // 将FIX消息的订单类型转换为订单的类型 Order::Type convert( const FIX::OrdType& ); // 将订单类型转换为FIX的订单类型 FIX::OrdType convert( Order::Type ); private: OrderMatcher m_orderMatcher;// 订单撮合引擎 IDGenerator m_generator;// ID生成器 }; #endif
Application.cpp文件:
#include "config.h" #include "Application.h" #include "quickfix/Session.h" #include "quickfix/fix42/ExecutionReport.h" void Application::onLogon( const FIX::SessionID& sessionID ) {} void Application::onLogout( const FIX::SessionID& sessionID ) {} 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 FIX42::NewOrderSingle& message, const FIX::SessionID& ) { FIX::SenderCompID senderCompID; FIX::TargetCompID targetCompID; FIX::ClOrdID clOrdID; FIX::Symbol symbol; FIX::Side side; FIX::OrdType ordType; FIX::Price price; FIX::OrderQty orderQty; FIX::TimeInForce timeInForce( FIX::TimeInForce_DAY ); message.getHeader().get( senderCompID ); message.getHeader().get( targetCompID ); message.get( clOrdID ); message.get( symbol ); message.get( side ); message.get( ordType ); // 限价单 if ( ordType == FIX::OrdType_LIMIT ) message.get( price ); message.get( orderQty ); message.getFieldIfSet( timeInForce ); try { if ( timeInForce != FIX::TimeInForce_DAY ) throw std::logic_error( "Unsupported TIF, use Day" ); Order order( clOrdID, symbol, senderCompID, targetCompID, convert( side ), convert( ordType ), price, (long)orderQty ); // 订单处理 processOrder( order ); } catch ( std::exception & e ) { // 拒单处理 rejectOrder( senderCompID, targetCompID, clOrdID, symbol, side, e.what() ); } } void Application::onMessage( const FIX42::OrderCancelRequest& message, const FIX::SessionID& ) { FIX::OrigClOrdID origClOrdID; FIX::Symbol symbol; FIX::Side side; message.get( origClOrdID ); message.get( symbol ); message.get( side ); try { // 撤单处理 processCancel( origClOrdID, symbol, convert( side ) ); } catch ( std::exception& ) {} } void Application::onMessage( const FIX42::MarketDataRequest& message, const FIX::SessionID& ) { FIX::MDReqID mdReqID; FIX::SubscriptionRequestType subscriptionRequestType; FIX::MarketDepth marketDepth; FIX::NoRelatedSym noRelatedSym; FIX42::MarketDataRequest::NoRelatedSym noRelatedSymGroup; message.get( mdReqID ); message.get( subscriptionRequestType ); if ( subscriptionRequestType != FIX::SubscriptionRequestType_SNAPSHOT ) EXCEPT( FIX::IncorrectTagValue( subscriptionRequestType.getField() ) ); message.get( marketDepth ); message.get( noRelatedSym ); for ( int i = 1; i <= noRelatedSym; ++i ) { FIX::Symbol symbol; message.getGroup( i, noRelatedSymGroup ); noRelatedSymGroup.get( symbol ); } } void Application::onMessage( const FIX43::MarketDataRequest& message, const FIX::SessionID& ) { std::cout << message.toXML() << std::endl; } void Application::updateOrder( const Order& order, char status ) { FIX::TargetCompID targetCompID( order.getOwner() ); FIX::SenderCompID senderCompID( order.getTarget() ); FIX42::ExecutionReport fixOrder ( FIX::OrderID ( order.getClientID() ), FIX::ExecID ( m_generator.genExecutionID() ), FIX::ExecTransType ( FIX::ExecTransType_NEW ), FIX::ExecType ( status ), FIX::OrdStatus ( status ), FIX::Symbol ( order.getSymbol() ), FIX::Side ( convert( order.getSide() ) ), FIX::LeavesQty ( order.getOpenQuantity() ), FIX::CumQty ( order.getExecutedQuantity() ), FIX::AvgPx ( order.getAvgExecutedPrice() ) ); fixOrder.set( FIX::ClOrdID( order.getClientID() ) ); fixOrder.set( FIX::OrderQty( order.getQuantity() ) ); if ( status == FIX::OrdStatus_FILLED || status == FIX::OrdStatus_PARTIALLY_FILLED ) { fixOrder.set( FIX::LastShares( order.getLastExecutedQuantity() ) ); fixOrder.set( FIX::LastPx( order.getLastExecutedPrice() ) ); } try { FIX::Session::sendToTarget( fixOrder, senderCompID, targetCompID ); } catch ( FIX::SessionNotFound& ) {} } void Application::rejectOrder ( const FIX::SenderCompID& sender, const FIX::TargetCompID& target, const FIX::ClOrdID& clOrdID, const FIX::Symbol& symbol, const FIX::Side& side, const std::string& message ) { FIX::TargetCompID targetCompID( sender.getValue() ); FIX::SenderCompID senderCompID( target.getValue() ); FIX42::ExecutionReport fixOrder ( FIX::OrderID ( clOrdID.getValue() ), FIX::ExecID ( m_generator.genExecutionID() ), FIX::ExecTransType ( FIX::ExecTransType_NEW ), FIX::ExecType ( FIX::ExecType_REJECTED ), FIX::OrdStatus ( FIX::ExecType_REJECTED ), symbol, side, FIX::LeavesQty( 0 ), FIX::CumQty( 0 ), FIX::AvgPx( 0 ) ); fixOrder.set( clOrdID ); fixOrder.set( FIX::Text( message ) ); try { FIX::Session::sendToTarget( fixOrder, senderCompID, targetCompID ); } catch ( FIX::SessionNotFound& ) {} } void Application::processOrder( const Order& order ) { if ( m_orderMatcher.insert( order ) ) { // 订单委托确认回报 acceptOrder( order ); std::queue < Order > orders; // 撮合成交 m_orderMatcher.match( order.getSymbol(), orders ); // 订单成交回报 while ( orders.size() ) { fillOrder( orders.front() ); orders.pop(); } } else rejectOrder( order );// 拒单回报 } void Application::processCancel( const std::string& id, const std::string& symbol, Order::Side side ) { Order & order = m_orderMatcher.find( symbol, side, id ); order.cancel(); cancelOrder( order ); m_orderMatcher.erase( order ); } Order::Side Application::convert( const FIX::Side& side ) { switch ( side ) { case FIX::Side_BUY: return Order::buy; case FIX::Side_SELL: return Order::sell; default: throw std::logic_error( "Unsupported Side, use buy or sell" ); } } Order::Type Application::convert( const FIX::OrdType& ordType ) { switch ( ordType ) { case FIX::OrdType_LIMIT: return Order::limit; default: throw std::logic_error( "Unsupported Order Type, use limit" ); } } FIX::Side Application::convert( Order::Side side ) { switch ( side ) { case Order::buy: return FIX::Side( FIX::Side_BUY ); case Order::sell: return FIX::Side( FIX::Side_SELL ); default: throw std::logic_error( "Unsupported Side, use buy or sell" ); } } FIX::OrdType Application::convert( Order::Type type ) { switch ( type ) { case Order::limit: return FIX::OrdType( FIX::OrdType_LIMIT ); default: throw std::logic_error( "Unsupported Order Type, use limit" ); } }
ordermatch.cpp文件:
#include "config.h" #include "quickfix/FileStore.h" #include "quickfix/SocketAcceptor.h" #include "quickfix/SessionSettings.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 ]; try { FIX::SessionSettings settings( file ); Application application; FIX::FileStoreFactory storeFactory( settings ); FIX::ScreenLogFactory logFactory( settings ); FIX::SocketAcceptor acceptor( application, storeFactory, settings, logFactory ); acceptor.start(); while ( true ) { application.orderMatcher().display(); std::cout << std::endl; sleep(5); } acceptor.stop(); return 0; } catch ( std::exception & e ) { std::cout << e.what() << std::endl; return 1; } }
CMakeLists.txt文件:
cmake_minimum_required(VERSION 3.10) project(OrderMatch) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_COMPILER "g++") set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") include_directories(/usr/local/include/quickfix) link_directories(/usr/local/lib) link_libraries(quickfix) add_executable(ordermatch Application.cpp Market.cpp ordermatch.cpp)
Acceptor Session配置文件:
[DEFAULT] ConnectionType=acceptor ReconnectInterval=60 SenderCompID=GATEWAY FileStorePath=./log SocketAcceptPort=8088 [SESSION] BeginString=FIX.4.2 TargetCompID=CLIENT UseLocalTime=Y StartTime=00:00:00 EndTime=23:30:00 HeartBtInt=30 SocketReuseAddress=Y UseDataDictionary=Y DataDictionary=./FIX42.xml ResetOnLogon=Y
3、tradeclient
tradeclient是Initiator应用。
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/fix42/NewOrderSingle.h" #include "quickfix/fix42/ExecutionReport.h" #include "quickfix/fix42/OrderCancelRequest.h" #include "quickfix/fix42/OrderCancelReject.h" #include "quickfix/fix42/OrderCancelReplaceRequest.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(); void queryMarketDataRequest(); 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 == '4' ) queryMarketDataRequest(); 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 ); } void Application::queryMarketDataRequest() { int version = queryVersion(); std::cout << "\nMarketDataRequest\n"; FIX::Message md; switch (version) { default: std::cerr << "No test for version " << version << std::endl; break; } FIX::Session::sendToTarget( md ); } 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(); } }
tradeclient.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> #include <unistd.h> 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; } }
CMakeLists.txt文件:
cmake_minimum_required(VERSION 3.10) project(tradeclient) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_COMPILER "g++") set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") include_directories(/usr/local/include/quickfix) link_directories(/usr/local/lib) link_libraries(quickfix) add_executable(tradeclient Application.cpp tradeclient.cpp)
Initiator Session配置文件:
[DEFAULT] ConnectionType=initiator ReconnectInterval=60 SenderCompID=CLIENT FileStorePath=./log [SESSION] BeginString=FIX.4.2 TargetCompID=GATEWAY UseLocalTime=Y StartTime=00:00:00 EndTime=23:30:00 HeartBtInt=30 SocketConnectPort=8088 SocketConnectHost=192.168.0.102 UseDataDictionary=Y DataDictionary=./FIX42.xml
推荐参考学习资料:
#FIX协议##QuickFIX#