交易系统开发(十三)——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实现。
二、QuickFIX C++实现
1、QuickFIX 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::Po***esend);
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 proce***eadSet( 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 one rror( SocketMonitor&, socket_handle socket ) = 0;
virtual void one rror( 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 one rror( 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 one rror( 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 one rror( 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