当前位置:网站首页>Development of trading system (XIII) -- Analysis of quickfix source code
Development of trading system (XIII) -- Analysis of quickfix source code
2022-06-25 04:02:00 【Tianshan old demon】
One 、QuickFIX Source directory
QuickFIX The main contents are as follows :
doc:QuickFIX Description and brief HTML file .
example:QuickFIX The sample program .
spec: Deposit FIX The data dictionary .
UnitTest++: Unit test framework .
test: The test script .
src: Source code directory .
src/C++:C++ Implementation code .
src/python:Python Realization .
src/python2:Python2 Realization .
src/python3:Python3 Realization .
src/ruby:Ruby Realization .
Two 、C++ Realization
1、C++ Implementation profile
QuickFIX Of C++ The implementation code is located in src/C++ Catalog ,C++ The code in the directory is QuickFIX Implementation of the general code , Use FIX Name space , Different FIX The implementation of the protocol is put in C++ Different directories under the directory , And use the corresponding FIX The protocol version namespace is qualified , Such as FIX42 The protocol implementation directory is fix42, Namespace is FIX42.
2、XML analysis
QuickFIX stay pugixml parser On the basis of the encapsulation of PUGIXML_DOMAttributes、PUGIXML_DOMNode、PUGIXML_DOMDocument Three categories , For parsing XML file , Defined in the header file PUGIXML_DOMDocument.h in .
#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
Developers just need to care PUGIXML_DOMDocument Class load() function , Used for loading XML file .
3、 Data dictionary parsing
DataDictionary Class is used to parse FIX The data dictionary .
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 Message parsing
QuickFIX Use in Message Class processing FIX news , stay Message.h as follows :
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 As defined in Message Class inherits from class FieldMap, It's different FIX The protocol version implements Message Base class , And contains 3 individual FiledMap, They are message headers 、 Message body 、 Message tail .
FieldMap Class is Message Class base class , For storing and organizing FIX Message field set , Such as the message header 、 Message body 、 Message tail .
5、 Different FIX Protocol implementation
src/C++ Directory fix40、fix41、fix42、fix43、fix44、fix50、fix50sp1、fix50sp2、fixt11 It's for different FIX Implementation of protocol version , Its code is qualified with different namespace .FIX42 Of Message.h The documents are as follows :
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 Protocol resolution MessageCracker Class is defined as follows :
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 encapsulation
SocketConnection Class encapsulation TCP Socket Client connection related operations ,IO Operation and use Select,SocketConnection Class is defined as follows :
/// 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 Class encapsulates the multithreaded TCP Socket Client connection related operations ,IO Operation and use Select;SSLSocketConnection Class encapsulates support for SSL Of TCP Socket Client connection related operations ,IO Operation and use Select;ThreadedSSLSocketConnection Class encapsulates support for SSL And multithreading support TCP Socket Client connection related operations ,IO Operation and use Select.
SocketConnector Class encapsulation Socket The operation of connecting to the remote server .
SocketMonitor Class encapsulates the pair Socket Listening operations for events connected to a collection .
/// 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 Class encapsulation Socket Related operations implemented by the server ,SocketServer Class is defined as follows :
/// 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 Configuration analysis
SessionSettings Class implements the FIX Session Profile parsing ,SessionSettings.h as follows :
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 encapsulation
FIX::Session Provides FIX Session Related operations of , frequently-used sendToTarget The method statement is as follows :
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 in ,Initiator The client is based on SocketConnection Client connection implementation ,SocketInitiator Class is defined as follows :
/// 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 It's supporting SSL Of Initiator Client implementation .
ThreadedSocketInitiator It supports multithreading Initiator Client implementation .
ThreadedSSLSocketInitiator It's supporting SSL And multithreaded Initiator Client implementation .
10、SocketAcceptor
QuickFIX in ,Acceptor Server based on SocketServer Realization .SocketAcceptor Class is defined as follows :
/// 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 It's supporting SSL Of Acceptor Application implementation .
ThreadedSocketAcceptor It supports multithreading Acceptor Application implementation .
ThreadedSSLSocketAcceptor It's supporting SSL And multithreaded Acceptor Application implementation .
11、Fix Application
FIX::Application The interface is defined as follows :
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;
};
about FIX application development , In addition to the implementation FIX::Application Interface , It needs to be re implemented FIX::MessageCracker From the concrete FIX The protocol version is inherited from the implementation onMessage Method , Such as FIX42::MessageCracker Some interfaces are as follows :
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& ) {}
};
3、 ... and 、 The sample program
1、 Sample program introduction
QuickFIX The sample program is located at quickfix/examples Catalog .
ordermatch:FIX Transaction gateway service , Match the price limit list .
tradeclient : Console Trading Client .
tradeclientgui:Java GUI Trading Client .
executor: Return the transaction return for the received price limit order .
2、ordermatch
ordermatch Examples include IDGenerator、Order、OrderMatcher、Market、ordermatch、Application.
IDGenerator:ID generator
Order: Order class
OrderMatcher: Match the engine
Market: Order book
Application:FIX Application
ordermatch: Program entrance
IDGenerator.h file :
#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 file :
#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;// client ID
std::string m_symbol;// Ticker
std::string m_owner;// Local end
std::string m_target;// Target end
Side m_side;// Business direction
Type m_type;// Order type
double m_price;// Commission price
long m_quantity;// Number of consignments
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 file :
#ifndef MARKET_H
#define MARKET_H
#include "Order.h"
#include <map>
#include <queue>
#include <string>
#include <functional>
class Market
{
public:
// Insert new order into order queue
bool insert( const Order& order );
// Delete order from order queue
void erase( const Order& order );
// Search for orders
Order& find( Order::Side side, std::string id );
// Make a deal
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;// Check , Descending order
typedef std::multimap < double, Order, std::less < double > > AskOrders;// vouchers of sale , Ascending sort
BidOrders m_bidOrders;// Order book : Pay line
AskOrders m_askOrders;// Order book : Order line
};
#endif
Market.cpp file :
#include "Market.h"
#include <iostream>
bool Market::insert( const Order& order )
{
// Check
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();
// Check
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 ;
}
}
// vouchers of sale
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();
// The price of the first tier in the buying queue is greater than or equal to the first tier price in the selling queue
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 )
{
// Check
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;
}
// vouchers of sale
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 file :
#ifndef ORDERMATCHER_H
#define ORDERMATCHER_H
#include "Market.h"
#include <map>
#include <iostream>
class OrderMatcher
{
typedef std::map < std::string, Market > Markets;
public:
// Insert order
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 );
}
// Delete 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 search
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 );
}
// Make a deal
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;// Market wide order book
};
#endif
Application.h file :
#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:
// The order processing
void processOrder( const Order& );
// Cancellation processing
void processCancel( const std::string& id, const std::string& symbol, Order::Side );
// Return on orders
void updateOrder( const Order&, char status );
// Rejection processing
void rejectOrder( const Order& order )
{
updateOrder( order, FIX::OrdStatus_REJECTED );
}
// entrust ACK Return
void acceptOrder( const Order& order )
{
updateOrder( order, FIX::OrdStatus_NEW );
}
// Transaction return
void fillOrder( const Order& order )
{
updateOrder( order,
order.isFilled() ? FIX::OrdStatus_FILLED
: FIX::OrdStatus_PARTIALLY_FILLED );
}
// Cancellation returns
void cancelOrder( const Order& order )
{
updateOrder( order, FIX::OrdStatus_CANCELED );
}
// In return
void rejectOrder( const FIX::SenderCompID&, const FIX::TargetCompID&,
const FIX::ClOrdID& clOrdID, const FIX::Symbol& symbol,
const FIX::Side& side, const std::string& message );
// take FIX The buying and selling direction of the message is converted to the buying and selling direction of the order
Order::Side convert( const FIX::Side& );
// Change the order's buying and selling direction to FIX The direction of buying and selling news
FIX::Side convert( Order::Side );
// take FIX The order type of the message is converted to the type of the order
Order::Type convert( const FIX::OrdType& );
// Convert order type to FIX Order type for
FIX::OrdType convert( Order::Type );
private:
OrderMatcher m_orderMatcher;// Order matching engine
IDGenerator m_generator;// ID generator
};
#endif
Application.cpp file :
#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 );
// Price limit list
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 );
// The order processing
processOrder( order );
}
catch ( std::exception & e )
{
// Rejection processing
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
{
// Cancellation processing
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 ) )
{
// Return on order confirmation
acceptOrder( order );
std::queue < Order > orders;
// Make a deal
m_orderMatcher.match( order.getSymbol(), orders );
// Return on orders
while ( orders.size() )
{
fillOrder( orders.front() );
orders.pop();
}
}
else
rejectOrder( order );// In return
}
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 file :
#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 file :
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 The configuration file :
[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 yes Initiator application .
Application.h file :
#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 file :
#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 file :
#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 file :
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 The configuration file :
[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
边栏推荐
猜你喜欢

MySQL modifies and deletes tables in batches according to the table prefix

谷歌创始人布林二婚破裂:被曝1月已提出与华裔妻子离婚,目前身家6314亿美元...

严重的PHP缺陷可导致QNAP NAS 设备遭RCE攻击

练习:仿真模拟福彩双色球——中500w巨奖到底有多难?跑跑代码就晓得了。

Crawler grabs the data of Douban group

Redis related-01

TensorFlow,危!抛弃者正是谷歌自己

Cesium 加载显示热力图

client-go gin的简单整合十-Update

Russian Airi Research Institute, etc. | SEMA: prediction of antigen B cell conformation characterization using deep transfer learning
随机推荐
Development of trading system (III) - risk control system
Google founder brin's second marriage broke up: it was revealed that he had filed for divorce from his Chinese wife in January, and his current fortune is $631.4 billion
China's SkyEye found suspicious signals of extraterrestrial civilization. Musk said that the Starship began its orbital test flight in July. Netinfo office: app should not force users to agree to proc
老叶的祝福
Deveco studio 3.0 editor configuration tips
windows 2003 64位系统php运行报错:1% 不是有效的 win32 应用程序
BSC parsing input data of transaction
Development of trading system (VI) -- HFT high frequency trading
Demonstration of combination of dream CAD cloud map and GIS
教你如何在winpe里安装win11系统
Lu Qi invests in quantum computing for the first time
冷热酸甜、想成就成?冷酸灵母公司登康口腔欲在深交所主板上市
Program. Launch (xxx) open file
Development of trading system (VIII) -- Construction of low delay network
程序员真人秀又来了!呼兰当主持挑灯狂补知识,SSS大佬本科竟是药学,清华朱军张敏等加入导师团...
太极图形60行代码实现经典论文,0.7秒搞定泊松盘采样,比Numpy实现快100倍
The era of copilot free is over! The official version is 67 yuan / month, and the student party and the defenders of popular open source projects can prostitute for nothing
【Proteus仿真】Arduino UNO按键控制数码管闪烁增/减显示
opencv是开源的吗?
MySQL modifies and deletes tables in batches according to the table prefix