QuickFIX C++:发送MarketDataRequest后服务器无响应求助
我是FIX协议与QuickFIX的新手,成功运行QuickFIX官方仓库的tradingclient示例后,自行构建了Initiator类。连接状态正常(能看到指定间隔的心跳包),配置文件与官方示例一致且能正常获取行情,但发送MarketDataRequest后服务器无任何响应,也未抛出异常。以下是我的代码及运行输出:
FIXTrader.h
#pragma once #include <quickfix/Session.h> #include <quickfix/MessageCracker.h> #include <quickfix/Values.h> #include <quickfix/Mutex.h> #include <quickfix/fix43/MarketDataRequest.h> #include <queue> namespace FIX { class FIXTrader: public Application, MessageCracker { public: virtual ~FIXTrader() {}; void run(); private: void onCreate(const SessionID&); void onLogon(const SessionID&); void onLogout(const SessionID&); void toAdmin(Message&, const SessionID&); void toApp(Message&, const SessionID&) throw(DoNotSend); void fromAdmin(const Message&, const SessionID&) throw(FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon); void fromApp(const Message&, const SessionID&) throw(FieldNotFound, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType); void onMessage(const FIX43::ExecutionReport&, const FIX::SessionID&); void onMessage(const FIX43::OrderCancelReject&, const FIX::SessionID&); void onMessage(const FIX43::MarketDataRequest&, const FIX::SessionID&); void onMessage(const FIX43::MarketDataRequestReject&, const FIX::SessionID&); FIX43::MarketDataRequest queryMarketDataRequest43(); void queryHeader(FIX::Header& header); }; } #pragma comment(lib, "ws2_32.lib")
FIXTrader.cpp相关代码
void FIX::FIXTrader::onMessage (const FIX43::ExecutionReport&, const FIX::SessionID&) {} void FIX::FIXTrader::onMessage (const FIX43::OrderCancelReject&, const FIX::SessionID&) {} void FIX::FIXTrader::onMessage (const FIX43::MarketDataRequest&, const FIX::SessionID&) { std::cout << "request success" << std::endl; } void FIX::FIXTrader::onMessage (const FIX43::MarketDataRequestReject&, const FIX::SessionID&) { std::cout << "request rejected" << std::endl; } FIX43::MarketDataRequest FIX::FIXTrader::queryMarketDataRequest43() { FIX::MDReqID mdReqID("MARKETDATAID"); FIX::SubscriptionRequestType subType(FIX::SubscriptionRequestType_SNAPSHOT_PLUS_UPDATES); FIX::MarketDepth marketDepth(0); FIX43::MarketDataRequest::NoMDEntryTypes marketDataEntryGroup; FIX::MDEntryType mdEntryType(FIX::MDEntryType_BID); marketDataEntryGroup.set(mdEntryType); FIX43::MarketDataRequest::NoRelatedSym symbolGroup; FIX::Symbol symbol("EURUSD.x"); symbolGroup.set(symbol); FIX43::MarketDataRequest message(mdReqID, subType, marketDepth); message.addGroup(marketDataEntryGroup); message.addGroup(symbolGroup); queryHeader(message.getHeader()); std::cout << message.toXML() << std::endl; std::cout << message.toString() << std::endl; return message; } void FIX::FIXTrader::run() { try { FIX::Message md = queryMarketDataRequest43(); std::cout << "Sending marketrequest" << std::endl; std::cout << "sendToTarget() => " << FIX::Session::sendToTarget(md) << std::endl; std::cout << "Sent marketrequest" << std::endl; while (_getwch() != 126); } catch (std::exception& e) { std::cout << "Message Not Sent: " << e.what(); } }
main函数
#include "FixTrader.h" #include <quickfix/FileStore.h> #include <quickfix/FileLog.h> #include <quickfix/SocketInitiator.h> #include <quickfix/SessionSettings.h> #include <quickfix/config.h> // #include "quickfix/Application.h" int main(int argc, char** argv) { try { if (argc < 2) return 1; std::string fileName = argv[1]; FIX::SessionSettings settings(fileName); FIX::FIXTrader trader_app; FIX::FileStoreFactory storeFactory(settings); FIX::FileLogFactory logFactory(settings); FIX::SocketInitiator initiator (trader_app, storeFactory, settings, logFactory /*optional*/); initiator.start(); trader_app.run(); initiator.stop(); return 0; } catch (FIX::ConfigError& e) { std::cout << e.what(); return 1; } }
运行输出
C:\fix_trader\Release>fix_trader.exe configfile.txt <message> <header> <field number="8"><![CDATA[FIX.4.3]]></field> <field number="35"><![CDATA[V]]></field> <field number="49"><![CDATA[***]]></field> <field number="56"><![CDATA[****]]></field> </header> <body> <field number="146"><![CDATA[1]]></field> <field number="262"><![CDATA[MARKETDATAID]]></field> <field number="263"><![CDATA[1]]></field> <field number="264"><![CDATA[0]]></field> <field number="267"><![CDATA[1]]></field> <group> <field number="55"><![CDATA[EURUSD.x]]></field> </group> <group> <field number="269"><![CDATA[0]]></field> </group> </body> <trailer> </trailer> </message> 8=FIX.4.3 9=79 35=V 49=*** 56=**** 146=1 55=EURUSD.x 262=MARKETDATAID 263=1 264=0 267=1 269=0 10=223 Sending marketrequest OUT: 8=FIX.4.3 9=109 35=V 34=5 49=*** 52=20220924-07:35:58.000 56=**** 146=1 55=EURUSD.x 262=MARKETDATAID 263=1 264=0 267=1 269=0 10=184 sendToTarget() => 1 Sent marketrequest fromAdmin: 8=FIX.4.3 9=62 35=A 34=1 49=**** 52=20220924-07:35:58.404 56=*** 98=0 108=30 10=234 Logon successful! Session ID: FIX.4.3:***->**** fromAdmin: 8=FIX.4.3 9=50 35=0 34=2 49=**** 52=20220924-07:36:28.662 56=*** 10=194 fromAdmin: 8=FIX.4.3 9=50 35=0 34=3 49=**** 52=20220924-07:36:58.682 56=*** 10=200 fromAdmin: 8=FIX.4.3 9=50 35=5 34=4 49=**** 52=20220924-07:37:06.188 56=*** 10=201 Logged out from session: FIX.4.3:***->****
问题排查与解决方案
消息组顺序不符合FIX规范
从输出的消息结构可以看到,NoRelatedSym(含55字段的组)出现在NoMDEntryTypes(含269字段的组)之前,但FIX 4.3规范要求MarketDataRequest的组顺序是先NoMDEntryTypes,再NoRelatedSym。
建议移除手动设置Header的queryHeader函数——QuickFIX会自动填充SenderCompID、TargetCompID等必要Header字段,手动修改容易打乱消息内部结构。未实现MessageCracker的消息分发逻辑
你的FIXTrader继承了MessageCracker,但fromApp方法未调用crack方法,导致服务器返回的行情消息无法路由到对应的onMessage处理函数。补充实现:void FIX::FIXTrader::fromApp(const Message& message, const SessionID& sessionID) throw(FieldNotFound, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType) { crack(message, sessionID); }同时需要添加行情响应消息的处理函数,否则即使收到响应也无法感知:
void FIX::FIXTrader::onMessage(const FIX43::MarketDataSnapshotFullRefresh&, const FIX::SessionID&) { std::cout << "Received market data snapshot" << std::endl; } void FIX::FIXTrader::onMessage(const FIX43::MarketDataIncrementalRefresh&, const FIX::SessionID&) { std::cout << "Received market data incremental update" << std::endl; }发送消息时机过早
当前代码在Initiator启动后立刻发送请求,此时会话可能未完全建立。建议将请求发送逻辑移到onLogon方法中,确保登录成功后再发送:void FIX::FIXTrader::onLogon(const SessionID& sessionID) { std::cout << "Logon successful! Session ID: " << sessionID << std::endl; try { FIX43::MarketDataRequest md = queryMarketDataRequest43(); FIX::Session::sendToTarget(md, sessionID); std::cout << "Sent marketrequest after logon" << std::endl; } catch (std::exception& e) { std::cout << "Message Not Sent: " << e.what(); } }对应的
run函数只保留等待逻辑:void FIX::FIXTrader::run() { while (_getwch() != 126); }MDReqID唯一性检查
部分服务器会拒绝重复的MDReqID请求,建议使用带时间戳的唯一ID,比如:FIX::MDReqID mdReqID("MARKETDATAID_" + std::to_string(time(nullptr)));
内容的提问来源于stack exchange,提问作者Karthik Sivasubramaniam

