jamesdbrock / hffix

Financial Information Exchange Protocol C++ Library
http://jamesdbrock.github.io/hffix
Other
276 stars 89 forks source link

Failed while checksumming #21

Closed ahdzesq closed 5 years ago

ahdzesq commented 5 years ago

Hello,

I was sending a FIX message that pushes a string that it contains a character '%' but this causes an error while checksumming the FIX Message

10=135 [incorrect should be 182]

Also, the field BodyLength value is incorrect

The original field text contains this: "% EF Error: Issuer-Err (7): Operation after hours"

Looking for the packet after sending it (with Wireshark) the text field contains this: "-7.160094E + 12F Error: Issuer-Err ( 7): Operation after hours "

if I remove the character '%' after sending the FIX Message there is no problem and the checksum is correct

Just to let you know

Regards.

jamesdbrock commented 5 years ago

Thank you for the report @ahdzesq .

I have some questions.

You are sending this message with hffix and using one of the hffix::message_writer::push_back_string methods, is that right? Can you provide the code excerpt?

Is there some function like printf which is formatting the FIX message and substituting %E for a floating point conversion at some point after the FIX message has been written or before the FIX message is read?

ahdzesq commented 5 years ago

This is how it looks like the Function that I'm using

` miliseconds = (microsec_clock::universal_time() - epoch).total_milliseconds(); ptime tsExecutionReport(epoch_milliseconds_to_ptime(miliseconds));

hffix::message_writer ExecutionReport(bufferExecutionReport, bufferExecutionReport + sizeof(bufferExecutionReport));    

ExecutionReport.push_back_header    (FIX_VERSION);
ExecutionReport.push_back_string    (hffix::tag::MsgType, "8");
ExecutionReport.push_back_string    (hffix::tag::SenderCompID, SenderCompId);
ExecutionReport.push_back_string    (hffix::tag::TargetCompID, TargetCompId);
ExecutionReport.push_back_int       (hffix::tag::MsgSeqNum, Out_Seq_Num);
ExecutionReport.push_back_timestamp (hffix::tag::SendingTime, tsExecutionReport);

ExecutionReport.push_back_string    (hffix::tag::OrderID, ExecRep.OrderID);
ExecutionReport.push_back_string    (hffix::tag::ClOrdID, ExecRep.ClOrdID);
ExecutionReport.push_back_int       (hffix::tag::ExecID, ExecRep.ExecID);
ExecutionReport.push_back_int       (hffix::tag::ExecType, ExecRep.ExecType);
ExecutionReport.push_back_string    (hffix::tag::OrdStatus, ExecRep.OrderStatus);
ExecutionReport.push_back_int       (hffix::tag::Account, ExecRep.Account);
if (ExecRep.Symbol.compare("") != 0)
    ExecutionReport.push_back_string    (hffix::tag::Symbol, ExecRep.Symbol);
if (ExecRep.SecurityID.compare("") != 0)
    ExecutionReport.push_back_string    (hffix::tag::SecurityID, ExecRep.SecurityID);
ExecutionReport.push_back_int       (hffix::tag::Side, ExecRep.Side);    
ExecutionReport.push_back_int       (hffix::tag::OrderQty, ExecRep.OrderQty);  
ExecutionReport.push_back_int       (hffix::tag::OrdType, ExecRep.OrdType);  
ExecutionReport.push_back_decimal   (hffix::tag::Price, ExecRep.Price.Mantissa, ExecRep.Price.Exponent);
ExecutionReport.push_back_int       (hffix::tag::TimeInForce, ExecRep.TimeInForce);  
ExecutionReport.push_back_int       (hffix::tag::LeavesQty, ExecRep.LeavesQty);  
ExecutionReport.push_back_int       (hffix::tag::CumQty, ExecRep.CumQty);    

if (ExecRep.SecuritySubType.compare("") != 0)
    ExecutionReport.push_back_string    (hffix::tag::SecuritySubType, ExecRep.SecuritySubType);  
if (ExecRep.LastPx.Mantissa != 0)
    ExecutionReport.push_back_decimal   (hffix::tag::LastPx, ExecRep.LastPx.Mantissa, ExecRep.LastPx.Exponent);
if (ExecRep.LastQty != 0)
    ExecutionReport.push_back_int       (hffix::tag::LastQty, ExecRep.LastQty);  
if (ExecRep.Text.compare("") != 0)
    ExecutionReport.push_back_string    (hffix::tag::Text, ExecRep.Text);

ExecutionReport.push_back_trailer();          `

Is there some function like printf which is formatting the FIX message and substituting %E for a floating point conversion at some point after the FIX message has been written or before the FIX message is read?

About this the answer is no, the Tag text it came with the char '%' from the exchange

Just to give you a little of context, I have two classes the first one is "SessionInitiator" this one starts the session with the exchange, sends all the orders, and receive the execution report messages, after reading the execution report it fills a struct named Execution report that it has a lot of fields then pass this execution report to another class "SessionAcceptor" that uses the function above described to send it to the correct "Client", this function is where the error happens

Regards.

jamesdbrock commented 5 years ago

Well, considering that

  1. The value of a message field is getting a number substituted in for %
  2. The BodyLength of the message is incorrect

It seems likely there is some function which is transforming the message buffer after

ExecutionReport.push_back_trailer();

and before the SessionAcceptor sends the message. Is there anything in your code like that? What function is called to send the message buffer to the network?

ahdzesq commented 5 years ago

James,

There is nothing before the ExecutionReport.push_back_trailer();

Take a look this is the part of code that receivers the Execution report from the Exchange and Send it to the SessionAccetor Class

ExecutionReport ExecutionReport;                         
if (reader.find_with_hint(hffix::tag::OrderID, i))
    ExecutionReport.OrderID = i++->value().as_string();    
if (reader.find_with_hint(hffix::tag::SecondaryOrderID, i))
    ExecutionReport.SecondaryOrderID = i++->value().as_string();
if (reader.find_with_hint(hffix::tag::ClOrdID, i))    
    ExecutionReport.ClOrdID = i++->value().as_string();
if (reader.find_with_hint(hffix::tag::ExecID, i))      
    ExecutionReport.ExecID = i++->value().as_int<int>();   
if (reader.find_with_hint(hffix::tag::ExecType, i))      
    ExecutionReport.ExecType = i++->value().as_string();                                                                                                                                                                                                                                                                                                                                             
if (reader.find_with_hint(hffix::tag::OrdStatus, i))
    ExecutionReport.OrderStatus = i++->value().as_string();
if (reader.find_with_hint(hffix::tag::Account, i))      
    ExecutionReport.Account = i++->value().as_int<int>();
if (reader.find_with_hint(hffix::tag::Symbol, i))     
    ExecutionReport.Symbol = i++->value().as_string();                                    
if (reader.find_with_hint(hffix::tag::SecurityID, i))     
    ExecutionReport.SecurityID = i++->value().as_string();
if (reader.find_with_hint(hffix::tag::SecurityIDSource, i))     
    ExecutionReport.SecurityIDSource = i++->value().as_int<int>();  
if (reader.find_with_hint(hffix::tag::Side, i))
    ExecutionReport.Side = i++->value().as_int<int>();                                                                         
if (reader.find_with_hint(hffix::tag::OrderQty, i))  
    ExecutionReport.OrderQty = i++->value().as_int<int>();
if (reader.find_with_hint(hffix::tag::OrdType, i))  
    ExecutionReport.OrdType = i++->value().as_int<int>(); 
if (reader.find_with_hint(hffix::tag::Price, i))
    i++->value().as_decimal(ExecutionReport.Price.Mantissa, ExecutionReport.Price.Exponent);   
if (reader.find_with_hint(hffix::tag::TimeInForce, i))  
    ExecutionReport.TimeInForce = i++->value().as_int<int>();
if (reader.find_with_hint(hffix::tag::LeavesQty, i))  
    ExecutionReport.LeavesQty = i++->value().as_int<int>();                                    
if (reader.find_with_hint(hffix::tag::CumQty, i))  
    ExecutionReport.CumQty = i++->value().as_int<int>();      
if (reader.find_with_hint(hffix::tag::HandlInst, i))  
    ExecutionReport.HndlInst = i++->value().as_int<int>();                                                                                
if (reader.find_with_hint(hffix::tag::ExDestination, i))     
    ExecutionReport.ExDestination = i++->value().as_string();
if (reader.find_with_hint(hffix::tag::SecuritySubType, i))     
    ExecutionReport.SecuritySubType = i++->value().as_string();
if (reader.find_with_hint(hffix::tag::SettlDate, i))  
    ExecutionReport.SettlDate = i++->value().as_int<int>();                                     
if (reader.find_with_hint(hffix::tag::TradeDate, i))  
    ExecutionReport.TradeDate = i++->value().as_int<int>();   
if (reader.find_with_hint(hffix::tag::TrdMatchID, i))     
    ExecutionReport.TrdMatchID = i++->value().as_string();                                             
if (reader.find_with_hint(hffix::tag::AggressorIndicator, i))
    ExecutionReport.AggressorIndicator = i++->value().as_string();
if (reader.find_with_hint(hffix::tag::LastPx, i))
    i++->value().as_decimal(ExecutionReport.LastPx.Mantissa, ExecutionReport.LastPx.Exponent);
if (reader.find_with_hint(hffix::tag::LastQty, i))
    ExecutionReport.LastQty = i++->value().as_int<int>();
if (reader.find_with_hint(hffix::tag::Text, i))
    ExecutionReport.Text = i++->value().as_string();

boost::erase_all(ExecutionReport.Text, "%");

string OrderToFind = ExecutionReport.ClOrdID.substr(ExecutionReport.ClOrdID.find("_") + 1);
ExecutionReport.ClOrdID = OrderToFind;

map<string,string> :: const_iterator OrdIt;
OrdIt = OrderMap.find(OrderToFind);
if (OrdIt != OrderMap.end())
{
    Session* TempSession = TradingSessions.find(OrdIt->second)->second; 
    if (TempSession != NULL)
    {
      TempSession->SendExecutionReport (ExecutionReport);                          
        if (ExecutionReport.OrderStatus == "2" || ExecutionReport.OrderStatus == "8")
        {
            OrderMap.erase(OrdIt->first);                                               
        }                                                   
    }                                        
}

`

Before of that there is just a Switch that it iterates to the Message type '8'

as you can see there is a struct that it names ExecutionReport where it have a Text field, the Execution report struct looks like this:

struct ExecutionReport
{   
    string              OrderID;
    string              SecondaryOrderID;
    string              ClOrdID;
    int                 ExecID;
    int                 ExecTransType;
    string              ExecType;
    string              OrderStatus;
    int                 Account;
    string              Symbol;
    string              SecurityID;
    int                 SecurityIDSource;
    int                 Side;
    int                 OrderQty;
    int                 OrdType;
    Px                  Price;          
    int                 TimeInForce;
    int                 LeavesQty;
    int                 CumQty;
    int                 HndlInst;
    string              ExDestination;
    string              SecuritySubType;    
    Px                  LastPx;
    int                 LastQty;
    int                 TradeDate;
    int                 SettlDate;
    string              AggressorIndicator;
    string              TrdMatchID;
    string              Text;
}

`

As you can see the Text field is only a string, so the character '%' it comes from the exchange, the only way that I've found this works is removing the character '%' from the string "Text"

Many Thanks, Regards.

jamesdbrock commented 5 years ago

Hi @ahdzesq , What's your theory of why this problem is happening?

jamesdbrock commented 5 years ago

Could not reproduce, closing.