c++windowsalgorithmic-tradingquickfixfix-protocol

QuickFIX C++ - No response for MarketDataRequest from the server


I'm new to FIX protocol and QuickFIX. After I was able to successfully run the tradingclient example from the official QuickFIX repo, I tried building my own class (initiator). Everything seems to go well up until I send a MarketDataRequest to the server. After that, there's no response from the server. No exceptions either.

I know my configuration file is correct, since the official example works and returns market data with the same configuration file. The connection is also intact, since I could see the heartbeat coming through at the specified interval. What might I be doing wrong?

Here's my class header file - 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")

Here are the relevant parts of my FIXTrader.cpp (I'm willing to add more if necessary):

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();
    }
}

And here's my main function:

#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;
    }
}

Here's the output when I try to run the build:

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:***->**** 

Any help is appreciated.


Solution

  • I finally figured out why it wasn't working. It is a silly mistake once the understanding came.

    I just needed to include MarketDataSnapshotFullRefresh (or whatever snapshot type I'm requesting), and overload the onMessage callback method appropriately.

    Sharing here for anyone who might find this helpful in future.

    #pragma once
    
    // Other includes here
    // ...
    // ...
    #include <quickfix/fix43/MarketDataSnapshotFullRefresh.h>
    
    namespace FIX
    {
        class FIXTrader: public Application, MessageCracker
        {
        public:
            virtual ~FIXTrader() {};
            void run();
    
        private:
    
            // Other member methods and overloads here
            // ...
            // ...
            void onMessage(const FIX43::MarketDataRequest&, const FIX::SessionID&);
            void onMessage(const FIX43::MarketDataRequestReject&, const FIX::SessionID&);
            void onMessage(const FIX43::MarketDataSnapshotFullRefresh&, const FIX::SessionID&);
        };
    }
    
    #pragma comment(lib, "ws2_32.lib")
    

    Since I was missing the overload, it looks like the response ticks from the counterparty was just disappearing into the void. Now the overloaded function captures the market data and sends it to my fromApp callback.