• FIX三天日记-quick fix简介


    一、介绍

    fix协议在上篇已经学习了,不再介绍。

    QuickFIX是一款C++实现的开源FIX引擎,同时提供Python等多种语言实现,具体看quickfix git地址

    官网已经介绍如何编译quickfix、配置文件字段含义等等,我假设你可以看懂,用的时候查阅即可,我就不复制过来了,本文是教你快速认识此框架并且用起来。

    二、主要类介绍

    想了解如何用某个组件,先了解他的成员都有哪些。

    2.1 Application

    若是须要使用QuickFIX开发FIX应用,则须要实现FIX::Application接口,并重载不一样FIX协议版本的MessageCracker::OnMessage接口,如FIX42::MessageCracker。

    1. class Application
    2. {
    3. public:
    4. virtual ~Application() {};
    5. /// Notification of a session begin created
    6. virtual void onCreate( const SessionID& ) = 0;
    7. /// Notification of a session successfully logging on
    8. virtual void onLogon( const SessionID& ) = 0;
    9. /// Notification of a session logging off or disconnecting
    10. virtual void onLogout( const SessionID& ) = 0;
    11. /// Notification of admin message being sent to target
    12. virtual void toAdmin( Message&, const SessionID& ) = 0;
    13. /// Notification of app message being sent to target
    14. virtual void toApp( Message&, const SessionID& )
    15. EXCEPT ( DoNotSend ) = 0;
    16. /// Notification of admin message being received from target
    17. virtual void fromAdmin( const Message&, const SessionID& )
    18. EXCEPT ( FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon ) = 0;
    19. /// Notification of app message being received from target
    20. virtual void fromApp( const Message&, const SessionID& )
    21. EXCEPT ( FieldNotFound, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType ) = 0;
    22. };

     onCreate:当Fix Session创建时调用。
    onLogon:当Fix Session登陆成功时调用。
    onLogout:当Fix Session退出时调用。
    fromAdmin:当收到一个Admin类型消息时调用。
    fromApp:当收到一个不属于Admin 类型消息时调用。
    toAdmin:当发送一个admin类型消息调用。
    toApp:当发送一个非admin(业务类型)消息调用。

    admin一般是服务提供方,app是客户端

    对于支持交易业务的FIX Initiator应用,通常重写4个基本消息,OnMessage(NewOrderSingle)、OnMessage(CancelRequest)、 OnMessage(ExecutionReport)、 OnMessage(CancelReject),用于做委托、撤单、执行回包和对撤单拒绝等4项业务。

    更全面的介绍是这样的,入门选手可以先不了解这么详细:

    • onCreate:当quickfix创建新会话时调用。会话一旦创建,将应用程序的整个生命周期内保持存在。不管对方是否连接到会话,会话都存在。一旦创建了会话,就可以开始向它发送消息。如果没有人登录,则消息将在与对方建立连接时发送。
    • onLogon:当建立连接并完成FIX登录过程(双方交换有效的登录消息)时调用该函数。
    • onLogout:当某个 FIX 会话不再在线时进行通知,这可能发生在正常的注销交换过程中,或者由于强制终止或网络连接丢失。
    • toAdmin:使您可以了解从FIX引擎发送到交易方的管理消息。这通常对应用程序没有用处,但它可以让你进行与管理消息相关的日志记录。注意:FIX::Message 不是常量,这允许你在发送管理消息之前向其添加字段。
    • toApp:正在发送给对手方的应用程序消息时进行的回调。如果在这个函数中抛出一个 DoNotSend 异常,应用程序将不会发送消息。这可用于取消重新发送一些不必要的消息,比如与当前市场不再相关的订单。注意:FIX::Message 不是常量,这允许你在发送管理消息之前向其添加字段。
      • 抛出 DoNotSend 异常并将消息的 PossDupFlag 设置为 true:a sequence reset will be sent in place of the message.(序列号将被重置为这个要发送的消息的序列号?)
      • 抛出 DoNotSend 异常并将消息的 PossDupFlag 设置为 false:不会发送消息。
    • fromAdmin:当管理消息从交易方发送到 FIX 引擎时通知您。这对于对登录消息(如验证密码)进行额外的验证非常有用。在函数中抛出 RejectLogon 异常将断开对方的连接。
    • fromApp:接收应用程序级请求。如果您的应用程序是一个卖方OMS,您将从函数中获得的新订单请求;如果你是买方,你会在这里拿到你的执行报告。
      • 如果抛出 FieldNotFound 异常,对方将收到一个 Reject消息,表示缺少一个条件要求的字段。当试图检索丢失的字段时,Message 类将抛出此异常,因此很少需要显式地抛出。
      • 如果抛出 UnsupportedMessageType 异常,对方将收到一个 Reject消息,通知他们您的应用程序无法处理这些类型的消息。
      • 如果字段包含您不支持的值,也会抛出 IncorrectTagValue

    如果应用程序在多个会话之间共享资源,则必须同步这些资源;可以用SynchronizedApplication 类来自动同步应用程序中的所有函数调用,各种 MessageCracker 类可用于将通用消息结构解析为特定的 FIX 消息。 

    2.2 SynchronizedApplication

    Application 的区别:通过 Mutex 在回调的时候保证这一次只有一个线程访问应用程序的代码,这样对性能有影响。

    1. /**
    2. * This is a special implementation of the Application interface that takes
    3. * in another Application interface and synchronizes all of its callbacks. This
    4. * will guarantee that only one thread will access the applications code at a time.
    5. *
    6. * This class is a great convenience for writing applications where you
    7. * don't want to worry about synchronization. There is of course a tradeoff
    8. * in that you may be synchronizing more than you need to. There is also a very
    9. * minor performance penalty due to the extra virtual table lookup.
    10. */
    11. class SynchronizedApplication : public Application
    12. {
    13. public:
    14. SynchronizedApplication( Application& app ) : m_app( app ) {}
    15. void onCreate( const SessionID& sessionID )
    16. { Locker l( m_mutex ); app().onCreate( sessionID ); }
    17. void onLogon( const SessionID& sessionID )
    18. { Locker l( m_mutex ); app().onLogon( sessionID ); }
    19. void onLogout( const SessionID& sessionID )
    20. { Locker l( m_mutex ); app().onLogout( sessionID ); }
    21. void toAdmin( Message& message, const SessionID& sessionID )
    22. { Locker l( m_mutex ); app().toAdmin( message, sessionID ); }
    23. void toApp( Message& message, const SessionID& sessionID )
    24. throw( DoNotSend )
    25. { Locker l( m_mutex ); app().toApp( message, sessionID ); }
    26. void fromAdmin( const Message& message, const SessionID& sessionID )
    27. throw( FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon )
    28. { Locker l( m_mutex ); app().fromAdmin( message, sessionID ); }
    29. void fromApp( const Message& message, const SessionID& sessionID )
    30. throw( FieldNotFound, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType )
    31. { Locker l( m_mutex ); app().fromApp( message, sessionID ); }
    32. Mutex m_mutex;
    33. Application& app() { return m_app; }
    34. Application& m_app;
    35. };

    2.3. FIX::NullApplication实现

    FIX::NullApplication 主要用于不想要实现所有回调接口的场景中,可以继承该类。

    1. class NullApplication : public Application
    2. {
    3. void onCreate( const SessionID& ) {}
    4. void onLogon( const SessionID& ) {}
    5. void onLogout( const SessionID& ) {}
    6. void toAdmin( Message&, const SessionID& ) {}
    7. void toApp( Message&, const SessionID& )
    8. EXCEPT ( DoNotSend ) {}
    9. void fromAdmin( const Message&, const SessionID& )
    10. EXCEPT ( FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon ) {}
    11. void fromApp( const Message&, const SessionID& )
    12. EXCEPT ( FieldNotFound, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType ) {}
    13. };

     

    2.4 SessionSettings

    FIX配置使用FIX::SessionSettings读取FIX Session配置文件并传递给QuickFIX框架。

    一个FIX应用能够管理多个FIX Session,每一个Session能够采用相同的FIX协议版本,也能够采用不一样的版本。即便采用的是相同的FIX协议版本,不一样FIX Session间也能够有FIX协议细节的差别,经过绑定FIX Session与FIX协议字典的方式来实现,即在Session配置文件中[Session]配置项中使用DataDictionary选项指定相应FIX字典文件来实现。

    FIX::SessionSettings settings("sessionConfig.ini");

    应用如何实现的管理多session?看Initiator/Acceptor源码可以明白

    1. class{
    2. '''
    3. typedef std::set < SessionID > SessionIDs;
    4. typedef std::map < SessionID, int > SessionState;
    5. typedef std::map < SessionID, Session* > Sessions;
    6. Sessions m_sessions;
    7. SessionIDs m_sessionIDs;
    8. SessionState m_sessionState;
    9. ...
    10. }

     三个map记录id、状态、具体对象。

    2.5 FileStoreFactory

    QuickFIX提供了存储消息到文件的类FIX::FileStoreFactory。消息文件存储的路径在Session配置中指定。具体配置下文提到。

    FIX::FileStoreFactory storeFactory(settings);

    2.4 MessageStoreFactory

    QuickFIX提供了给Fix Session持久化类型(如文件存储、数据存储,存储内容包括状态、建立时间、消息及其本身维护的发送序列号和接收序列号等)。
    如果开发者要自定义持久化方式,也可以自己实现MessageStoreFactory,而且自定义一种MessageStore的ide。

    1. /**
    2. * This interface must be implemented to create a MessageStore.
    3. */
    4. class MessageStoreFactory
    5. {
    6. public:
    7. virtual ~MessageStoreFactory() {}
    8. virtual MessageStore* create( const SessionID& ) = 0;
    9. virtual void destroy( MessageStore* ) = 0;
    10. };

    2.5 FIX::FileLogFactory

    QuickFIX提供了存储全部日志事件到文件的类FIX::FileLogFactory。

    2.6 FIX::Message

    QuickFIX中定义了不一样FIX协议版本消息的基类FIX::Message,用于定义FIX消息的通用结构,不一样的FIX消息版本的消息定义在不一样的FIX命名空间内定义,如FIX42::Message。FIX::MessageCracker则继承了全部不一样FIX协议版本的MessageCracker类,接收消息后生成具体FIX协议Message对象实现对消息进行处理。

    2.7 FIX::Acceptor


    FIX::Acceptor用于创建和管理本Acceptor的Session。

    具体Session的TCP连接管理、数据读写由具体的SocketAcceptor、SSLSocketAcceptor、ThreadedSocketAcceptor、ThreadedSSLSocketAcceptor实现。

    1. FIX::Acceptor* acceptor = new FIX::SocketAcceptor(application, storeFactory, 
    2.                                                   settings, logFactory);


    2.8 FIX::Initiator


    FIX::Initiator用于创建和管理本Initiator支持的Session。

    具体Session的TCP连接管理、数据读写由具体的SocketInitiator、SSLSocketInitiator、ThreadedSocketInitiator、ThreadedSSLSocketInitiator实现。

    FIX::Initiator * initiator = new FIX::SocketInitiator(application,  storeFactory,  settings, logFactory);

    三、创建应用

    我们根据第二章的内容创建一个应用(主体见2.1)

    .h

    1. #ifndef EXECUTOR_APPLICATION_H
    2. #define EXECUTOR_APPLICATION_H
    3. #include "quickfix/Application.h"
    4. #include "quickfix/MessageCracker.h"
    5. #include "quickfix/Values.h"
    6. #include "quickfix/Utility.h"
    7. #include "quickfix/Mutex.h"
    8. #include "quickfix/fix40/NewOrderSingle.h"
    9. #include "quickfix/fix41/NewOrderSingle.h"
    10. #include "quickfix/fix42/NewOrderSingle.h"
    11. #include "quickfix/fix43/NewOrderSingle.h"
    12. #include "quickfix/fix44/NewOrderSingle.h"
    13. #include "quickfix/fix50/NewOrderSingle.h"
    14. class Application
    15. : public FIX::Application, public FIX::MessageCracker
    16. {
    17. public:
    18. Application() : m_orderID(0), m_execID(0) {}
    19. // Application overloads
    20. void onCreate( const FIX::SessionID& );
    21. void onLogon( const FIX::SessionID& sessionID );
    22. void onLogout( const FIX::SessionID& sessionID );
    23. void toAdmin( FIX::Message&, const FIX::SessionID& );
    24. void toApp( FIX::Message&, const FIX::SessionID& )
    25. EXCEPT( FIX::DoNotSend );
    26. void fromAdmin( const FIX::Message&, const FIX::SessionID& )
    27. EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::RejectLogon );
    28. void fromApp( const FIX::Message& message, const FIX::SessionID& sessionID )
    29. EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::UnsupportedMessageType );
    30. // MessageCracker overloads
    31. void onMessage( const FIX40::NewOrderSingle&, const FIX::SessionID& );
    32. void onMessage( const FIX41::NewOrderSingle&, const FIX::SessionID& );
    33. void onMessage( const FIX42::NewOrderSingle&, const FIX::SessionID& );
    34. void onMessage( const FIX43::NewOrderSingle&, const FIX::SessionID& );
    35. void onMessage( const FIX44::NewOrderSingle&, const FIX::SessionID& );
    36. void onMessage( const FIX50::NewOrderSingle&, const FIX::SessionID& );
    37. std::string genOrderID() {
    38. std::stringstream stream;
    39. stream << ++m_orderID;
    40. return stream.str();
    41. }
    42. std::string genExecID() {
    43. std::stringstream stream;
    44. stream << ++m_execID;
    45. return stream.str();
    46. }
    47. private:
    48. int m_orderID, m_execID;
    49. };
    50. #endif

    .cpp

    1. #include "quickfix/config.h"
    2. #include "Application.h"
    3. #include "quickfix/Session.h"
    4. #include "quickfix/fix40/ExecutionReport.h"
    5. #include "quickfix/fix41/ExecutionReport.h"
    6. #include "quickfix/fix42/ExecutionReport.h"
    7. #include "quickfix/fix43/ExecutionReport.h"
    8. #include "quickfix/fix44/ExecutionReport.h"
    9. #include "quickfix/fix50/ExecutionReport.h"
    10. void Application::onCreate( const FIX::SessionID& sessionID ) {}
    11. void Application::onLogon( const FIX::SessionID& sessionID ) {}
    12. void Application::onLogout( const FIX::SessionID& sessionID ) {}
    13. void Application::toAdmin( FIX::Message& message,
    14. const FIX::SessionID& sessionID ) {}
    15. void Application::toApp( FIX::Message& message,
    16. const FIX::SessionID& sessionID )
    17. EXCEPT( FIX::DoNotSend ) {}
    18. void Application::fromAdmin( const FIX::Message& message,
    19. const FIX::SessionID& sessionID )
    20. EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::RejectLogon ) {}
    21. void Application::fromApp( const FIX::Message& message,
    22. const FIX::SessionID& sessionID )
    23. EXCEPT( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::UnsupportedMessageType )
    24. { crack( message, sessionID ); }
    25. void Application::onMessage( const FIX40::NewOrderSingle& message,
    26. const FIX::SessionID& sessionID )
    27. {
    28. FIX::Symbol symbol;
    29. FIX::Side side;
    30. FIX::OrdType ordType;
    31. FIX::OrderQty orderQty;
    32. FIX::Price price;
    33. FIX::ClOrdID clOrdID;
    34. FIX::Account account;
    35. message.get( ordType );
    36. if ( ordType != FIX::OrdType_LIMIT )
    37. throw FIX::IncorrectTagValue( ordType.getField() );
    38. message.get( symbol );
    39. message.get( side );
    40. message.get( orderQty );
    41. message.get( price );
    42. message.get( clOrdID );
    43. FIX40::ExecutionReport executionReport = FIX40::ExecutionReport
    44. ( FIX::OrderID( genOrderID() ),
    45. FIX::ExecID( genExecID() ),
    46. FIX::ExecTransType( FIX::ExecTransType_NEW ),
    47. FIX::OrdStatus( FIX::OrdStatus_FILLED ),
    48. symbol,
    49. side,
    50. orderQty,
    51. FIX::LastShares( orderQty ),
    52. FIX::LastPx( price ),
    53. FIX::CumQty( orderQty ),
    54. FIX::AvgPx( price ) );
    55. executionReport.set( clOrdID );
    56. if( message.isSet(account) )
    57. executionReport.setField( message.get(account) );
    58. try
    59. {
    60. FIX::Session::sendToTarget( executionReport, sessionID );
    61. }
    62. catch ( FIX::SessionNotFound& ) {}
    63. }

    代码很简单,唯一可能值得注意的两点:

    1、一般情况下,对于FIX应用开发,除了实现FIX::Application接口,还需要重新实现FIX::MessageCracker从具体FIX协议版本实现继承来的onMessage方法,所以我们一般这么写:

    class FIXApplication: public FIX::Application, public FIX::MessageCracker

    2、crack接口,他根据message类型匹配到你实现的具体onMessage接口上。

    1. void crack( const Message& message,
    2. const SessionID& sessionID )
    3. {
    4. const FIX::BeginString& beginString =
    5. FIELD_GET_REF( message.getHeader(), BeginString );
    6. crack( message, sessionID, beginString );
    7. }
    8. void crack( const Message& message,
    9. const SessionID& sessionID,
    10. const BeginString& beginString )
    11. {
    12. if ( beginString == BeginString_FIX40 )
    13. ((FIX40::MessageCracker&)(*this)).crack((const FIX40::Message&) message, sessionID);
    14. else if ( beginString == BeginString_FIX41 )
    15. ((FIX41::MessageCracker&)(*this)).crack((const FIX41::Message&) message, sessionID);
    16. else if ( beginString == BeginString_FIX42 )
    17. ((FIX42::MessageCracker&)(*this)).crack((const FIX42::Message&) message, sessionID);
    18. else if ( beginString == BeginString_FIX43 )
    19. ((FIX43::MessageCracker&)(*this)).crack((const FIX43::Message&) message, sessionID);
    20. else if ( beginString == BeginString_FIX44 )
    21. ((FIX44::MessageCracker&)(*this)).crack((const FIX44::Message&) message, sessionID);
    22. else if ( beginString == BeginString_FIXT11 )
    23. {
    24. if( message.isAdmin() )
    25. {
    26. ((FIXT11::MessageCracker&)(*this)).crack((const FIXT11::Message&) message, sessionID);
    27. }
    28. else
    29. {
    30. '''
    31. }
    32. }
    33. }

    四、发送方

    Acceptor,也可以称作为 Server,就是服务端。客户端从各地发来交易或者行情请求后,由这些服务器端接收,并进一步送给决策端进行验证、决策,并由此服务器返回相应的结果。大概的回复可能是这样的:

    • 行情请求(35=V)——行情报价回复(35=W);
    • 新建订单(35=D)——订单回复(35=8)
    • 撤销订单(35=F)——订单回复(35=8)或者拒绝(35=9)

    搭建一个服务端非常的简单,只需要两个类:一个类负责初始化、启动和关停服务(见2.7 FIX::Acceptor);另一个类负责服务,即收发消息(见2.1 Application)。

    在第三章我们已经实现了收发消息的类,接下来我们实现Acceptor,万里长征就走完了一大半。

    (1)创建FIX Session配置对象FIX::SessionSettings settings(sessionFile);
    (2)创建FIX应用:Application application;
    (3)创建日志工厂:LogFactory logFactory(settings);
    (4)创建消息存储文件工厂:FIX::FileStoreFactory storeFactory(settings);
    (5)创建Acceptor服务端:acceptor = new FIX::SocketAcceptor ( application, storeFactory, 
                                             settings, logFactory );
    (6)启动:acceptor->start();

    1. #include "config.h"
    2. #include "quickfix/FileStore.h"
    3. #include "quickfix/SocketAcceptor.h"
    4. #include "quickfix/Log.h"
    5. #include "quickfix/SessionSettings.h"
    6. #include "Application.h"
    7. #include
    8. #include
    9. #include
    10. int main( int argc, char** argv )
    11. {
    12. if ( argc < 2 )
    13. {
    14. std::cout << "usage: " << argv[ 0 ]
    15. << " FILE." << std::endl;
    16. return 0;
    17. }
    18. std::string file = argv[ 1 ];
    19. FIX::Acceptor * acceptor = 0;
    20. try
    21. {
    22. FIX::SessionSettings settings( file );
    23. Application application;
    24. FIX::FileStoreFactory storeFactory( settings );
    25. FIX::ScreenLogFactory logFactory( settings );
    26. acceptor = new FIX::SocketAcceptor ( application, storeFactory,
    27. settings, logFactory );
    28. acceptor->start();
    29. // dosomething wait();
    30. acceptor->stop();
    31. delete acceptor;
    32. return 0;
    33. }
    34. catch ( std::exception & e )
    35. {
    36. std::cout << e.what() << std::endl;
    37. delete acceptor;
    38. return 1;
    39. }
    40. }

    五、接收方

    Initiator,也可以称作为 Client,就是分散在各个地方的交易机(客户端)。业务员在上面操作以后,客户端会向服务器发送请求。请求多种多样,基本常用的有:行情请求(35=V),新建订单(35=D),撤销订单(35=F)。

    搭建Initiator和服务端基本一样,不过多解释。(当然,买方卖方的application逻辑肯定不一样,这里只是给你一个代码框架,希望你注意)

    1. #include "config.h"
    2. #include "quickfix/FileStore.h"
    3. #include "quickfix/SocketInitiator.h"
    4. #include "quickfix/SessionSettings.h"
    5. #include "quickfix/Log.h"
    6. #include "Application.h"
    7. #include
    8. #include
    9. #include
    10. int main( int argc, char** argv )
    11. {
    12. if ( argc < 2 )
    13. {
    14. std::cout << "usage: " << argv[ 0 ]
    15. << " FILE." << std::endl;
    16. return 0;
    17. }
    18. std::string file = argv[ 1 ];
    19. FIX::Initiator * initiator = 0;
    20. try
    21. {
    22. FIX::SessionSettings settings( file );
    23. Application application;
    24. FIX::FileStoreFactory storeFactory( settings );
    25. FIX::ScreenLogFactory logFactory( settings );
    26. initiator = new FIX::SocketInitiator( application, storeFactory,
    27. settings, logFactory );
    28. initiator->start();
    29. application.run();
    30. initiator->stop();
    31. delete initiator;
    32. return 0;
    33. }
    34. catch ( std::exception & e )
    35. {
    36. std::cout << e.what();
    37. delete initiator;
    38. return 1;
    39. }
    40. }

    六、进一步的操作

    通过上文,我们已经了解了quickfix大概的代码框架是什么样子的,接下来认识一些进一步的操作,以便我们可以把这个小demo真的做成一个功能。

     6.1 配置文件

    配置文件,简化来讲,有两个:一个是程序调用的properties,另一个是传输时候的字典,相当于“密码本”。
     

    先看一下文件内容

    6.1.1 quickfix.properties

    1. #quickfix-server.properties
    2. [default]
    3. # 这些字段接的改成你的设置
    4. FileStorePath=fileStore
    5. SocketConnectHost=XXX.XXX.XXX.XXX
    6. SocketConnectPort=XXXXX
    7. TargetCompID=QUICKFIX_ACCEPTOR
    8. # 以下字段可以不改
    9. ConnectionType=initiator
    10. HeartBtInt=30
    11. ReconnectInterval=10
    12. FileLogPath=log
    13. UseDataDictionary=N
    14. DataDictionary=src/main/resources/FIX44.modified.xml
    15. ContinueInitializationOnError=Y
    16. BeginString=FIX.4.4
    17. StartTime=00:00:00
    18. EndTime=23:00:00
    19. ResetOnLogon=Y
    20. ResetSeqNumFlag=Y
    21. MaxMessagesInResendRequest=1
    22. [session]
    23. SenderCompID=QUICKFIX_INITIATOR1
    24. [session]
    25. SenderCompID=QUICKFIX_INITIATOR2

    能看到,配置被分为3大类:开头的[default],然后是两个[session]。

    session的意思是,你作为发送方时,不一定发给一个人。或者你作为接收方时,不一定只接收一个人的信息。每个session下面配了不同的SenderCompID,意思就是可能会有很多Sender给我发消息,因此我要根据不同的SenderComID来区别不同的发送方。这个名字可以随便起,只要保证收发双方一致。

    其他公用的部分可以放在[default]里面,其中:

    • FileStorePath是存储消息和事件的文件夹,确保一定要有写的权限;
    • SocketConnectHost和SocketConnectPort 是你Accepter的IP地址和端口;
    • TargetCompID 是你发的消息由谁来接收(和SenderCompID对应);
    • ConnectionType是你扮演的角色,有initiator和acceptor两种;
    • HeartBtInt是心跳间隔。

    更多配置直接查阅官网。

    讲到这里,我害怕你还是不会写两边的配置,所以我复制一份

    1. [default]
    2. # 这些字段记得改成你的设置
    3. FileStorePath=fileStore
    4. SocketConnectHost=***
    5. SocketConnectPort=***
    6. TargetCompID=QUICKFIX_ACCEPTOR
    7. # 以下字段可以不改
    8. ConnectionType=initiator
    9. HeartBtInt=30
    10. ReconnectInterval=10
    11. FileLogPath=log
    12. UseDataDictionary=N
    13. DataDictionary=src/main/resources/FIX44.modified.xml
    14. ContinueInitializationOnError=Y
    15. BeginString=FIX.4.4
    16. StartTime=00:00:00
    17. EndTime=23:00:00
    18. ResetOnLogon=Y
    19. ResetSeqNumFlag=Y
    20. MaxMessagesInResendRequest=1
    21. [session]
    22. SenderCompID=QUICKFIX_INITIATOR1
    23. [session]
    24. SenderCompID=QUICKFIX_INITIATOR2
    1. #quickfix-server.properties
    2. [default]
    3. # 这些字段记得改成你的设置
    4. FileStorePath=fileStore
    5. SocketAcceptAddress=***
    6. SocketAcceptPort=***
    7. SenderCompID=QUICKFIX_ACCEPTOR
    8. # 以下字段可以不改
    9. ConnectionType=acceptor
    10. HeartBtInt=30
    11. #ReconnectInterval=10
    12. FileLogPath=log
    13. DataDictionary=src/main/resources/FIX44.modified.xml
    14. ContinueInitializationOnError=Y
    15. BeginString=FIX.4.4
    16. StartTime=00:00:00
    17. EndTime=23:00:00
    18. ResetOnLogon=Y
    19. ResetSeqNumFlag=Y
    20. MaxMessagesInResendRequest=1
    21. SocketReuseAddress=Y
    22. UseDataDictionary=Y
    23. [session]
    24. TargetCompID=QUICKFIX_INITIATOR1
    25. [session]
    26. TargetCompID=QUICKFIX_INITIATOR2

    6.1.2 FIX44.modified.xml

    在实际业务中,我们会对字典进行一定修改,比如让某些字段从“必须有”到“可以有”,增减某些消息里面的某些字段,甚至定义自己的新消息。在这个时候,我们就可以在原有FIX44.xml的基础上维护我们自己的“密码本”,取个名字:FIX44.modified.xml。

    每一个消息都在message的标签内:

    • name="MarketDataRequestReject" 表示名字;
    • msgtype="Y" 表示他的类别,在传输的时候会表现为“35=Y”;
    • msgcat="app" 表示他是App层的传输。另外一个是Admin;
    • field name="MDReqID" required="N" 表示这个消息有个字段叫MDReqID,并且在传输的时候不是必须的。如果一个字段定义为required="Y"但是实际没有传,那么这条消息就会被自动拒收,并返回“35=3”的消息高速对方;
    • group name="NoAltMDSource" 表示里面有个重复组,即一个消息中可能多次出现同一个字段(比如我在查询行情的时候可能查询多个产品的行情),那么这可以“重复”的字段就必须定义在重复组里。

    更多信息查阅官网

    6.2 官网需要查看的东西

    我还希望你可以查看官网的第三章和第四章,这可以帮助你学习quickfix的各种细节用法,包括如何收发消息、重复组的使用、自定义字段使用、他们自带的一套测试框架等等

     七、常见的错误解答&q&a

    第一条消息由Initiator 发出,但是在Acceptor端没有看到接收的痕迹。

    可能是Initiator端在发送第一条消息的时候过快,以至于抢在了登录之前。

    SessionNotFound

    一般都是你配置错误导致找不到session,我们前期讲过,一个Session由3个基本要素构成:消息头、发送方、接收方。任何一方有错误都会导致上述的SessionNotFound问题。

    比如最常见的错误是:Properties 文件中IP地址和端口不对或被占用?

    toApp 接口中,抛出 DoNoSend 异常会对序列号造成影响吗?

    Application::toApp() 接口的回调发生在序列号递增(Session::persist())之前,所以不会对序列号造成影响。

    SendingTime Accuracy Problem

    因为收发双方的时间不对应,根据Fix协议,默认双方时差在30s以上时就会爆出这种时钟不同步的问题。

    解决办法1:配置你的机器,使时间一致。

    解决办法2:通过设置properties文件,配置CheckLatency=N,这样就不会去做时钟同步检查。


    Logout is Called

    在建立链接的时候,立即收到Logout is Called的消息,除此之外没有其他提示。

    如果不是网络问题,那就是对方拒绝了跟你的通信,但出于安全考虑,又不想暴露原因,就会抛出这么一个消息。

    可能的原因有:

    1. 没有使用SSL链接方式;
    2. Logon时候对方需求在消息中包含用户名和密码,但你没有写;
    3. SenderCompID没配好,是对方不能识别或者没有记录在案的ID。

     

  • 相关阅读:
    AspNetCore7.0源码解读之UseMiddleware
    深入理解 Docker 核心原理:Namespace、Cgroups 和 Rootfs
    Linux性能优化-网络篇-DNS问题排查
    C专家编程 第1章 C:穿越时空的迷雾 1.3 标准I/O库和C预处理器
    python中取整数操作
    javaee spring 声明式事务管理 自定义异常类
    再见 Sidecars,eBPF 能否扛起新大旗?
    【花雕体验】11 上手ESP32C3
    java计算机毕业设计用户行为自动化书籍推荐系统源码+系统+mysql数据库+lw文档+部署
    Stable DIffusion 炫酷应用 | AI嵌入艺术字+光影光效
  • 原文地址:https://blog.csdn.net/hebtu666/article/details/126179473