QuickFIX源码解析

 一、QuickFIX源码目录

QuickFIX主要目录如下:

doc:QuickFIX说明和简要HTML文件。

example:QuickFIX示例程序。

spec:存放FIX数据字典。

UnitTest++:单元测试框架。

test:测试脚本。

src:源代码目录。

src/C++:C++实现代码。

src/python:Python实现。

src/python2:Python2实现。

src/python3:Python3实现。

src/ruby:Ruby实现。

二、C++实现

1、C++实现简介

QuickFIX的C++实现代码位于src/C++目录,C++目录下的代码为QuickFIX实现的通用代码,使用FIX命名空间进行限定,不同FIX协议的实现放在C++目录下的不同目录,并使用相应的FIX协议版本命名空间进行限定,如FIX42协议实现目录为fix42,命名空间为FIX42。

2、XML解析

QuickFIX在pugixml parser基础上封装了PUGIXML_DOMAttributes、PUGIXML_DOMNode、PUGIXML_DOMDocument三个类,用于解析XML文件,定义在在头文件PUGIXML_DOMDocument.h中。

#ifndef FIX_PUGIXMLDOMDOCUMENT_H
#define FIX_PUGIXMLDOMDOCUMENT_H

#include "DOMDocument.h"
#include "Exceptions.h"
#include "pugixml.hpp"

namespace FIX
{
/// XML attribute as represented by pugixml.
class PUGIXML_DOMAttributes : public DOMAttributes
{
public:
    PUGIXML_DOMAttributes( pugi::xml_node pNode )
        : m_pNode(pNode) {}

    bool get( const std::string&, std::string& );
    DOMAttributes::map toMap();

private:
    pugi::xml_node m_pNode;
};

/// XML node as represented by pugixml.
class PUGIXML_DOMNode : public DOMNode
{
public:
    PUGIXML_DOMNode( pugi::xml_node pNode )
        : m_pNode(pNode) {}
    ~PUGIXML_DOMNode() {}

    DOMNodePtr getFirstChildNode();
    DOMNodePtr getNextSiblingNode();
    DOMAttributesPtr getAttributes();
    std::string getName();
    std::string getText();

private:
    pugi::xml_node m_pNode;
};

/// XML document as represented by pugixml.
class PUGIXML_DOMDocument : public DOMDocument
{
public:
    PUGIXML_DOMDocument() EXCEPT ( ConfigError );
    ~PUGIXML_DOMDocument();

    bool load( std::istream& );
    bool load( const std::string& );
    bool xml( std::ostream& );

    DOMNodePtr getNode( const std::string& );

private:
    pugi::xml_document m_pDoc;
};
}

#endif

开发者只需要关心PUGIXML_DOMDocument类的load()函数,用于加载XML文件。

3、数据字典解析

DataDictionary类用于解析FIX数据字典。

void DataDictionary::readFromURL( const std::string& url )
EXCEPT ( ConfigError )
{
  DOMDocumentPtr pDoc(new PUGIXML_DOMDocument());
  if(!pDoc->load(url))
    throw ConfigError(url + ": Could not parse data dictionary file");
  try
  {
    readFromDocument( pDoc );
  }
  catch( ConfigError& e )
  {
    throw ConfigError( url + ": " + e.what() );
  }
}

void DataDictionary::readFromDocument( const DOMDocumentPtr &pDoc )
EXCEPT ( ConfigError )
{
  // VERSION
  DOMNodePtr pFixNode = pDoc->getNode("/fix");
  if(!pFixNode.get())
    throw ConfigError("Could not parse data dictionary file"
                      ", or no <fix> node found at root");
  DOMAttributesPtr attrs = pFixNode->getAttributes();
  std::string type = "FIX";
  if(attrs->get("type", type))
  {
    if(type != "FIX" && type != "FIXT")
      throw ConfigError("type attribute must be FIX or FIXT");
  }

  std::string major;
  if(!attrs->get("major", major))
    throw ConfigError("major attribute not found on <fix>");

  std::string minor;
  if(!attrs->get("minor", minor))
    throw ConfigError("minor attribute not found on <fix>");
  setVersion(type + "." + major + "." + minor);

  // FIELDS
  DOMNodePtr pFieldsNode = pDoc->getNode("/fix/fields");
  if(!pFieldsNode.get())
    throw ConfigError("<fields> section not found in data dictionary");

  DOMNodePtr pFieldNode = pFieldsNode->getFirstChildNode();
  if(!pFieldNode.get()) throw ConfigError("No fields defined");

  while(pFieldNode.get())
  {
    if(pFieldNode->getName() == "field")
    {
      DOMAttributesPtr attrs = pFieldNode->getAttributes();
      std::string name;
      if(!attrs->get("name", name))
        throw ConfigError("<field> does not have a name attribute");

      std::string number;
      if(!attrs->get("number", number))
        throw ConfigError("<field> " + name + " does not have a number attribute");

      int num = atoi(number.c_str());
      std::string type;
      if(!attrs->get("type", type))
        throw ConfigError("<field> " + name + " does not have a type attribute");

      addField(num);
      addFieldType(num, XMLTypeToType(type));
      addFieldName(num, name);

      DOMNodePtr pFieldValueNode = pFieldNode->getFirstChildNode();
      while(pFieldValueNode.get())
      {
        if(pFieldValueNode->getName() == "value")
        {
          DOMAttributesPtr attrs = pFieldValueNode->getAttributes();
          std::string enumeration;
          if(!attrs->get("enum", enumeration))
            throw ConfigError("<value> does not have enum attribute in field " + name);

          addFieldValue(num, enumeration);
          std::string description;
          if(attrs->get("description", description))
            addValueName(num, enumeration, description);
        }
        RESET_AUTO_PTR(pFieldValueNode, pFieldValueNode->getNextSiblingNode());
      }
    }
    RESET_AUTO_PTR(pFieldNode, pFieldNode->getNextSiblingNode());
  }

  // HEADER
  if( type == "FIXT" || (type == "FIX" && major < "5") )
  {
    DOMNodePtr pHeaderNode = pDoc->getNode("/fix/header");
    if(!pHeaderNode.get())
      throw ConfigError("<header> section not found in data dictionary");

    DOMNodePtr pHeaderFieldNode = pHeaderNode->getFirstChildNode();
    if(!pHeaderFieldNode.get()) throw ConfigError("No header fields defined");

    while(pHeaderFieldNode.get())
    {
      if(pHeaderFieldNode->getName() == "field" || pHeaderFieldNode->getName() == "group" )
      {
        DOMAttributesPtr attrs = pHeaderFieldNode->getAttributes();
        std::string name;
        if(!attrs->get("name", name))
          throw ConfigError("<field> does not have a name attribute");

        std::string required = "false";
        attrs->get("required", required);
        addHeaderField(lookupXMLFieldNumber(pDoc.get(), name), required == "true");
      }

      if(pHeaderFieldNode->getName() == "group")
      {
        DOMAttributesPtr attrs = pHeaderFieldNode->getAttributes();
        std::string required;
        attrs->get("required", required);
        bool isRequired = (required == "Y" || required == "y");
        addXMLGroup(pDoc.get(), pHeaderFieldNode.get(), "_header_", *this, isRequired);
      }

      RESET_AUTO_PTR(pHeaderFieldNode, pHeaderFieldNode->getNextSiblingNode());
    }
  }

  // TRAILER
    if( type == "FIXT" || (type == "FIX" && major < "5") )
    {
    DOMNodePtr pTrailerNode = pDoc->getNode("/fix/trailer");
    if(!pTrailerNode.get())
      throw ConfigError("<trailer> section not found in data dictionary");

    DOMNodePtr pTrailerFieldNode = pTrailerNode->getFirstChildNode();
    if(!pTrailerFieldNode.get()) throw ConfigError("No trailer fields defined");

    while(pTrailerFieldNode.get())
    {
      if(pTrailerFieldNode->getName() == "field" || pTrailerFieldNode->getName() == "group" )
      {
        DOMAttributesPtr attrs = pTrailerFieldNode->getAttributes();
        std::string name;
        if(!attrs->get("name", name))
          throw ConfigError("<field> does not have a name attribute");
        std::string required = "false";
        attrs->get("required", required);
        addTrailerField(lookupXMLFieldNumber(pDoc.get(), name), required == "true");
      }

      if(pTrailerFieldNode->getName() == "group")
      {
        DOMAttributesPtr attrs = pTrailerFieldNode->getAttributes();
        std::string required;
        attrs->get("required", required);
        bool isRequired = (required == "Y" || required == "y");
        addXMLGroup(pDoc.get(), pTrailerFieldNode.get(), "_trailer_", *this, isRequired);
      }

      RESET_AUTO_PTR(pTrailerFieldNode, pTrailerFieldNode->getNextSiblingNode());
    }
  }

  // MSGTYPE
  DOMNodePtr pMessagesNode = pDoc->getNode("/fix/messages");
  if(!pMessagesNode.get())
    throw ConfigError("<messages> section not found in data dictionary");

  DOMNodePtr pMessageNode = pMessagesNode->getFirstChildNode();
  if(!pMessageNode.get()) throw ConfigError("No messages defined");

  while(pMessageNode.get())
  {
    if(pMessageNode->getName() == "message")
    {
      DOMAttributesPtr attrs = pMessageNode->getAttributes();
      std::string msgtype;
      if(!attrs->get("msgtype", msgtype))
        throw ConfigError("<message> does not have a msgtype attribute");
      addMsgType(msgtype);

      std::string name;
      if(attrs->get("name", name))
        addValueName( 35, msgtype, name );

      DOMNodePtr pMessageFieldNode = pMessageNode->getFirstChildNode();
      while( pMessageFieldNode.get() )
      {
        if(pMessageFieldNode->getName() == "field"
           || pMessageFieldNode->getName() == "group")
        {
          DOMAttributesPtr attrs = pMessageFieldNode->getAttributes();
          std::string name;
          if(!attrs->get("name", name))
            throw ConfigError("<field> does not have a name attribute");

          int num = lookupXMLFieldNumber(pDoc.get(), name);
          addMsgField(msgtype, num);

          std::string required;
          if(attrs->get("required", required)
             && (required == "Y" || required == "y"))
          {
            addRequiredField(msgtype, num);
          }
        }
        else if(pMessageFieldNode->getName() == "component")
        {
          DOMAttributesPtr attrs = pMessageFieldNode->getAttributes();
          std::string required;
          attrs->get("required", required);
          bool isRequired = (required == "Y" || required == "y");
          addXMLComponentFields(pDoc.get(), pMessageFieldNode.get(),
                                msgtype, *this, isRequired);
        }

        if(pMessageFieldNode->getName() == "group")
        {
          DOMAttributesPtr attrs = pMessageFieldNode->getAttributes();
          std::string required;
          attrs->get("required", required);
          bool isRequired = (required == "Y" || required == "y");
          addXMLGroup(pDoc.get(), pMessageFieldNode.get(), msgtype, *this, isRequired);
        }
        RESET_AUTO_PTR(pMessageFieldNode,
                       pMessageFieldNode->getNextSiblingNode());
      }
    }
    RESET_AUTO_PTR(pMessageNode, pMessageNode->getNextSiblingNode());
  }
}

4、FIX消息解析

QuickFIX中使用Message类处理FIX消息,在Message.h如下:

class Header : public FieldMap
{
  enum { REQUIRED_FIELDS = 8 };
public:
  Header() : FieldMap( message_order( message_order::header ), REQUIRED_FIELDS )
  {}

  Header(const message_order & order) : FieldMap(order)
  {}

  void addGroup( const FIX::Group& group )
  { FieldMap::addGroup( group.field(), group ); }

  void replaceGroup( unsigned num, const FIX::Group& group )
  { FieldMap::replaceGroup( num, group.field(), group ); }

  Group& getGroup( unsigned num, FIX::Group& group ) const EXCEPT ( FieldNotFound )
  { 
    group.clear();
    return static_cast < Group& >
      ( FieldMap::getGroup( num, group.field(), group ) );
  }

  void removeGroup( unsigned num, const FIX::Group& group )
  { FieldMap::removeGroup( num, group.field() ); }

  void removeGroup( const FIX::Group& group )
  { FieldMap::removeGroup( group.field() ); }

  bool hasGroup( const FIX::Group& group ) const
  { return FieldMap::hasGroup( group.field() ); }

  bool hasGroup( unsigned num, const FIX::Group& group ) const
  { return FieldMap::hasGroup( num, group.field() ); }
};

class Trailer : public FieldMap
{
  enum { REQUIRED_FIELDS = 1 };
public:
  Trailer() : FieldMap( message_order( message_order::trailer ), REQUIRED_FIELDS )
  {}

  Trailer(const message_order & order) : FieldMap(order)
  {}

  void addGroup( const FIX::Group& group )
  { FieldMap::addGroup( group.field(), group ); }

  void replaceGroup( unsigned num, const FIX::Group& group )
  { FieldMap::replaceGroup( num, group.field(), group ); }

  Group& getGroup( unsigned num, FIX::Group& group ) const EXCEPT ( FieldNotFound )
  { group.clear();
    return static_cast < Group& >
      ( FieldMap::getGroup( num, group.field(), group ) );
  }

  void removeGroup( unsigned num, const FIX::Group& group )
  { FieldMap::removeGroup( num, group.field() ); }

  void removeGroup( const FIX::Group& group )
  { FieldMap::removeGroup( group.field() ); }

  bool hasGroup( const FIX::Group& group ) const
  { return FieldMap::hasGroup( group.field() ); }

  bool hasGroup( unsigned num, const FIX::Group& group ) const
  { return FieldMap::hasGroup( num, group.field() ); }
};


/**
 * Base class for all %FIX messages.
 *
 * A message consists of three field maps.  One for the header, the body,
 * and the trailer.
 */
class Message : public FieldMap
{
  friend class DataDictionary;
  friend class Session;
  enum field_type { header, body, trailer };
public:
  Message();
  /// Construct message with a specified order of fields
  Message( const message_order& hdrOrder, const message_order& trlOrder,  
           const message_order& order);
  /// Construct a message from a string
  Message( const std::string& string, bool validate = true )
  EXCEPT ( InvalidMessage );

  /// Construct a message from a string using a data dictionary
  Message( const std::string& string, const FIX::DataDictionary& dataDictionary,
           bool validate = true )
  EXCEPT ( InvalidMessage );

  /// Construct a message from a string using a session and application data dictionary
  Message( const std::string& string, const FIX::DataDictionary& sessionDataDictionary,
           const FIX::DataDictionary& applicationDataDictionary, bool validate = true )
  EXCEPT ( InvalidMessage );

  /// Construct a message from a string using a data dictionary
  Message( const message_order& hdrOrder, const message_order& trlOrder,  
           const message_order& order, const std::string& string, 
           const FIX::DataDictionary& dataDictionary,
           bool validate = true )
  EXCEPT ( InvalidMessage );

  /// Construct a message from a string using a session and application data dictionary
  Message( const message_order& hdrOrder, const message_order& trlOrder,  
            const message_order& order, const std::string& string, 
            const FIX::DataDictionary& sessionDataDictionary,
            const FIX::DataDictionary& applicationDataDictionary, 
            bool validate = true )
  EXCEPT ( InvalidMessage );

  Message( const Message& copy );

  ~Message();

  /// Set global data dictionary for encoding messages into XML
  static bool InitializeXML( const std::string& string );

  void addGroup( const FIX::Group& group )
  { FieldMap::addGroup( group.field(), group ); }

  void replaceGroup( unsigned num, const FIX::Group& group )
  { FieldMap::replaceGroup( num, group.field(), group ); }

  Group& getGroup( unsigned num, FIX::Group& group ) const EXCEPT ( FieldNotFound )
  { group.clear();
    return static_cast < Group& >
      ( FieldMap::getGroup( num, group.field(), group ) );
  }

  void removeGroup( unsigned num, const FIX::Group& group )
  { FieldMap::removeGroup( num, group.field() ); }

  void removeGroup( const FIX::Group& group )
  { FieldMap::removeGroup( group.field() ); }

  bool hasGroup( const FIX::Group& group ) const
  { return FieldMap::hasGroup( group.field() ); }

  bool hasGroup( unsigned num, const FIX::Group& group ) const
  { return FieldMap::hasGroup( num, group.field() ); }
protected:
  // Constructor for derived classes
  Message( const BeginString& beginString, const MsgType& msgType );
public:
  /// Get a string representation of the message
  std::string toString( int beginStringField = FIELD::BeginString,
                        int bodyLengthField = FIELD::BodyLength,
                        int checkSumField = FIELD::CheckSum ) const;
  /// Get a string representation without making a copy
  std::string& toString( std::string&,
                         int beginStringField = FIELD::BeginString,
                         int bodyLengthField = FIELD::BodyLength,
                         int checkSumField = FIELD::CheckSum ) const;
  /// Get a XML representation of the message
  std::string toXML() const;
  /// Get a XML representation without making a copy
  std::string& toXML( std::string& ) const;
  /**
   * Add header informations depending on a source message.
   * This can be used to add routing informations like OnBehalfOfCompID
   * and DeliverToCompID to a message.
   */
  void reverseRoute( const Header& );

  /**
   * Set a message based on a string representation
   * This will fill in the fields on the message by parsing out the string
   * that is passed in.  It will return true on success and false
   * on failure.
   */

  void setString( const std::string& string )
  EXCEPT ( InvalidMessage )
  { setString(string, true); }

  void setString( const std::string& string, bool validate )
  EXCEPT ( InvalidMessage )
  { setString(string, validate, 0); }

  void setString( const std::string& string,
                  bool validate,
                  const FIX::DataDictionary* pDataDictionary )
  EXCEPT ( InvalidMessage )
  { setString(string, validate, pDataDictionary, pDataDictionary); }

  void setString( const std::string& string,
                  bool validate,
                  const FIX::DataDictionary* pSessionDataDictionary,
                  const FIX::DataDictionary* pApplicationDataDictionary )
  EXCEPT ( InvalidMessage );

  void setGroup( const std::string& msg, const FieldBase& field,
                 const std::string& string, std::string::size_type& pos,
                 FieldMap& map, const DataDictionary& dataDictionary );

  /**
   * Set a messages header from a string
   * This is an optimization that can be used to get useful information
   * from the header of a FIX string without parsing the whole thing.
   */
  bool setStringHeader( const std::string& string );

  /// Getter for the message header
  const Header& getHeader() const { return m_header; }

  /// Mutable getter for the message header
  Header& getHeader() { return m_header; }

  /// Getter for the message trailer
  const Trailer& getTrailer() const { return m_trailer; }

  /// Mutable getter for the message trailer
  Trailer& getTrailer() { return m_trailer; }

  bool hasValidStructure(int& tag) const
  { tag = m_tag;
    return m_validStructure;
  }

  int bodyLength( int beginStringField = FIELD::BeginString,
                  int bodyLengthField = FIELD::BodyLength,
                  int checkSumField = FIELD::CheckSum ) const
  { return m_header.calculateLength(beginStringField, bodyLengthField, checkSumField)
           + calculateLength(beginStringField, bodyLengthField, checkSumField)
           + m_trailer.calculateLength(beginStringField, bodyLengthField, checkSumField);
  }

  int checkSum( int checkSumField = FIELD::CheckSum ) const
  { return ( m_header.calculateTotal(checkSumField)
             + calculateTotal(checkSumField)
             + m_trailer.calculateTotal(checkSumField) ) % 256;
  }

  bool isAdmin() const
  { 
    MsgType msgType;
    if( m_header.getFieldIfSet( msgType ) )
      return isAdminMsgType( msgType );
    return false;
  }

  bool isApp() const
  { 
    MsgType msgType;
    if( m_header.getFieldIfSet( msgType ) )
      return !isAdminMsgType( msgType );
    return false;
  }

  bool isEmpty()
  { return m_header.isEmpty() && FieldMap::isEmpty() && m_trailer.isEmpty(); }

  void clear()
  {
    m_tag = 0;
    m_validStructure = true;
    m_header.clear();
    FieldMap::clear();
    m_trailer.clear();
  }

  static bool isAdminMsgType( const MsgType& msgType )
  { if ( msgType.getValue().length() != 1 ) return false;
    return strchr
           ( "0A12345",
             msgType.getValue().c_str() [ 0 ] ) != 0;
  }

  static ApplVerID toApplVerID(const BeginString& value)
  {
    if( value == BeginString_FIX40 )
      return ApplVerID(ApplVerID_FIX40);

    if( value == BeginString_FIX41 )
      return ApplVerID(ApplVerID_FIX41);

    if( value == BeginString_FIX42 )
      return ApplVerID(ApplVerID_FIX42);

    if( value == BeginString_FIX43 )
      return ApplVerID(ApplVerID_FIX43);

    if( value == BeginString_FIX44 )
      return ApplVerID(ApplVerID_FIX44);

    if( value == BeginString_FIX50 )
      return ApplVerID(ApplVerID_FIX50);

    if( value == "FIX.5.0SP1" )
      return ApplVerID(ApplVerID_FIX50SP1);

    if( value == "FIX.5.0SP2" )
      return ApplVerID(ApplVerID_FIX50SP2);

    return ApplVerID(ApplVerID(value));
  }

  static BeginString toBeginString( const ApplVerID& applVerID )
  {
    if( applVerID == ApplVerID_FIX40 )
      return BeginString(BeginString_FIX40);
    else if( applVerID == ApplVerID_FIX41 )
      return BeginString(BeginString_FIX41);
    else if( applVerID == ApplVerID_FIX42 )
      return BeginString(BeginString_FIX42);
    else if( applVerID == ApplVerID_FIX43 )
      return BeginString(BeginString_FIX43);
    else if( applVerID == ApplVerID_FIX44 )
      return BeginString(BeginString_FIX44);
    else if( applVerID == ApplVerID_FIX50 )
      return BeginString(BeginString_FIX50);
    else if( applVerID == ApplVerID_FIX50SP1 )
      return BeginString(BeginString_FIX50);
    else if( applVerID == ApplVerID_FIX50SP2 )
      return BeginString(BeginString_FIX50);
    else
      return BeginString("");
  }

  static bool isHeaderField( int field );
  static bool isHeaderField( const FieldBase& field,
                             const DataDictionary* pD = 0 );
  static bool isHeaderField( int field,
                             const DataDictionary* pD );

  static bool isTrailerField( int field );
  static bool isTrailerField( const FieldBase& field,
                              const DataDictionary* pD = 0 );
  static bool isTrailerField( int field,
                              const DataDictionary* pD );

  /// Returns the session ID of the intended recipient
  SessionID getSessionID( const std::string& qualifier = "" ) const
  EXCEPT ( FieldNotFound );
  /// Sets the session ID of the intended recipient
  void setSessionID( const SessionID& sessionID );

#ifdef HAVE_EMX
  void  setSubMessageType(const std::string & subMsgType) { m_subMsgType.assign(subMsgType); }
  const std::string & getSubMessageType() const { return m_subMsgType; }
#endif

private:
  FieldBase extractField(
    const std::string& string, std::string::size_type& pos,
    const DataDictionary* pSessionDD = 0, const DataDictionary* pAppDD = 0,
    const Group* pGroup = 0) const;

  static bool IsDataField(
    int field,
    const DataDictionary* pSessionDD,
    const DataDictionary* pAppDD )
  {
    if( (pSessionDD && pSessionDD->isDataField( field )) ||
        (pAppDD && pAppDD != pSessionDD && pAppDD->isDataField( field )) )
    {
      return true;
    }

    return false;
  }

  void validate() const;
  std::string toXMLFields(const FieldMap& fields, int space) const;
protected:
  mutable Header m_header;
  mutable Trailer m_trailer;
  bool m_validStructure;
  int m_tag;
#ifdef HAVE_EMX
  std::string m_subMsgType;
#endif
  static SmartPtr<DataDictionary> s_dataDictionary;
};

/*! @} */
inline std::ostream& operator <<
( std::ostream& stream, const Message& message )
{
  std::string str;
  stream << message.toString( str );
  return stream;
}

/// Parse the type of a message from a string.
inline MsgType identifyType( const std::string& message )
EXCEPT ( MessageParseError )
{
  std::string::size_type pos = message.find( "\001" "35=" );
  if ( pos == std::string::npos ) throw MessageParseError();

  std::string::size_type startValue = pos + 4;
  std::string::size_type soh = message.find_first_of( '\001', startValue );
  if ( soh == std::string::npos ) throw MessageParseError();

  std::string value = message.substr( startValue, soh - startValue );
  return MsgType( value );
}

Message.h中定义的Message类继承自类FieldMap,是不同FIX协议版本实现的Message基类,并且包含3个FiledMap,分别为消息头、消息体、消息尾。

FieldMap类是Message类的基类,用于存储和组织FIX消息字段集合,如消息头、消息体、消息尾。

5、不同FIX协议实现

src/C++目录中fix40、fix41、fix42、fix43、fix44、fix50、fix50sp1、fix50sp2、fixt11是针对不同FIX协议版本的实现,其代码使用不同命名空间进行限定。FIX42的Message.h文件如下:

namespace FIX42
{
  class Header : public FIX::Header
  {
  public:
    FIELD_SET(*this, FIX::BeginString);
    FIELD_SET(*this, FIX::BodyLength);
    FIELD_SET(*this, FIX::MsgType);
    FIELD_SET(*this, FIX::SenderCompID);
    FIELD_SET(*this, FIX::TargetCompID);
    FIELD_SET(*this, FIX::OnBehalfOfCompID);
    FIELD_SET(*this, FIX::DeliverToCompID);
    FIELD_SET(*this, FIX::SecureDataLen);
    FIELD_SET(*this, FIX::SecureData);
    FIELD_SET(*this, FIX::MsgSeqNum);
    FIELD_SET(*this, FIX::SenderSubID);
    FIELD_SET(*this, FIX::SenderLocationID);
    FIELD_SET(*this, FIX::TargetSubID);
    FIELD_SET(*this, FIX::TargetLocationID);
    FIELD_SET(*this, FIX::OnBehalfOfSubID);
    FIELD_SET(*this, FIX::OnBehalfOfLocationID);
    FIELD_SET(*this, FIX::DeliverToSubID);
    FIELD_SET(*this, FIX::DeliverToLocationID);
    FIELD_SET(*this, FIX::PossDupFlag);
    FIELD_SET(*this, FIX::PossResend);
    FIELD_SET(*this, FIX::SendingTime);
    FIELD_SET(*this, FIX::OrigSendingTime);
    FIELD_SET(*this, FIX::XmlDataLen);
    FIELD_SET(*this, FIX::XmlData);
    FIELD_SET(*this, FIX::MessageEncoding);
    FIELD_SET(*this, FIX::LastMsgSeqNumProcessed);
    FIELD_SET(*this, FIX::OnBehalfOfSendingTime);
  };

  class Trailer : public FIX::Trailer
  {
  public:
    FIELD_SET(*this, FIX::SignatureLength);
    FIELD_SET(*this, FIX::Signature);
    FIELD_SET(*this, FIX::CheckSum);
  };

  class Message : public FIX::Message
  {
  public:
    Message( const FIX::MsgType& msgtype )
    : FIX::Message(
      FIX::BeginString("FIX.4.2"), msgtype )
     {} 

    Message(const FIX::Message& m) : FIX::Message(m) {}
    Message(const Message& m) : FIX::Message(m) {}
    Header& getHeader() { return (Header&)m_header; }
    const Header& getHeader() const { return (Header&)m_header; }
    Trailer& getTrailer() { return (Trailer&)m_trailer; }
    const Trailer& getTrailer() const { return (Trailer&)m_trailer; }
  };
}

FIX42协议解析的MessageCracker类定义如下:

namespace FIX42
{

class MessageCracker
{
public:
    virtual ~MessageCracker() {}
    virtual void onMessage( const Message&, const FIX::SessionID& )
    {
        throw FIX::UnsupportedMessageType();
    }

    virtual void onMessage( Message&, const FIX::SessionID& )
    {
        throw FIX::UnsupportedMessageType();
    }

    virtual void onMessage( const Heartbeat&, const FIX::SessionID& )
    {}

    virtual void onMessage( const TestRequest&, const FIX::SessionID& )
    {}

    virtual void onMessage( const ResendRequest&, const FIX::SessionID& )
    {}

    virtual void onMessage( const Reject&, const FIX::SessionID& )
    {}

    virtual void onMessage( const SequenceReset&, const FIX::SessionID& )
    {}

    virtual void onMessage( const Logout&, const FIX::SessionID& )

    {}

    virtual void onMessage( const ExecutionReport&, const FIX::SessionID& )
    {
        throw FIX::UnsupportedMessageType();
    }

    virtual void onMessage( const OrderCancelReject&, const FIX::SessionID& )
    {
        throw FIX::UnsupportedMessageType();
    }

    virtual void onMessage( const Logon&, const FIX::SessionID& )
    {}

    virtual void onMessage( const NewOrderSingle&, const FIX::SessionID& )
    {
        throw FIX::UnsupportedMessageType();
    }

    virtual void onMessage( const OrderCancelRequest&, const FIX::SessionID& )
    {
        throw FIX::UnsupportedMessageType();
    }

    virtual void onMessage( const OrderStatusRequest&, const FIX::SessionID& )
    {
        throw FIX::UnsupportedMessageType();
    }

    virtual void onMessage( Heartbeat&, const FIX::SessionID& ) {}
public:
    void crack( const Message& message,
                const FIX::SessionID& sessionID )
    {
        const std::string& msgTypeValue
            = message.getHeader().getField( FIX::FIELD::MsgType );

        if( msgTypeValue == "0" )
            onMessage( (const Heartbeat&)message, sessionID );
        else if( msgTypeValue == "1" )
            onMessage( (const TestRequest&)message, sessionID );
        else if( msgTypeValue == "2" )
            onMessage( (const ResendRequest&)message, sessionID );
        else if( msgTypeValue == "3" )
            onMessage( (const Reject&)message, sessionID );
        else if( msgTypeValue == "4" )
            onMessage( (const SequenceReset&)message, sessionID );
        else if( msgTypeValue == "5" )
            onMessage( (const Logout&)message, sessionID );
        else if( msgTypeValue == "6" )
            onMessage( (const IOI&)message, sessionID );
        else if( msgTypeValue == "7" )
            onMessage( (const Advertisement&)message, sessionID );
        else if( msgTypeValue == "8" )
            onMessage( (const ExecutionReport&)message, sessionID );
        else if( msgTypeValue == "9" )
            onMessage( (const OrderCancelReject&)message, sessionID );
        else if( msgTypeValue == "A" )
            onMessage( (const Logon&)message, sessionID );
        else if( msgTypeValue == "B" )
            onMessage( (const News&)message, sessionID );
        else if( msgTypeValue == "C" )
            onMessage( (const Email&)message, sessionID );
        else if( msgTypeValue == "D" )
            onMessage( (const NewOrderSingle&)message, sessionID );
        else if( msgTypeValue == "E" )
            onMessage( (const NewOrderList&)message, sessionID );
        else if( msgTypeValue == "F" )
            onMessage( (const OrderCancelRequest&)message, sessionID );
        else if( msgTypeValue == "G" )
            onMessage( (const OrderCancelReplaceRequest&)message, sessionID );
        else if( msgTypeValue == "H" )
            onMessage( (const OrderStatusRequest&)message, sessionID );
        else if( msgTypeValue == "J" )
            onMessage( (const Allocation&)message, sessionID );
        else if( msgTypeValue == "K" )
            onMessage( (const ListCancelRequest&)message, sessionID );
        else if( msgTypeValue == "L" )
            onMessage( (const ListExecute&)message, sessionID );
        else if( msgTypeValue == "M" )
            onMessage( (const ListStatusRequest&)message, sessionID );
        else if( msgTypeValue == "N" )
            onMessage( (const ListStatus&)message, sessionID );
        else if( msgTypeValue == "P" )
            onMessage( (const AllocationInstructionAck&)message, sessionID );
        else if( msgTypeValue == "Q" )
            onMessage( (const DontKnowTrade&)message, sessionID );
        else if( msgTypeValue == "R" )
            onMessage( (const QuoteRequest&)message, sessionID );
        else if( msgTypeValue == "S" )
            onMessage( (const Quote&)message, sessionID );
        else if( msgTypeValue == "T" )
            onMessage( (const SettlementInstructions&)message, sessionID );
        else if( msgTypeValue == "V" )
            onMessage( (const MarketDataRequest&)message, sessionID );
        else if( msgTypeValue == "W" )
            onMessage( (const MarketDataSnapshotFullRefresh&)message, sessionID );
        else if( msgTypeValue == "X" )
            onMessage( (const MarketDataIncrementalRefresh&)message, sessionID );
        else if( msgTypeValue == "Y" )
            onMessage( (const MarketDataRequestReject&)message, sessionID );
        else if( msgTypeValue == "Z" )
            onMessage( (const QuoteCancel&)message, sessionID );
        else if( msgTypeValue == "a" )
            onMessage( (const QuoteStatusRequest&)message, sessionID );
        else if( msgTypeValue == "b" )
            onMessage( (const QuoteAcknowledgement&)message, sessionID );
        else if( msgTypeValue == "c" )
            onMessage( (const SecurityDefinitionRequest&)message, sessionID );
        else if( msgTypeValue == "d" )
            onMessage( (const SecurityDefinition&)message, sessionID );
        else if( msgTypeValue == "e" )
            onMessage( (const SecurityStatusRequest&)message, sessionID );
        else if( msgTypeValue == "f" )
            onMessage( (const SecurityStatus&)message, sessionID );
        else if( msgTypeValue == "g" )
            onMessage( (const TradingSessionStatusRequest&)message, sessionID );
        else if( msgTypeValue == "h" )
            onMessage( (const TradingSessionStatus&)message, sessionID );
        else if( msgTypeValue == "i" )
            onMessage( (const MassQuote&)message, sessionID );
        else if( msgTypeValue == "j" )
            onMessage( (const BusinessMessageReject&)message, sessionID );
        else if( msgTypeValue == "k" )
            onMessage( (const BidRequest&)message, sessionID );
        else if( msgTypeValue == "l" )
            onMessage( (const BidResponse&)message, sessionID );
        else if( msgTypeValue == "m" )
            onMessage( (const ListStrikePrice&)message, sessionID );
        else onMessage( message, sessionID );
    }

    void crack( Message& message,
                const FIX::SessionID& sessionID )
    {
        FIX::MsgType msgType;
        message.getHeader().getField(msgType);
        std::string msgTypeValue = msgType.getValue();

        if( msgTypeValue == "0" )
            onMessage( (Heartbeat&)message, sessionID );
        else if( msgTypeValue == "1" )
            onMessage( (TestRequest&)message, sessionID );
        else if( msgTypeValue == "2" )
            onMessage( (ResendRequest&)message, sessionID );
        else if( msgTypeValue == "3" )
            onMessage( (Reject&)message, sessionID );
        else if( msgTypeValue == "4" )
            onMessage( (SequenceReset&)message, sessionID );
        else if( msgTypeValue == "5" )
            onMessage( (Logout&)message, sessionID );
        else if( msgTypeValue == "6" )
            onMessage( (IOI&)message, sessionID );
        else if( msgTypeValue == "7" )
            onMessage( (Advertisement&)message, sessionID );
        else if( msgTypeValue == "8" )
            onMessage( (ExecutionReport&)message, sessionID );
        else if( msgTypeValue == "9" )
            onMessage( (OrderCancelReject&)message, sessionID );
        else if( msgTypeValue == "A" )
            onMessage( (Logon&)message, sessionID );
        else if( msgTypeValue == "B" )
            onMessage( (News&)message, sessionID );
        else if( msgTypeValue == "C" )
            onMessage( (Email&)message, sessionID );
        else if( msgTypeValue == "D" )
            onMessage( (NewOrderSingle&)message, sessionID );
        else if( msgTypeValue == "E" )
            onMessage( (NewOrderList&)message, sessionID );
        else if( msgTypeValue == "F" )
            onMessage( (OrderCancelRequest&)message, sessionID );
        else if( msgTypeValue == "G" )
            onMessage( (OrderCancelReplaceRequest&)message, sessionID );
        else if( msgTypeValue == "H" )
            onMessage( (OrderStatusRequest&)message, sessionID );
        else if( msgTypeValue == "J" )
            onMessage( (Allocation&)message, sessionID );
        else if( msgTypeValue == "K" )
            onMessage( (ListCancelRequest&)message, sessionID );
        else if( msgTypeValue == "L" )
            onMessage( (ListExecute&)message, sessionID );
        else if( msgTypeValue == "M" )
            onMessage( (ListStatusRequest&)message, sessionID );
        else if( msgTypeValue == "N" )
            onMessage( (ListStatus&)message, sessionID );
        else if( msgTypeValue == "P" )
            onMessage( (AllocationInstructionAck&)message, sessionID );
        else if( msgTypeValue == "Q" )
            onMessage( (DontKnowTrade&)message, sessionID );
        else if( msgTypeValue == "R" )
            onMessage( (QuoteRequest&)message, sessionID );
        else if( msgTypeValue == "S" )
            onMessage( (Quote&)message, sessionID );
        else if( msgTypeValue == "T" )
            onMessage( (SettlementInstructions&)message, sessionID );
        else if( msgTypeValue == "V" )
            onMessage( (MarketDataRequest&)message, sessionID );
        else if( msgTypeValue == "W" )
            onMessage( (MarketDataSnapshotFullRefresh&)message, sessionID );
        else if( msgTypeValue == "X" )
            onMessage( (MarketDataIncrementalRefresh&)message, sessionID );
        else if( msgTypeValue == "Y" )
            onMessage( (MarketDataRequestReject&)message, sessionID );
        else if( msgTypeValue == "Z" )
            onMessage( (QuoteCancel&)message, sessionID );
        else if( msgTypeValue == "a" )
            onMessage( (QuoteStatusRequest&)message, sessionID );
        else if( msgTypeValue == "b" )
            onMessage( (QuoteAcknowledgement&)message, sessionID );
        else if( msgTypeValue == "c" )
            onMessage( (SecurityDefinitionRequest&)message, sessionID );
        else if( msgTypeValue == "d" )
            onMessage( (SecurityDefinition&)message, sessionID );
        else if( msgTypeValue == "e" )
            onMessage( (SecurityStatusRequest&)message, sessionID );
        else if( msgTypeValue == "f" )
            onMessage( (SecurityStatus&)message, sessionID );
        else if( msgTypeValue == "g" )
            onMessage( (TradingSessionStatusRequest&)message, sessionID );
        else if( msgTypeValue == "h" )
            onMessage( (TradingSessionStatus&)message, sessionID );
        else if( msgTypeValue == "i" )
            onMessage( (MassQuote&)message, sessionID );
        else if( msgTypeValue == "j" )
            onMessage( (BusinessMessageReject&)message, sessionID );
        else if( msgTypeValue == "k" )
            onMessage( (BidRequest&)message, sessionID );
        else if( msgTypeValue == "l" )
            onMessage( (BidResponse&)message, sessionID );
        else if( msgTypeValue == "m" )
            onMessage( (ListStrikePrice&)message, sessionID );
        else onMessage( message, sessionID );
    }
};

}

6、TCP Socket封装

SocketConnection类封装了TCP Socket客户端连接的相关操作,IO操作使用Select,SocketConnection类定义如下:

/// Encapsulates a socket file descriptor (single-threaded).
class SocketConnection : Responder
{
public:
  typedef std::set<SessionID> Sessions;

  SocketConnection( socket_handle s, Sessions sessions, SocketMonitor* pMonitor );
  SocketConnection( SocketInitiator&, const SessionID&, socket_handle, SocketMonitor* );
  virtual ~SocketConnection();

  socket_handle getSocket() const { return m_socket; }
  Session* getSession() const { return m_pSession; }

  bool read( SocketConnector& s );
  bool read( SocketAcceptor&, SocketServer& );
  bool processQueue();

  void signal()
  {
    Locker l( m_mutex );
    if( m_sendQueue.size() == 1 )
      m_pMonitor->signal( m_socket );
  }

  void unsignal()
  {
    Locker l( m_mutex );
    if( m_sendQueue.size() == 0 )
      m_pMonitor->unsignal( m_socket );
  }

  void onTimeout();
private:
  typedef std::deque<std::string, ALLOCATOR<std::string> > Queue;

  bool isValidSession();
  void readFromSocket() EXCEPT ( SocketRecvFailed );
  bool readMessage( std::string& msg );
  void readMessages( SocketMonitor& s );
  bool send( const std::string& );
  void disconnect();

  socket_handle m_socket;
  char m_buffer[BUFSIZ];

  Parser m_parser;
  Queue m_sendQueue;
  unsigned m_sendLength;
  Sessions m_sessions;
  Session* m_pSession;
  SocketMonitor* m_pMonitor;
  Mutex m_mutex;
  fd_set m_fds;
};

ThreadedSocketConnection类封装了支持多线程的TCP Socket客户端连接的相关操作,IO操作使用Select;SSLSocketConnection类封装了支持SSL的TCP Socket客户端连接的相关操作,IO操作使用Select;ThreadedSSLSocketConnection类封装了支持SSL以及多线程支持的TCP Socket客户端连接的相关操作,IO操作使用Select。

SocketConnector类封装了Socket连接远程服务端的操作。

SocketMonitor类封装了对Socket连接集合的事件的监听操作。

/// Monitors events on a collection of sockets.
class SocketMonitor
{
public:
    class Strategy;

    SocketMonitor( int timeout = 0 );
    virtual ~SocketMonitor();

    bool addConnect(socket_handle socket );
    bool addRead(socket_handle socket );
    bool addWrite(socket_handle socket );
    bool drop(socket_handle socket );
    void signal(socket_handle socket );
    void unsignal(socket_handle socket );
    void block( Strategy& strategy, bool poll = 0, double timeout = 0.0 );

    size_t numSockets()
    {
        return m_readSockets.size() - 1;
    }
private:
    typedef std::set < socket_handle > Sockets;
    typedef std::queue < socket_handle > Queue;

    void setsockopt();
    bool bind();
    bool listen();
    void buildSet( const Sockets&, fd_set& );
    inline timeval* getTimeval( bool poll, double timeout );
    inline bool sleepIfEmpty( bool poll );

    void processReadSet( Strategy&, fd_set& );
    void processWriteSet( Strategy&, fd_set& );
    void processExceptSet( Strategy&, fd_set& );

    int m_timeout;
    timeval m_timeval;
#ifndef SELECT_DECREMENTS_TIME
    clock_t m_ticks;
#endif

    socket_handle m_signal;
    socket_handle m_interrupt;
    Sockets m_connectSockets;
    Sockets m_readSockets;
    Sockets m_writeSockets;
    Queue m_dropped;
public:
    class Strategy
    {
    public:
        virtual ~Strategy()
        {}

        virtual void onConnect( SocketMonitor&, socket_handle socket ) = 0;
        virtual void onEvent( SocketMonitor&, socket_handle socket ) = 0;
        virtual void onWrite( SocketMonitor&, socket_handle socket ) = 0;
        virtual void onError( SocketMonitor&, socket_handle socket ) = 0;
        virtual void onError( SocketMonitor& ) = 0;
        virtual void onTimeout( SocketMonitor& )
        {}
    }
    ;
};

SocketServer类封装了Socket服务端实现的相关操作,SocketServer类定义如下:

/// Listens for and accepts incoming socket connections on a port.
class SocketServer
{
public:
  class Strategy;

  SocketServer( int timeout = 0 );
  socket_handle add( int port, bool reuse = false, bool noDelay = false,
           int sendBufSize = 0, int rcvBufSize = 0 ) EXCEPT( SocketException& );
  socket_handle accept(socket_handle socket );
  void close();
  bool block( Strategy& strategy, bool poll = 0, double timeout = 0.0 );

  size_t numConnections() { return m_monitor.numSockets() - 1; }
  SocketMonitor& getMonitor() { return m_monitor; }

  int socketToPort(socket_handle socket );
  socket_handle portToSocket( int port );
private:
  typedef std::map<socket_handle, SocketInfo> SocketToInfo;
  typedef std::map<int, SocketInfo> PortToInfo;

  SocketToInfo m_socketToInfo;  
  PortToInfo m_portToInfo;
  SocketMonitor m_monitor;
public:
  class Strategy
  {
  public:
    virtual ~Strategy() {}
    virtual void onConnect( SocketServer&, socket_handle acceptSocket, 
                            socket_handle socket ) = 0;
    virtual void onWrite( SocketServer&, socket_handle socket ) = 0;
    virtual bool onData( SocketServer&, socket_handle socket ) = 0;
    virtual void onDisconnect( SocketServer&, socket_handle socket ) = 0;
    virtual void onError( SocketServer& ) = 0;
    virtual void onTimeout( SocketServer& ) {};
  };
};

7、FIX Session配置解析

SessionSettings类实现了FIX Session配置文件解析,SessionSettings.h如下:

class SessionSettings
{
public:
  SessionSettings() { m_resolveEnvVars = false; }
  SessionSettings( std::istream& stream, bool resolveEnvVars = false ) 
    EXCEPT ( ConfigError );
  SessionSettings( const std::string& file, bool resolveEnvVars = false ) 
    EXCEPT ( ConfigError );

  /// Check if session setings are present
  const bool has( const SessionID& ) const;

  /// Get a dictionary for a session.
  const Dictionary& get( const SessionID& ) const EXCEPT ( ConfigError );

  /// Set a dictionary for a session
  void set( const SessionID&, Dictionary ) EXCEPT ( ConfigError );

  /// Get global default settings
  const Dictionary& get() const { return m_defaults; }

  /// Set global default settings
  void set( const Dictionary& defaults ) EXCEPT ( ConfigError );

  /// Number of session settings
  size_t size() const { return m_settings.size(); }

  typedef std::map < SessionID, Dictionary > Dictionaries;
  std::set < SessionID > getSessions() const;
private:
  void validate( const Dictionary& ) const EXCEPT ( ConfigError );
  Dictionaries m_settings;
  Dictionary m_defaults;
  bool m_resolveEnvVars;  // while reading, replace $var, $(var) and ${var} by environment variable var

  friend std::istream& operator>>( std::istream&, SessionSettings& ) 
    EXCEPT ( ConfigError );
  friend std::ostream& operator<<( std::ostream&, const SessionSettings& );
};

8、FIX Session封装

FIX::Session提供了FIX Session的相关操作,常用的sendToTarget方法声明如下:

static bool FIX::Session::sendToTarget( Message& message,
                                        const std::string& qualifier = "" )
EXCEPT ( SessionNotFound );

static bool FIX::Session::sendToTarget( Message& message,
                                        const SessionID& sessionID )
EXCEPT ( SessionNotFound );

static bool FIX::Session::sendToTarget( Message&,
                          const SenderCompID& senderCompID,
                          const TargetCompID& targetCompID,
                          const std::string& qualifier = "" )
EXCEPT ( SessionNotFound );

static bool FIX::Session::sendToTarget( Message& message,
                          const std::string& senderCompID,
                          const std::string& targetCompID,
                          const std::string& qualifier = "" )
EXCEPT ( SessionNotFound );

9、SocketInitiator

QuickFIX中,Initiator客户端基于SocketConnection客户端连接实现,SocketInitiator类定义如下:

/// Socket implementation of Initiator.
class SocketInitiator : public Initiator, SocketConnector::Strategy
{
public:
  SocketInitiator( Application&, MessageStoreFactory&,
                   const SessionSettings& ) EXCEPT ( ConfigError );

  SocketInitiator( Application&, MessageStoreFactory&,
                   const SessionSettings&, LogFactory& ) EXCEPT ( ConfigError );

  virtual ~SocketInitiator();
private:
  typedef std::map < socket_handle, SocketConnection* > SocketConnections;
  typedef std::map < SessionID, int > SessionToHostNum;

  void onConfigure( const SessionSettings& ) EXCEPT ( ConfigError );
  void onInitialize( const SessionSettings& ) EXCEPT ( RuntimeError );

  void onStart();
  bool onPoll( double timeout );
  void onStop();

  void doConnect( const SessionID&, const Dictionary& d );
  void onConnect( SocketConnector&, socket_handle);
  void onWrite( SocketConnector&, socket_handle);
  bool onData( SocketConnector&, socket_handle);
  void onDisconnect( SocketConnector&, socket_handle);
  void onError( SocketConnector& );
  void onTimeout( SocketConnector& );

  void getHost( const SessionID&, const Dictionary&, std::string&, 
                short&, std::string&, short& );

  SessionSettings m_settings;
  SessionToHostNum m_sessionToHostNum;
  SocketConnector m_connector;
  SocketConnections m_pendingConnections;
  SocketConnections m_connections;
  time_t m_lastConnect;
  int m_reconnectInterval;
  bool m_noDelay;
  int m_sendBufSize;
  int m_rcvBufSize;
};

SSLSocketInitiator是支持SSL的Initiator客户端实现。

ThreadedSocketInitiator是支持多线程的Initiator客户端实现。

ThreadedSSLSocketInitiator是支持SSL和多线程的Initiator客户端实现。

10、SocketAcceptor

QuickFIX中,Acceptor服务端基于SocketServer实现。SocketAcceptor类定义如下:

/// Socket implementation of Acceptor.
class SocketAcceptor : public Acceptor, SocketServer::Strategy
{
  friend class SocketConnection;
public:
  SocketAcceptor( Application&, MessageStoreFactory&,
                  const SessionSettings& ) EXCEPT ( ConfigError );
  SocketAcceptor( Application&, MessageStoreFactory&,
                  const SessionSettings&, LogFactory& ) EXCEPT ( ConfigError );

  virtual ~SocketAcceptor();
private:
  bool readSettings( const SessionSettings& );
  typedef std::set < SessionID > Sessions;
  typedef std::map < int, Sessions > PortToSessions;
  typedef std::map < socket_handle, SocketConnection* > SocketConnections;

  void onConfigure( const SessionSettings& ) EXCEPT ( ConfigError );
  void onInitialize( const SessionSettings& ) EXCEPT ( RuntimeError );

  void onStart();
  bool onPoll( double timeout );
  void onStop();

  void onConnect( SocketServer&, socket_handle, socket_handle );
  void onWrite( SocketServer&, socket_handle );
  bool onData( SocketServer&, socket_handle );
  void onDisconnect( SocketServer&, socket_handle );
  void onError( SocketServer& );
  void onTimeout( SocketServer& );

  SocketServer* m_pServer;
  PortToSessions m_portToSessions;
  SocketConnections m_connections;
};

SSLSocketAcceptor是支持SSL的Acceptor应用实现。

ThreadedSocketAcceptor是支持多线程的Acceptor应用实现。

ThreadedSSLSocketAcceptor是支持SSL和多线程的Acceptor应用实现。

11、Fix Application

FIX::Application接口定义如下:

class Application
{
public:
  virtual ~Application() {};

  /// Notification of a session begin created
  virtual void onCreate( const SessionID& ) = 0;

  /// Notification of a session successfully logging on
  virtual void onLogon( const SessionID& ) = 0;

  /// Notification of a session logging off or disconnecting
  virtual void onLogout( const SessionID& ) = 0;

  /// Notification of admin message being sent to target
  virtual void toAdmin( Message&, const SessionID& ) = 0;

  /// Notification of app message being sent to target
  virtual void toApp( Message&, const SessionID& )
  EXCEPT ( DoNotSend ) = 0;

  /// Notification of admin message being received from target
  virtual void fromAdmin( const Message&, const SessionID& )
  EXCEPT ( FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon ) = 0;

  /// Notification of app message being received from target
  virtual void fromApp( const Message&, const SessionID& )
  EXCEPT ( FieldNotFound, IncorrectDataFormat, IncorrectTagValue, 
            UnsupportedMessageType ) = 0;
};

对于FIX应用开发,除了实现FIX::Application接口,还需要重新实现FIX::MessageCracker从具体的FIX协议版本实现继承而来的onMessage方法,如FIX42::MessageCracker部分接口如下:

class MessageCracker
{
public:
    virtual ~MessageCracker() {}
    virtual void onMessage( const Message&, const FIX::SessionID& )
    {
        throw FIX::UnsupportedMessageType();
    }

    virtual void onMessage( Message&, const FIX::SessionID& )
    {
        throw FIX::UnsupportedMessageType();
    }

    virtual void onMessage( const Heartbeat&, const FIX::SessionID& ){}
    virtual void onMessage( const TestRequest&, const FIX::SessionID& ){}
    virtual void onMessage( const ResendRequest&, const FIX::SessionID& ){}
    virtual void onMessage( const Reject&, const FIX::SessionID& ){}
    virtual void onMessage( const SequenceReset&, const FIX::SessionID& ){}
    virtual void onMessage( const Logout&, const FIX::SessionID& ){}
    virtual void onMessage( const ExecutionReport&, const FIX::SessionID& )
    {
        throw FIX::UnsupportedMessageType();
    }

    virtual void onMessage( const OrderCancelReject&, const FIX::SessionID& )
    {
        throw FIX::UnsupportedMessageType();
    }

    virtual void onMessage( const Logon&, const FIX::SessionID& ){}
    virtual void onMessage( const NewOrderSingle&, const FIX::SessionID& )
    {
        throw FIX::UnsupportedMessageType();
    }

    virtual void onMessage( const OrderCancelRequest&, const FIX::SessionID& )
    {
        throw FIX::UnsupportedMessageType();
    }

    virtual void onMessage( const OrderStatusRequest&, const FIX::SessionID& )
    {
        throw FIX::UnsupportedMessageType();
    }

    virtual void onMessage( const BusinessMessageReject&, const FIX::SessionID& ){}
    virtual void onMessage( Heartbeat&, const FIX::SessionID& ) {}
    virtual void onMessage( TestRequest&, const FIX::SessionID& ) {}
    virtual void onMessage( ResendRequest&, const FIX::SessionID& ) {}
    virtual void onMessage( Reject&, const FIX::SessionID& ) {}
    virtual void onMessage( SequenceReset&, const FIX::SessionID& ) {}
    virtual void onMessage( Logout&, const FIX::SessionID& ) {}
    virtual void onMessage( ExecutionReport&, const FIX::SessionID& ) {}
    virtual void onMessage( OrderCancelReject&, const FIX::SessionID& ) {}
    virtual void onMessage( Logon&, const FIX::SessionID& ) {}
    virtual void onMessage( NewOrderSingle&, const FIX::SessionID& ) {}
    virtual void onMessage( OrderCancelRequest&, const FIX::SessionID& ) {}
    virtual void onMessage( OrderStatusRequest&, const FIX::SessionID& ) {}
};

三、示例程序

1、示例程序简介

QuickFIX示例程序位于quickfix/examples目录。

ordermatch:FIX交易网关服务,撮合限价单。

tradeclient :控制台交易客户端。

tradeclientgui:Java GUI交易客户端。

executor:对接收的限价单申报返回成交回报。

2、ordermatch

ordermatch示例包含IDGenerator、Order、OrderMatcher、Market、ordermatch、Application。

IDGenerator:ID生成器

Order:订单类

OrderMatcher:撮合引擎

Market:订单簿

Application:FIX Application

ordermatch:程序入口

IDGenerator.h文件:

#ifndef IDGENERATOR_H
#define IDGENERATOR_H

#include <string>
#include <sstream>

class IDGenerator
{
public:
  IDGenerator() : m_orderID(0), m_executionID(0) 
  {

  }

  std::string genOrderID()
  {
    m_stream.clear();
    m_stream.str("");
    m_stream << ++m_orderID;
    return m_stream.str();
  }

  std::string genExecutionID()
  {
    m_stream.clear();
    m_stream.str("");
    m_stream << ++m_executionID;
    return m_stream.str();
  }
private:
  long m_orderID;
  long m_executionID;
  std::stringstream m_stream;
};

#endif

Order.h文件:

#ifndef ORDER_H
#define ORDER_H

#include <string>
#include <iomanip>
#include <ostream>

class Order
{
  friend std::ostream& operator<<( std::ostream&, const Order& );
public:
  enum Side { buy, sell };
  enum Type { market, limit };
  Order( const std::string& clientId, const std::string& symbol,
         const std::string& owner, const std::string& target,
         Side side, Type type, double price, long quantity )
: m_clientId( clientId ), m_symbol( symbol ), m_owner( owner ),m_target( target ), 
m_side( side ), m_type( type ), m_price( price ),m_quantity( quantity )
  {
    m_openQuantity = m_quantity;
    m_executedQuantity = 0;
    m_avgExecutedPrice = 0;
    m_lastExecutedPrice = 0;
    m_lastExecutedQuantity = 0;
  }

  const std::string& getClientID() const 
  { 
    return m_clientId; 
  }

  const std::string& getSymbol() const 
  { 
    return m_symbol; 
  }

  const std::string& getOwner() const 
  { 
    return m_owner; 
  }

  const std::string& getTarget() const 
  { 
    return m_target; 
  }

  Side getSide() const 
  { 
    return m_side; 
  }

  Type getType() const 
  {
    return m_type; 
  }

  double getPrice() const 
  { 
    return m_price; 
  }

  long getQuantity() const 
  { 
    return m_quantity; 
  }

  long getOpenQuantity() const 
  { 
    return m_openQuantity; 
  }

  long getExecutedQuantity() const 
  { 
    return m_executedQuantity; 
  }

  double getAvgExecutedPrice() const 
  { 
    return m_avgExecutedPrice; 
  }

  double getLastExecutedPrice() const 
  { 
    return m_lastExecutedPrice; 
  }

  long getLastExecutedQuantity() const 
  { 
    return m_lastExecutedQuantity; 
  }

  bool isFilled() const 
  { 
    return m_quantity == m_executedQuantity; 
  }

  bool isClosed() const 
  { 
    return m_openQuantity == 0; 
  }

  void execute( double price, long quantity )
  {
    m_avgExecutedPrice =
      ( ( quantity * price ) + ( m_avgExecutedPrice * m_executedQuantity ) )
      / ( quantity + m_executedQuantity );

    m_openQuantity -= quantity;
    m_executedQuantity += quantity;
    m_lastExecutedPrice = price;
    m_lastExecutedQuantity = quantity;
  }

  void cancel()
  {
    m_openQuantity = 0;
  }
private:
  std::string m_clientId;// 客户端ID
  std::string m_symbol;// Ticker
  std::string m_owner;// 本地端
  std::string m_target;// 目标端
  Side m_side;// 买卖方向
  Type m_type;// 订单类型
  double m_price;// 委托价格
  long m_quantity;// 委托数量
  long m_openQuantity;
  long m_executedQuantity;
  double m_avgExecutedPrice;
  double m_lastExecutedPrice;
  long m_lastExecutedQuantity;
};

inline std::ostream& operator<<( std::ostream& ostream, const Order& order )
{
  return ostream
         << "ID: " <<  order.getClientID()
         << " Ticker: " << order.getSymbol()
         << " OWNER: " << order.getOwner()
         << " PRICE: " << order.getPrice()
         << " OPENQUANTITY: " << order.getOpenQuantity();
}

#endif

Market.h文件:

#ifndef MARKET_H
#define MARKET_H

#include "Order.h"
#include <map>
#include <queue>
#include <string>
#include <functional>

class Market
{
public:
  // 插入新订单到订单队列
  bool insert( const Order& order );
  // 从订单队列中删除订单
  void erase( const Order& order );
  // 查找订单
  Order& find( Order::Side side, std::string id );
  // 撮合成交
  bool match( std::queue < Order > & );

  void display() const;
protected:
  void match( Order& bid, Order& ask );
private:
  // 买单,降序排列
  typedef std::multimap < double, Order, std::greater < double > > BidOrders;
  // 卖单,升序排序
  typedef std::multimap < double, Order, std::less < double > > AskOrders;
  BidOrders m_bidOrders;// 订单簿:买单队列
  AskOrders m_askOrders;// 订单簿:卖单队列
};

#endif

Market.cpp文件:

#include "Market.h"
#include <iostream>

bool Market::insert( const Order& order )
{
  // 买单
  if ( order.getSide() == Order::buy )
    m_bidOrders.insert( BidOrders::value_type( order.getPrice(), order ) );
  else
    m_askOrders.insert( AskOrders::value_type( order.getPrice(), order ) );
  return true;
}

void Market::erase( const Order& order )
{
  std::string id = order.getClientID();
  // 买单
  if ( order.getSide() == Order::buy )
  {
    BidOrders::iterator i;
    for ( i = m_bidOrders.begin(); i != m_bidOrders.end(); ++i )
      if ( i->second.getClientID() == id )
      {
        m_bidOrders.erase( i );
        return ;
      }
  }
  // 卖单
  else if ( order.getSide() == Order::sell )
  {
    AskOrders::iterator i;
    for ( i = m_askOrders.begin(); i != m_askOrders.end(); ++i )
      if ( i->second.getClientID() == id )
      {
        m_askOrders.erase( i );
        return ;
      }
  }
}

bool Market::match( std::queue < Order > & orders )
{
  while ( true )
  {
    if ( !m_bidOrders.size() || !m_askOrders.size() )
      return orders.size() != 0;

    BidOrders::iterator iBid = m_bidOrders.begin();
    AskOrders::iterator iAsk = m_askOrders.begin();
    // 买单队列的第一档的价格大于等于卖单队列第一档价格
    if ( iBid->second.getPrice() >= iAsk->second.getPrice() )
    {
      Order & bid = iBid->second;
      Order& ask = iAsk->second;

      match( bid, ask );
      orders.push( bid );
      orders.push( ask );

      if ( bid.isClosed() ) 
        m_bidOrders.erase( iBid );
      if ( ask.isClosed() )
        m_askOrders.erase( iAsk );
    }
    else
      return orders.size() != 0;
  }
}

Order& Market::find( Order::Side side, std::string id )
{
  // 买单
  if ( side == Order::buy )
  {
    BidOrders::iterator i;
    for ( i = m_bidOrders.begin(); i != m_bidOrders.end(); ++i )
      if ( i->second.getClientID() == id ) return i->second;
  }
  // 卖单
  else if ( side == Order::sell )
  {
    AskOrders::iterator i;
    for ( i = m_askOrders.begin(); i != m_askOrders.end(); ++i )
      if ( i->second.getClientID() == id ) return i->second;
  }
  throw std::exception();
}

void Market::match( Order& bid, Order& ask )
{
  double price = ask.getPrice();
  long quantity = 0;

  if ( bid.getOpenQuantity() > ask.getOpenQuantity() )
    quantity = ask.getOpenQuantity();
  else
    quantity = bid.getOpenQuantity();

  bid.execute( price, quantity );
  ask.execute( price, quantity );
}

void Market::display() const
{
  BidOrders::const_iterator iBid;
  AskOrders::const_iterator iAsk;

  std::cout << "BIDS:" << std::endl;
  for ( iBid = m_bidOrders.begin(); iBid != m_bidOrders.end(); ++iBid )
    std::cout << iBid->second << std::endl;

  std::cout << std::endl << std::endl;

  std::cout << "ASKS:" << std::endl;
  for ( iAsk = m_askOrders.begin(); iAsk != m_askOrders.end(); ++iAsk )
    std::cout << iAsk->second << std::endl;
}

OrderMatch.h文件:

#ifndef ORDERMATCHER_H
#define ORDERMATCHER_H

#include "Market.h"
#include <map>
#include <iostream>

class OrderMatcher
{
  typedef std::map < std::string, Market > Markets;
public:
  // 插入订单
  bool insert( const Order& order )
  {
    Markets::iterator i = m_markets.find( order.getSymbol() );
    if ( i == m_markets.end() )
      i = m_markets.insert( std::make_pair( order.getSymbol(), Market() ) ).first;
    return i->second.insert( order );
  }

  // 删除订单
  void erase( const Order& order )
  {
    Markets::iterator i = m_markets.find( order.getSymbol() );
    if ( i == m_markets.end() ) 
      return ;
    i->second.erase( order );
  }

  // 订单查找
  Order& find(const std::string symbol, Order::Side side, std::string id )
  {
    Markets::iterator i = m_markets.find( symbol );
    if ( i == m_markets.end() ) 
      throw std::exception();
    return i->second.find( side, id );
  }

  // 撮合成交
  bool match( const std::string symbol, std::queue < Order > & orders )
  {
    Markets::iterator i = m_markets.find( symbol );
    if ( i == m_markets.end() ) 
      return false;
    return i->second.match( orders );
  }

  bool match( std::queue < Order > & orders )
  {
    Markets::iterator i;
    for ( i = m_markets.begin(); i != m_markets.end(); ++i )
      i->second.match( orders );
    return orders.size() != 0;
  }

  void display( std::string symbol ) const
  {
    Markets::const_iterator i = m_markets.find( symbol );
    if ( i == m_markets.end() )
      return ;
    i->second.display();
  }

  void display() const
  {
    std::cout << "SYMBOLS:" << std::endl;
    std::cout << "--------" << std::endl;
    Markets::const_iterator i;
    for ( i = m_markets.begin(); i != m_markets.end(); ++i )
    {
      i->second.display();
    }
  }

private:
  Markets m_markets;// 全市场订单簿
};


#endif

Application.h文件:

#ifndef APPLICATION_H
#define APPLICATION_H

#include "IDGenerator.h"
#include "OrderMatcher.h"
#include "Order.h"
#include <queue>
#include <iostream>

#include "quickfix/Application.h"
#include "quickfix/MessageCracker.h"
#include "quickfix/Values.h"
#include "quickfix/Utility.h"
#include "quickfix/Mutex.h"

#include "quickfix/fix42/NewOrderSingle.h"
#include "quickfix/fix42/OrderCancelRequest.h"
#include "quickfix/fix42/MarketDataRequest.h"
#include "quickfix/fix43/MarketDataRequest.h"

class Application
      : public FIX::Application,
        public FIX::MessageCracker
{
public:
  const OrderMatcher& orderMatcher() 
  { 
    return m_orderMatcher; 
  }

protected:
  // Application overloads
  void onCreate( const FIX::SessionID& ) {}
  void onLogon( const FIX::SessionID& sessionID );
  void onLogout( const FIX::SessionID& sessionID );
  void toAdmin( FIX::Message&, const FIX::SessionID& ) {}
  void toApp( FIX::Message&, const FIX::SessionID& )
  EXCEPT( FIX::DoNotSend ) {}
  void fromAdmin( const FIX::Message&, const FIX::SessionID& )
  EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, 
          FIX::RejectLogon ) {}
  void fromApp( const FIX::Message& message, const FIX::SessionID& sessionID )
  EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, 
          FIX::UnsupportedMessageType );
protected:
  // MessageCracker overloads
  void onMessage( const FIX42::NewOrderSingle&, const FIX::SessionID& );
  void onMessage( const FIX42::OrderCancelRequest&, const FIX::SessionID& );
  void onMessage( const FIX42::MarketDataRequest&, const FIX::SessionID& );
  void onMessage( const FIX43::MarketDataRequest&, const FIX::SessionID& );
protected:
  // 订单处理
  void processOrder( const Order& );

  // 撤单处理
  void processCancel( const std::string& id, const std::string& symbol, Order::Side );

  // 订单成交回报
  void updateOrder( const Order&, char status );

  // 拒单处理
  void rejectOrder( const Order& order )
  { 
    updateOrder( order, FIX::OrdStatus_REJECTED ); 
  }

  // 委托ACK回报
  void acceptOrder( const Order& order )
  { 
    updateOrder( order, FIX::OrdStatus_NEW );
  }

  // 成交回报
  void fillOrder( const Order& order )
  {
    updateOrder( order,
                 order.isFilled() ? FIX::OrdStatus_FILLED
                 : FIX::OrdStatus_PARTIALLY_FILLED );
  }

  // 撤单回报
  void cancelOrder( const Order& order )
  { 
    updateOrder( order, FIX::OrdStatus_CANCELED ); 
  }

  // 拒单回报
  void rejectOrder( const FIX::SenderCompID&, const FIX::TargetCompID&,
                    const FIX::ClOrdID& clOrdID, const FIX::Symbol& symbol,
                    const FIX::Side& side, const std::string& message );

  // 将FIX消息的买卖方向转换为订单的买卖方向
  Order::Side convert( const FIX::Side& );

  // 将订单的买卖方向转换为FIX消息的买卖方向
  FIX::Side convert( Order::Side );

  // 将FIX消息的订单类型转换为订单的类型
  Order::Type convert( const FIX::OrdType& );

  // 将订单类型转换为FIX的订单类型
  FIX::OrdType convert( Order::Type );
private:
  OrderMatcher m_orderMatcher;// 订单撮合引擎
  IDGenerator m_generator;// ID生成器
};

#endif

Application.cpp文件:

#include "config.h"
#include "Application.h"
#include "quickfix/Session.h"

#include "quickfix/fix42/ExecutionReport.h"

void Application::onLogon( const FIX::SessionID& sessionID ) {}
void Application::onLogout( const FIX::SessionID& sessionID ) {}
void Application::fromApp( const FIX::Message& message,
                           const FIX::SessionID& sessionID )
EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, 
        FIX::UnsupportedMessageType )
{
  crack( message, sessionID );
}

void Application::onMessage( const FIX42::NewOrderSingle& message, 
                             const FIX::SessionID& )
{
  FIX::SenderCompID senderCompID;
  FIX::TargetCompID targetCompID;
  FIX::ClOrdID clOrdID;
  FIX::Symbol symbol;
  FIX::Side side;
  FIX::OrdType ordType;
  FIX::Price price;
  FIX::OrderQty orderQty;
  FIX::TimeInForce timeInForce( FIX::TimeInForce_DAY );

  message.getHeader().get( senderCompID );
  message.getHeader().get( targetCompID );
  message.get( clOrdID );
  message.get( symbol );
  message.get( side );
  message.get( ordType );
  // 限价单
  if ( ordType == FIX::OrdType_LIMIT )
    message.get( price );
  message.get( orderQty );
  message.getFieldIfSet( timeInForce );

  try
  {
    if ( timeInForce != FIX::TimeInForce_DAY )
      throw std::logic_error( "Unsupported TIF, use Day" );

    Order order( clOrdID, symbol, senderCompID, targetCompID,
                 convert( side ), convert( ordType ),
                 price, (long)orderQty );
    // 订单处理
    processOrder( order );
  }
  catch ( std::exception & e )
  {
    // 拒单处理
    rejectOrder( senderCompID, targetCompID, clOrdID, symbol, side, e.what() );
  }
}

void Application::onMessage( const FIX42::OrderCancelRequest& message, 
                             const FIX::SessionID& )
{
  FIX::OrigClOrdID origClOrdID;
  FIX::Symbol symbol;
  FIX::Side side;

  message.get( origClOrdID );
  message.get( symbol );
  message.get( side );

  try
  {
    // 撤单处理
    processCancel( origClOrdID, symbol, convert( side ) );
  }
  catch ( std::exception& ) {}
}



void Application::onMessage( const FIX42::MarketDataRequest& message, 
                             const FIX::SessionID& )
{
  FIX::MDReqID mdReqID;
  FIX::SubscriptionRequestType subscriptionRequestType;
  FIX::MarketDepth marketDepth;
  FIX::NoRelatedSym noRelatedSym;
  FIX42::MarketDataRequest::NoRelatedSym noRelatedSymGroup;

  message.get( mdReqID );
  message.get( subscriptionRequestType );
  if ( subscriptionRequestType != FIX::SubscriptionRequestType_SNAPSHOT )
    EXCEPT( FIX::IncorrectTagValue( subscriptionRequestType.getField() ) );
  message.get( marketDepth );
  message.get( noRelatedSym );

  for ( int i = 1; i <= noRelatedSym; ++i )
  {
    FIX::Symbol symbol;
    message.getGroup( i, noRelatedSymGroup );
    noRelatedSymGroup.get( symbol );
  }
}

void Application::onMessage( const FIX43::MarketDataRequest& message, 
                             const FIX::SessionID& )
{
    std::cout << message.toXML() << std::endl;
}

void Application::updateOrder( const Order& order, char status )
{
  FIX::TargetCompID targetCompID( order.getOwner() );
  FIX::SenderCompID senderCompID( order.getTarget() );

  FIX42::ExecutionReport fixOrder
  ( FIX::OrderID ( order.getClientID() ),
    FIX::ExecID ( m_generator.genExecutionID() ),
    FIX::ExecTransType ( FIX::ExecTransType_NEW ),
    FIX::ExecType ( status ),
    FIX::OrdStatus ( status ),
    FIX::Symbol ( order.getSymbol() ),
    FIX::Side ( convert( order.getSide() ) ),
    FIX::LeavesQty ( order.getOpenQuantity() ),
    FIX::CumQty ( order.getExecutedQuantity() ),
    FIX::AvgPx ( order.getAvgExecutedPrice() ) 
  );

  fixOrder.set( FIX::ClOrdID( order.getClientID() ) );
  fixOrder.set( FIX::OrderQty( order.getQuantity() ) );

  if ( status == FIX::OrdStatus_FILLED ||
       status == FIX::OrdStatus_PARTIALLY_FILLED )
  {
    fixOrder.set( FIX::LastShares( order.getLastExecutedQuantity() ) );
    fixOrder.set( FIX::LastPx( order.getLastExecutedPrice() ) );
  }

  try
  {
    FIX::Session::sendToTarget( fixOrder, senderCompID, targetCompID );
  }
  catch ( FIX::SessionNotFound& ) {}
}

void Application::rejectOrder
( const FIX::SenderCompID& sender, const FIX::TargetCompID& target,
  const FIX::ClOrdID& clOrdID, const FIX::Symbol& symbol,
  const FIX::Side& side, const std::string& message )
{
  FIX::TargetCompID targetCompID( sender.getValue() );
  FIX::SenderCompID senderCompID( target.getValue() );

  FIX42::ExecutionReport fixOrder
  ( FIX::OrderID ( clOrdID.getValue() ),
    FIX::ExecID ( m_generator.genExecutionID() ),
    FIX::ExecTransType ( FIX::ExecTransType_NEW ),
    FIX::ExecType ( FIX::ExecType_REJECTED ),
    FIX::OrdStatus ( FIX::ExecType_REJECTED ),
    symbol, side, FIX::LeavesQty( 0 ), FIX::CumQty( 0 ), FIX::AvgPx( 0 ) 
  );

  fixOrder.set( clOrdID );
  fixOrder.set( FIX::Text( message ) );

  try
  {
    FIX::Session::sendToTarget( fixOrder, senderCompID, targetCompID );
  }
  catch ( FIX::SessionNotFound& ) {}
}

void Application::processOrder( const Order& order )
{
  if ( m_orderMatcher.insert( order ) )
  {
    // 订单委托确认回报
    acceptOrder( order );
    std::queue < Order > orders;
    // 撮合成交
    m_orderMatcher.match( order.getSymbol(), orders );
    // 订单成交回报
    while ( orders.size() )
    {
      fillOrder( orders.front() );
      orders.pop();
    }
  }
  else
    rejectOrder( order );// 拒单回报
}

void Application::processCancel( const std::string& id,
                                 const std::string& symbol, Order::Side side )
{
  Order & order = m_orderMatcher.find( symbol, side, id );
  order.cancel();
  cancelOrder( order );
  m_orderMatcher.erase( order );
}

Order::Side Application::convert( const FIX::Side& side )
{
  switch ( side )
  {
    case FIX::Side_BUY: 
      return Order::buy;
    case FIX::Side_SELL: 
      return Order::sell;
    default: 
      throw std::logic_error( "Unsupported Side, use buy or sell" );
  }
}

Order::Type Application::convert( const FIX::OrdType& ordType )
{
  switch ( ordType )
  {
    case FIX::OrdType_LIMIT: 
      return Order::limit;
    default: 
      throw std::logic_error( "Unsupported Order Type, use limit" );
  }
}

FIX::Side Application::convert( Order::Side side )
{
  switch ( side )
  {
    case Order::buy: 
      return FIX::Side( FIX::Side_BUY );
    case Order::sell: 
      return FIX::Side( FIX::Side_SELL );
    default: 
      throw std::logic_error( "Unsupported Side, use buy or sell" );
  }
}


FIX::OrdType Application::convert( Order::Type type )
{
  switch ( type )
  {
    case Order::limit:
      return FIX::OrdType( FIX::OrdType_LIMIT );
    default: 
      throw std::logic_error( "Unsupported Order Type, use limit" );
  }
}

ordermatch.cpp文件:

#include "config.h"
#include "quickfix/FileStore.h"
#include "quickfix/SocketAcceptor.h"
#include "quickfix/SessionSettings.h"
#include "Application.h"
#include <string>
#include <iostream>
#include <fstream>

int main( int argc, char** argv )
{
  if ( argc != 2 )
  {
    std::cout << "usage: " << argv[ 0 ] << " FILE." << std::endl;
    return 0;
  }

  std::string file = argv[ 1 ];

  try
  {
    FIX::SessionSettings settings( file );

    Application application;
    FIX::FileStoreFactory storeFactory( settings );
    FIX::ScreenLogFactory logFactory( settings );
    FIX::SocketAcceptor acceptor( application, storeFactory, settings, logFactory );

    acceptor.start();
    while ( true )
    {
      application.orderMatcher().display();
      std::cout << std::endl;
      sleep(5);
    }

    acceptor.stop();
    return 0;
  }
  catch ( std::exception & e )
  {
    std::cout << e.what() << std::endl;
    return 1;
  }
}

CMakeLists.txt文件:

cmake_minimum_required(VERSION 3.10)

project(OrderMatch)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")


include_directories(/usr/local/include/quickfix)
link_directories(/usr/local/lib)
link_libraries(quickfix)

add_executable(ordermatch Application.cpp Market.cpp ordermatch.cpp)

Acceptor Session配置文件:

[DEFAULT]
ConnectionType=acceptor
ReconnectInterval=60
SenderCompID=GATEWAY
FileStorePath=./log
SocketAcceptPort=8088

[SESSION]
BeginString=FIX.4.2
TargetCompID=CLIENT
UseLocalTime=Y
StartTime=00:00:00
EndTime=23:30:00
HeartBtInt=30
SocketReuseAddress=Y
UseDataDictionary=Y
DataDictionary=./FIX42.xml
ResetOnLogon=Y

3、tradeclient

tradeclient是Initiator应用。

Application.h文件:

#ifndef TRADECLIENT_APPLICATION_H
#define TRADECLIENT_APPLICATION_H

#include "quickfix/Application.h"
#include "quickfix/MessageCracker.h"
#include "quickfix/Values.h"
#include "quickfix/Mutex.h"

#include "quickfix/fix42/NewOrderSingle.h"
#include "quickfix/fix42/ExecutionReport.h"
#include "quickfix/fix42/OrderCancelRequest.h"
#include "quickfix/fix42/OrderCancelReject.h"
#include "quickfix/fix42/OrderCancelReplaceRequest.h"

#include <queue>

class Application :
      public FIX::Application,
      public FIX::MessageCracker
{
public:
  void run();
private:
  void onCreate( const FIX::SessionID& ) {}
  void onLogon( const FIX::SessionID& sessionID );
  void onLogout( const FIX::SessionID& sessionID );
  void toAdmin( FIX::Message&, const FIX::SessionID& ) {}
  void toApp( FIX::Message&, const FIX::SessionID& )
  EXCEPT( FIX::DoNotSend );

  void fromAdmin( const FIX::Message&, const FIX::SessionID& )
  EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, 
          FIX::RejectLogon ) {}

  void fromApp( const FIX::Message& message, const FIX::SessionID& sessionID )
  EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, 
          FIX::UnsupportedMessageType );

  void onMessage( const FIX42::ExecutionReport&, const FIX::SessionID& );
  void onMessage( const FIX42::OrderCancelReject&, const FIX::SessionID& );

  void queryEnterOrder();
  void queryCancelOrder();
  void queryReplaceOrder();
  void queryMarketDataRequest();

  FIX42::NewOrderSingle queryNewOrderSingle42();
  FIX42::OrderCancelRequest queryOrderCancelRequest42();
  FIX42::OrderCancelReplaceRequest queryCancelReplaceRequest42();

  void queryHeader( FIX::Header& header );
  char queryAction();
  int queryVersion();
  bool queryConfirm( const std::string& query );

  FIX::SenderCompID querySenderCompID();
  FIX::TargetCompID queryTargetCompID();
  FIX::TargetSubID queryTargetSubID();
  FIX::ClOrdID queryClOrdID();
  FIX::OrigClOrdID queryOrigClOrdID();
  FIX::Symbol querySymbol();
  FIX::Side querySide();
  FIX::OrderQty queryOrderQty();
  FIX::OrdType queryOrdType();
  FIX::Price queryPrice();
  FIX::StopPx queryStopPx();
  FIX::TimeInForce queryTimeInForce();
};

#endif

Application.cpp文件:

#include "config.h"
#include "Application.h"
#include "quickfix/Session.h"
#include <iostream>

void Application::onLogon( const FIX::SessionID& sessionID )
{
  std::cout << std::endl << "Logon - " << sessionID << std::endl;
}

void Application::onLogout( const FIX::SessionID& sessionID )
{
  std::cout << std::endl << "Logout - " << sessionID << std::endl;
}

void Application::fromApp( const FIX::Message& message, const FIX::SessionID& sessionID )
EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, 
        FIX::UnsupportedMessageType )
{
  crack( message, sessionID );
  std::cout << std::endl << "IN: " << message << std::endl;
}

void Application::toApp( FIX::Message& message, const FIX::SessionID& sessionID )
EXCEPT( FIX::DoNotSend )
{
  try
  {
    FIX::PossDupFlag possDupFlag;
    message.getHeader().getField( possDupFlag );
    if ( possDupFlag ) throw FIX::DoNotSend();
  }
  catch ( FIX::FieldNotFound& ) {}

  std::cout << std::endl
  << "OUT: " << message << std::endl;
}

void Application::onMessage
( const FIX42::ExecutionReport&, const FIX::SessionID& ) {}

void Application::onMessage
( const FIX42::OrderCancelReject&, const FIX::SessionID& ) {}

void Application::run()
{
  while ( true )
  {
    try
    {
      char action = queryAction();

      if ( action == '1' )
        queryEnterOrder();
      else if ( action == '2' )
        queryCancelOrder();
      else if ( action == '3' )
        queryReplaceOrder();
      else if ( action == '4' )
        queryMarketDataRequest();
      else if ( action == '5' )
        break;
    }
    catch ( std::exception & e )
    {
      std::cout << "Message Not Sent: " << e.what();
    }
  }
}

void Application::queryEnterOrder()
{
  int version = queryVersion();
  std::cout << "\nNewOrderSingle\n";
  FIX::Message order;

  switch ( version ) {
  case 42:
    order = queryNewOrderSingle42();
    break;
  default:
    std::cerr << "No test for version " << version << std::endl;
    break;
  }

  if ( queryConfirm( "Send order" ) )
    FIX::Session::sendToTarget( order );
}

void Application::queryCancelOrder()
{
  int version = queryVersion();
  std::cout << "\nOrderCancelRequest\n";
  FIX::Message cancel;

  switch ( version ) {
  case 42:
    cancel = queryOrderCancelRequest42();
    break;
  default:
    std::cerr << "No test for version " << version << std::endl;
    break;
  }

  if ( queryConfirm( "Send cancel" ) )
    FIX::Session::sendToTarget( cancel );
}



void Application::queryReplaceOrder()
{
  int version = queryVersion();
  std::cout << "\nCancelReplaceRequest\n";
  FIX::Message replace;

  switch ( version ) {
  case 42:
    replace = queryCancelReplaceRequest42();
    break;
  default:
    std::cerr << "No test for version " << version << std::endl;
    break;
  }

  if ( queryConfirm( "Send replace" ) )
    FIX::Session::sendToTarget( replace );
}

void Application::queryMarketDataRequest()
{
  int version = queryVersion();
  std::cout << "\nMarketDataRequest\n";
  FIX::Message md;

  switch (version) {
  default:
    std::cerr << "No test for version " << version << std::endl;
    break;
  }

  FIX::Session::sendToTarget( md );
}

FIX42::NewOrderSingle Application::queryNewOrderSingle42()
{
  FIX::OrdType ordType;
  FIX42::NewOrderSingle newOrderSingle(
    queryClOrdID(), FIX::HandlInst( '1' ), querySymbol(), querySide(),
    FIX::TransactTime(), ordType = queryOrdType() );

  newOrderSingle.set( queryOrderQty() );
  newOrderSingle.set( queryTimeInForce() );
  if ( ordType == FIX::OrdType_LIMIT || ordType == FIX::OrdType_STOP_LIMIT )
    newOrderSingle.set( queryPrice() );

  if ( ordType == FIX::OrdType_STOP || ordType == FIX::OrdType_STOP_LIMIT )
    newOrderSingle.set( queryStopPx() );

  queryHeader( newOrderSingle.getHeader() );
  return newOrderSingle;
}

FIX42::OrderCancelRequest Application::queryOrderCancelRequest42()
{
  FIX42::OrderCancelRequest orderCancelRequest( queryOrigClOrdID(),
      queryClOrdID(), querySymbol(), querySide(), FIX::TransactTime() );

  orderCancelRequest.set( queryOrderQty() );
  queryHeader( orderCancelRequest.getHeader() );
  return orderCancelRequest;
}

FIX42::OrderCancelReplaceRequest Application::queryCancelReplaceRequest42()
{
  FIX42::OrderCancelReplaceRequest cancelReplaceRequest(
    queryOrigClOrdID(), queryClOrdID(), FIX::HandlInst( '1' ),
    querySymbol(), querySide(), FIX::TransactTime(), queryOrdType() );

  if ( queryConfirm( "New price" ) )
    cancelReplaceRequest.set( queryPrice() );
  if ( queryConfirm( "New quantity" ) )
    cancelReplaceRequest.set( queryOrderQty() );

  queryHeader( cancelReplaceRequest.getHeader() );
  return cancelReplaceRequest;
}

void Application::queryHeader( FIX::Header& header )
{
  header.setField( querySenderCompID() );
  header.setField( queryTargetCompID() );

  if ( queryConfirm( "Use a TargetSubID" ) )
    header.setField( queryTargetSubID() );
}

char Application::queryAction()
{
  char value;
  std::cout << std::endl
  << "1) Enter Order" << std::endl
  << "2) Cancel Order" << std::endl
  << "3) Replace Order" << std::endl
  << "4) Market data test" << std::endl
  << "5) Quit" << std::endl
  << "Action: ";
  std::cin >> value;
  switch ( value )
  {
    case '1': case '2': case '3': case '4': case '5': break;
    default: throw std::exception();
  }
  return value;
}

int Application::queryVersion()
{
  char value;
  std::cout << std::endl
  << "1) FIX.4.0" << std::endl
  << "2) FIX.4.1" << std::endl
  << "3) FIX.4.2" << std::endl
  << "4) FIX.4.3" << std::endl
  << "5) FIX.4.4" << std::endl
  << "6) FIXT.1.1 (FIX.5.0)" << std::endl
  << "BeginString: ";
  std::cin >> value;
  switch ( value )
  {
    case '1': return 40;
    case '2': return 41;
    case '3': return 42;
    case '4': return 43;
    case '5': return 44;
    case '6': return 50;
    default: throw std::exception();
  }
}

bool Application::queryConfirm( const std::string& query )
{
  std::string value;
  std::cout << std::endl << query << "?: ";
  std::cin >> value;
  return toupper( *value.c_str() ) == 'Y';
}

FIX::SenderCompID Application::querySenderCompID()
{
  std::string value;
  std::cout << std::endl << "SenderCompID: ";
  std::cin >> value;
  return FIX::SenderCompID( value );
}

FIX::TargetCompID Application::queryTargetCompID()
{
  std::string value;
  std::cout << std::endl << "TargetCompID: ";
  std::cin >> value;
  return FIX::TargetCompID( value );
}

FIX::TargetSubID Application::queryTargetSubID()
{
  std::string value;
  std::cout << std::endl << "TargetSubID: ";
  std::cin >> value;
  return FIX::TargetSubID( value );
}

FIX::ClOrdID Application::queryClOrdID()
{
  std::string value;
  std::cout << std::endl << "ClOrdID: ";
  std::cin >> value;
  return FIX::ClOrdID( value );
}

FIX::OrigClOrdID Application::queryOrigClOrdID()
{
  std::string value;
  std::cout << std::endl << "OrigClOrdID: ";
  std::cin >> value;
  return FIX::OrigClOrdID( value );
}

FIX::Symbol Application::querySymbol()
{
  std::string value;
  std::cout << std::endl << "Symbol: ";
  std::cin >> value;
  return FIX::Symbol( value );
}

FIX::Side Application::querySide()
{
  char value;
  std::cout << std::endl
  << "1) Buy" << std::endl
  << "2) Sell" << std::endl
  << "3) Sell Short" << std::endl
  << "4) Sell Short Exempt" << std::endl
  << "5) Cross" << std::endl
  << "6) Cross Short" << std::endl
  << "7) Cross Short Exempt" << std::endl
  << "Side: ";

  std::cin >> value;
  switch ( value )
  {
    case '1': return FIX::Side( FIX::Side_BUY );
    case '2': return FIX::Side( FIX::Side_SELL );
    case '3': return FIX::Side( FIX::Side_SELL_SHORT );
    case '4': return FIX::Side( FIX::Side_SELL_SHORT_EXEMPT );
    case '5': return FIX::Side( FIX::Side_CROSS );
    case '6': return FIX::Side( FIX::Side_CROSS_SHORT );
    case '7': return FIX::Side( 'A' );
    default: throw std::exception();
  }
}

FIX::OrderQty Application::queryOrderQty()
{
  long value;
  std::cout << std::endl << "OrderQty: ";
  std::cin >> value;
  return FIX::OrderQty( value );
}

FIX::OrdType Application::queryOrdType()
{
  char value;
  std::cout << std::endl
  << "1) Market" << std::endl
  << "2) Limit" << std::endl
  << "3) Stop" << std::endl
  << "4) Stop Limit" << std::endl
  << "OrdType: ";

  std::cin >> value;
  switch ( value )
  {
    case '1': return FIX::OrdType( FIX::OrdType_MARKET );
    case '2': return FIX::OrdType( FIX::OrdType_LIMIT );
    case '3': return FIX::OrdType( FIX::OrdType_STOP );
    case '4': return FIX::OrdType( FIX::OrdType_STOP_LIMIT );
    default: throw std::exception();
  }
}

FIX::Price Application::queryPrice()
{
  double value;
  std::cout << std::endl << "Price: ";
  std::cin >> value;
  return FIX::Price( value );
}

FIX::StopPx Application::queryStopPx()
{
  double value;
  std::cout << std::endl << "StopPx: ";
  std::cin >> value;
  return FIX::StopPx( value );
}

FIX::TimeInForce Application::queryTimeInForce()
{
  char value;
  std::cout << std::endl
  << "1) Day" << std::endl
  << "2) IOC" << std::endl
  << "3) OPG" << std::endl
  << "4) GTC" << std::endl
  << "5) GTX" << std::endl
  << "TimeInForce: ";

  std::cin >> value;
  switch ( value )
  {
    case '1': return FIX::TimeInForce( FIX::TimeInForce_DAY );
    case '2': return FIX::TimeInForce( FIX::TimeInForce_IMMEDIATE_OR_CANCEL );
    case '3': return FIX::TimeInForce( FIX::TimeInForce_AT_THE_OPENING );
    case '4': return FIX::TimeInForce( FIX::TimeInForce_GOOD_TILL_CANCEL );
    case '5': return FIX::TimeInForce( FIX::TimeInForce_GOOD_TILL_CROSSING );
    default: throw std::exception();
  }
}

tradeclient.cpp文件:

#include "config.h"
#include "quickfix/FileStore.h"
#include "quickfix/SocketInitiator.h"
#include "quickfix/SessionSettings.h"
#include "quickfix/Log.h"
#include "Application.h"
#include <string>
#include <iostream>
#include <fstream>
#include <unistd.h>

int main( int argc, char** argv )
{
  if ( argc < 2 )
  {
    std::cout << "usage: " << argv[ 0 ]
    << " FILE." << std::endl;
    return 0;
  }
  std::string file = argv[ 1 ];

  FIX::Initiator * initiator = 0;
  try
  {
    FIX::SessionSettings settings( file );
    Application application;
    FIX::FileStoreFactory storeFactory( settings );
    FIX::ScreenLogFactory logFactory( settings );
    initiator = new FIX::SocketInitiator( application, storeFactory, 
                                          settings, logFactory );
    initiator->start();
    application.run();
    initiator->stop();

    delete initiator;

    return 0;
  }
  catch ( std::exception & e )
  {
    std::cout << e.what();
    delete initiator;
    return 1;
  }
}

CMakeLists.txt文件:

cmake_minimum_required(VERSION 3.10)

project(tradeclient)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")

include_directories(/usr/local/include/quickfix)
link_directories(/usr/local/lib)
link_libraries(quickfix)

add_executable(tradeclient Application.cpp tradeclient.cpp)

Initiator Session配置文件:

[DEFAULT]
ConnectionType=initiator
ReconnectInterval=60
SenderCompID=CLIENT
FileStorePath=./log

[SESSION]
BeginString=FIX.4.2
TargetCompID=GATEWAY
UseLocalTime=Y
StartTime=00:00:00
EndTime=23:30:00
HeartBtInt=30
SocketConnectPort=8088
SocketConnectHost=192.168.0.102
UseDataDictionary=Y
DataDictionary=./FIX42.xml

推荐参考学习资料:

量化IT技术专栏

QuantFabric开源量化交易系统

#FIX协议##QuickFIX#
全部评论

相关推荐

点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
11-27 10:48
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务