CDealInfo -> Magic() not returning magic number on profitable deal

 

Greets,

This has been working for a while now, but today I noticed it's not working as expected. Not sure what's changed (maybe nothing has changed and this has never worked).


I basically want to trigger some code when a deal is in profit/loss. It works when the deal is in loss (ie, hits the SL), but not when in profit.

Perhaps I'm not understanding:

if (m_deal.Entry() == DEAL_ENTRY_OUT)

...which works when a position hits the SL, but not when I want to programmatically trigger a TP.


Here's the code:


void OnTradeTransaction(
   const MqlTradeTransaction&    trans,
   const MqlTradeRequest&        request,
   const MqlTradeResult&         result
   ) {
   
   CDealInfo      m_deal; 

   if(trans.type == TRADE_TRANSACTION_DEAL_ADD) 
   {
      ResetLastError();
      if (HistoryDealSelect(trans.deal))
         m_deal.Ticket(trans.deal);
      else
         return;

      // check if last deal was in profit
      if (m_deal.DealType() == DEAL_TYPE_BUY || m_deal.DealType() == DEAL_TYPE_SELL) 
      {
         if (m_deal.Entry() == DEAL_ENTRY_OUT)
         {
            if (m_deal.Profit() < 0 && m_deal.Magic() == EAMagic) 
            {
               // this section is triggered correctly. m_deal.Magic() always returns a value so the if() succeeds.
            }
            else if (m_deal.Profit() > 0 && m_deal.Magic() == EAMagic) 
            {
                // this is never triggered. I stepped through the code using the debugger and m_deal.Magic() is always returning 0.
            }
         }
      }
   }
}


I'd appreciate any pointers on what I'm missing.


Thanks

 
fxsaber #:
Thanks for the comment.

What does that mean though? If an EA has created a position via an IN deal, then surely the corresponding OUT deal (when the same EA programmatically closes it) will have the same magic?

Update: one of the few times chatgpt has turned out to be useful and saved time:

*** Why in an mql5 ea, when i create an IN deal with a magic number, the same position when later closed has a zero magic number:

In MQL5, the "magic number" is primarily associated with orders rather than positions. The confusion often arises because of the difference between orders, deals, and positions:

  • **Order**: An instruction to execute a trade (e.g., buy or sell).
  • **Deal**: The result of executing an order, either opening or closing a position.
  • **Position**: The current open trade resulting from one or more deals.

Here's the detailed breakdown of how magic numbers work and why you might see a zero magic number on closing deals:

### Orders and Magic Numbers

When you create an order (e.g., to open a buy position), you assign a magic number to it. This helps identify the order as belonging to a particular EA or strategy.

### Deals and Magic Numbers

A deal is created when an order is executed. The deal inherits the magic number from the order that triggered it. However, when examining closed positions, the deal itself does not explicitly store the magic number. Instead, positions are aggregated trades, and the magic number is not directly associated with the position object.

### Positions and Magic Numbers

Positions in MQL5 are aggregates of one or more deals. When you look at the position directly, it doesn’t have a magic number associated with it because the position is a net result of multiple deals.

### Closing Deals

When a position is closed, the resulting deal does not carry the magic number in the traditional sense you might expect. Instead, the magic number is related to the orders that led to the creation of that position. Hence, when you examine closed positions or deals directly in the trading history, the magic number might show up as zero because the terminal shows magic numbers associated with orders rather than positions.

### Checking Orders and Deals

To track the magic number through the lifecycle of a trade, you need to focus on the orders and their corresponding deals. Here’s how you can check and ensure the magic number is set and tracked correctly:

1. **Create Order with Magic Number**:

// Setting the magic number for an order
   int magicNumber = 123456;
   double lotSize = 0.1;
   trade.SetExpertMagicNumber(magicNumber);
   trade.Buy(lotSize, _Symbol);



2. **Check Orders and Deals**:
   You need to query orders and deals separately. Here’s an example to list orders and their magic numbers:
           
 
   void PrintOrdersAndDeals()
   {
      for(int i = OrdersHistoryTotal() - 1; i >= 0; i--)
      {
         if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
         {
            if(OrderMagicNumber() == magicNumber)
            {
               Print("Order #", OrderTicket(), ": Magic Number = ", OrderMagicNumber());
            }
         }
      }

      for(int i = DealsTotal() - 1; i >= 0; i--)
      {
         if(DealSelect(i))
         {
            if(DealMagic() == magicNumber)
            {
               Print("Deal #", DealTicket(), ": Magic Number = ", DealMagic());
            }
         }
      }
   }
   


### Why You See Zero

The primary reason you might see a zero magic number on a closed position is that when querying positions, the magic number attribute isn't directly tied to the position itself in the history context. Instead, it's better to trace orders and deals:


  • **Orders**: Check the magic number associated with orders to ensure they are set correctly.
  • **Orders**: Check the magic number associated with orders to ensure they are set correctly.
  • **Deals**: Check the deals resulting from these orders to confirm the magic number is propagated.


By understanding this distinction and tracking orders and deals instead of positions, you can accurately monitor and verify the magic numbers throughout the trading lifecycle in your EA.

 

Found the reason why some deals and orders were returning zero for profit.


For the EA I had the following:

#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>

CTrade trade;
CPositionInfo position;

// ... and later in the code I was calling the following function which closed trades when in profit:
closeProfitablePositions();
// ...

void closeProfitablePositions() {
    CPositionInfo p;
    CTrade t;

    for (int i = PositionsTotal() - 1; i >= 0; i--) {
        if (p.SelectByIndex(i) && p.Profit() > 0) {
            ulong ticket = p.Ticket();
            
            if (!t.PositionClose(ticket)) {
                Print("Failed to close position with ticket: ", ticket, " Error: ", t.ResultRetcode(), " - ", t.ResultRetcodeDescription());
            }
        }
    }
}


This resulted in a new CPositionInfo object being created with a zero magic number.


Solution was to use the parent CPositionInfo/CTrade objects:

// ...
closeProfitablePositions(position, trade);
// ...

void closeProfitablePositions(CPositionInfo &p, CTrade &t) {...}