Two orders with the same ticket number

yoriz  

I am running two instances of the same EA on two VPSes in two different data-centers, each with a different magic number. Tonight both EAs placed the same buy stop order (with different magic numbers) using this code:

CTrade trade;
if (!trade.BuyStop(lotSize, entry, _Symbol, sl, tp, ORDER_TIME_GTC)) {
    Print(expert + ": ERROR: Failed to open new pending buy stop");
    return;
}
switch (trade.ResultRetcode()) {
    case TRADE_RETCODE_PLACED:
    case TRADE_RETCODE_DONE:
    case TRADE_RETCODE_DONE_PARTIAL:
        break;
    default:
        PrintFormat(expert + ": ERROR: Failed to open new pending buy stop (retcode=%u)", trade.ResultRetcode());
        return;
}
ulong buyTicket = trade.ResultOrder();
PrintFormat(expert + ": Opened new pending buy stop #%u at %s", buyTicket, DoubleToString(entry, _Digits));


In the Experts tab of VPS A this message is logged:

2023.01.16 01:00:00.280   Expert: Opened new pending buy stop #569182975 at 1.08671

In the Experts tab of VPS B the exact same ticket number is logged:

2023.01.16 01:00:00.367   Expert: Opened new pending buy stop #569182975 at 1.08671


After 0.357 seconds VPS A received a OnTradeTransaction with a new ticket number via this code:

void OnTradeTransaction(
               const MqlTradeTransaction&    trans,
               const MqlTradeRequest&        request,
               const MqlTradeResult&         result) {
   if (trans.type == TRADE_TRANSACTION_ORDER_ADD) {
      COrderInfo order;
      if (order.Select(trans.order)) {
         if (order.Magic() == MagicNumber &&
             order.Symbol() == _Symbol) {
            if (order.OrderType() == ORDER_TYPE_BUY_STOP) {
               if (buyTicket > 0) {
                  if (buyTicket != order.Ticket()) {
                     PrintFormat(expert + ": ERROR: Buy ticket #%u has been replaced by ticket #%u", buyTicket, order.Ticket());
                  }
               } else {
                  PrintFormat(expert + ": Pending buy order was assigned ticket number #%u", order.Ticket());
                  buyTicket = order.Ticket();
               }
            }
            ...

In the Experts log I see the following message:

2023.01.16 01:00:00.637   Expert: ERROR: Buy ticket #569182975 has been replaced by ticket #569183075

This weird change in ticket number confused further logic in my EA resulting in the trade being abandoned costing me 1050 Euro in loss.

The documentation of CTrade::ResultOrder() says: "Get the order ticket. Return value: Order ticket if the order is placed.". I have seen in other EAs that it occasionally returns 0 (when placement of the order is still busy) and later returns it via OnTradeTransaction. But in this case MT5 returned a ticket number which turns out to be for the order of another EA on another VPS?!

Please advice what I should change in my code to prevent this in the future.

Documentation on MQL5: Language Basics / Functions / Event Handling Functions
Documentation on MQL5: Language Basics / Functions / Event Handling Functions
  • www.mql5.com
Event Handling Functions - Functions - Language Basics - MQL5 Reference - Reference on algorithmic/automated trading language for MetaTrader 5
Enrique Dangeroux  

I can not comment on the duplicate ticket no's, but this:

2023.01.16 01:00:00.637   Expert: ERROR: Buy ticket #569182975 has been replaced by ticket #569183075

is most likely a flaw in your code logic. The first ticket is older then the new ticket. Also the error message is suspect as i have never encountered ticket numbers being changed (Or "replaced" as the error message suggest) after being issued (MT5) with over 30k trades on live account.

Lorentzos Roussos  
On a first glance it appears the magic numbers are the same (i mean in the orders not in your EAs)
yoriz  

Enrique Dangeroux #:

is most likely a flaw in your code logic.

How is it a flaw in my code? One EA is running in a data-center in Newark, the other EA in a data-center in New York. Both EAs get exact same ticket number back from the CTrade::ResultOrder()?!

Enrique Dangeroux #:

Also the error message is suspect as i have never encountered ticket numbers being changed

The message is merely reporting the old ticket number I got via CTrade::ResultOrder() and the new ticket number I got via the OnTradeTransaction event. I am just as confused as you why an order gets a different number.

yoriz  
Lorentzos Roussos #:
On a first glance it appears the magic numbers are the same (i mean in the orders not in your EAs)

Yes, that was the first thing I double checked. I thought I made a mistake. But they are really different. I have attached a screenshot of the history tab. Magic numbers 30 and 31.

Files:
deals.png  11 kb
Enrique Dangeroux  
yoriz #:

How is it a flaw in my code? One EA is running in a data-center in Newark, the other EA in a data-center in New York. Both EAs get exact same ticket number back from the CTrade::ResultOrder()?!

...


Your logic accounts for a replacement of a ticket  Like i wrote. i never encountered a ticket changed by broker. 

 Besides you have not explained if the tickets are issued on the same account or the same broker, or they are diffrent.

Regardless, for the EA's logic the ticket number should be enough in order to manage the positions and not allow for a trade going rogue.
Lorentzos Roussos  
yoriz #:

Yes, that was the first thing I double checked. I thought I made a mistake. But they are really different. I have attached a screenshot of the history tab. Magic numbers 30 and 31.

Yes , i mean as far as the check OnTransaction is concerned , one of the EAs had both orders reach the 

if (order.OrderType() == ORDER_TYPE_BUY_STOP) {

point , otherwise they would not get past the magic number check.

---edit  , i did not share that correctly ----

One of the EAs in one VPS had the buy ticket set at the opening phase , with one magic number . 

And in the OnTransaction it receives the other ticket (with the other magic number) and gets past the check of this magic number .

How is it getting through if the magic is different ? 

That means behavior of OrderInfo is malfunctioning or the # are the same

yoriz  

Enrique Dangeroux #:

Your logic accounts for a replacement of a ticket  Like i wrote. i never encountered a ticket changed by broker. 

Me neither. But I am glad I did add that sanity check in the code, otherwise I would have never discovered this unusual race-condition.


Enrique Dangeroux #:

Besides you have not explained if the tickets are issued on the same account or the same broker, or they are diffrent.

Yes, both EAs are logged into the same account at the same broker, but running with different magic numbers.


Enrique Dangeroux #:

Your logic accounts for a replacement of a ticket  Like i wrote. i never encountered a ticket changed by broker. 

 Besides you have not explained if the tickets are issued on the same account or the same broker, or they are diffrent.

Regardless, for the EA's logic the ticket number should be enough in order to manage the positions and not allow for a trade going rogue.

Yes, should my EA have the *correct* ticket number, then it would have nicely managed the trade. However, due to the duplicate ticket number both EAs started to manage each others' trades which resulted in the renumbered trade to be left drifting on its own without actively managing a trailing stop. Eventually it hit the fail-safe Stop Loss it always sets immediately when opening the trade. But it is a very wide SL to not be in the way of the actual trading logic.


Am I the "lucky" discoverer of a race-condition bug in the MT5 platform? Is my broker giving out duplicate ticket numbers? What is going on?

yoriz  
Lorentzos Roussos #:

Yes , i mean as far as the check OnTransaction is concerned , one of the EAs had both orders reach the 

point , otherwise they would not get past the magic number check.

---edit  , i did not share that correctly ----

One of the EAs in one VPS had the buy ticket set at the opening phase , with one magic number . 

And in the OnTransaction it receives the other ticket (with the other magic number) and gets past the check of this magic number .

How is it getting through if the magic is different ? 

That means behavior of OrderInfo is malfunctioning or the # are the same

No, I think one of the EAs received its own ticket with its own magic number. The other also, but that one did not log anything because the received back ticket number matched the ticket number it got initially from the CTrade::ResultOrder().


I don't think OrderInfo is malfunctioning, I think CTrade::ResultOrder() is malfunctioning. How can two EAs in two different data-centers receive the same ticket number when they each open a buy stop?

Lorentzos Roussos  
yoriz #:
No, I think one of the EAs received its own ticket with its own magic number. The other also, but that one did not log anything because the received back ticket number matched the ticket number it got initially from the CTrade::ResultOrder().


I don't think OrderInfo is malfunctioning, I think CTrade::ResultOrder() is malfunctioning. How can two EAs in two different data-centers receive the same ticket number when they each open a buy stop?

I see your point yeah , so in other words if the result in one VPS is 

TRADE_RETCODE_DONE_PARTIAL:

then it exits the switch and the buy_ticket becomes the ticket from the other VPS

So then it receives OnTrade transaction for its own proper ticket , it passes the magic number check , and it is different from the ticket it stored earlier

which (if the logs are correct) is the ticket opened by the other VPS

--edit:

So your broker returned the ticket you already had open at first , or , the ResultOrder() is malfunctioning

You can test it by having a test EA open a buy stop (very far obviously) and then request the same exact price on the other VPS and see what ticket and retcode it returns.

Reason: