OnTradeTransaction Event is triggered 4 times when closing one position

Joerg Hartgen
1306
Joerg Hartgen  

Hi there,

this code is triggered 4 times when I'm closing one position.

It's important for me to do (// do something) in the following code only one time. But how?


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

   // Select Deals from History
   datetime to = TimeCurrent();
   datetime from = to - PeriodSeconds(PERIOD_M5); // check deals for the last 5 minutes
   
   HistorySelect(from, to);
   int deals_total = HistoryDealsTotal();
   
   if(deals_total < 1){
      return;  
   }

newest_deal_ticket = HistoryDealGetTicket(deals_total - 1);

ulong deal_entry            = HistoryDealGetInteger(newest_deal_ticket, DEAL_ENTRY);
ulong deal_reason          = HistoryDealGetInteger(newest_deal_ticket, DEAL_REASON);
ulong deal_type            = HistoryDealGetInteger(newest_deal_ticket, DEAL_TYPE);

if((deal_entry == DEAL_ENTRY_OUT) && (deal_reason == DEAL_REASON_EXPERT) && ((deal_type == DEAL_TYPE_BUY ) || (deal_type == DEAL_TYPE_SELL)) ){
// do something
}

}
Alain Verleyen
41911
Alain Verleyen  
Of course it is. Read the documentation, some articles about transactions, and fix your code.
Vladimir Karputov
Moderator
257730
Vladimir Karputov  
Jorg1:

Hi there,

this code is triggered 4 times when I'm closing one position.

It's important for me to do (// do something) in the following code only one time. But how?


Пример:

//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans,
                        const MqlTradeRequest &request,
                        const MqlTradeResult &result)
  {
//--- get transaction type as enumeration value
   ENUM_TRADE_TRANSACTION_TYPE type=trans.type;
//--- if transaction is result of addition of the transaction in history
   if(type==TRADE_TRANSACTION_DEAL_ADD)
     {
      if(HistoryDealSelect(trans.deal))
         m_deal.Ticket(trans.deal);
      else
         return;
      if(m_deal.Symbol()==m_symbol.Name() && m_deal.Magic()==InpMagic)
        {
         if(m_deal.DealType()==DEAL_TYPE_BUY || m_deal.DealType()==DEAL_TYPE_SELL)
           {
            if(m_deal.Entry()==DEAL_ENTRY_IN || m_deal.Entry()==DEAL_ENTRY_INOUT)
               m_last_deal_in=iTime(m_symbol.Name(),Period(),0);
Joerg Hartgen
1306
Joerg Hartgen  

@Vladimir Karputov: Thanks a lot, but your solution needs special includes / classes to work:

#include <Trade\SymbolInfo.mqh>
#include <Trade\DealInfo.mqh>
//---
CSymbolInfo    m_symbol;                     // object of CSymbolInfo class
CDealInfo      m_deal;                       // object of CDealInfo class

@Alain Verleyen: You are not so friendly to me :-) But thank you, too.


I prefer the following solution:

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


   // What kind is the new transaction?
   // We do only track transactions that add something to the history
   if(trans.type != TRADE_TRANSACTION_DEAL_ADD){
      return;
   }
   
   // Read ticket of the new deal and select it
   ulong newest_deal_ticket = trans.deal;
   HistoryDealSelect(newest_deal_ticket);
   
   // Read deal properties
   // List of Deal Properties: https://www.mql5.com/en/docs/constants/tradingconstants/dealproperties#enum_deal_property_integer
   long position_ID           = HistoryDealGetInteger(newest_deal_ticket, DEAL_POSITION_ID);
   long order_ticket          = HistoryDealGetInteger(newest_deal_ticket, DEAL_ORDER);
   long deal_magic            = HistoryDealGetInteger(newest_deal_ticket, DEAL_MAGIC);
   int int_deal_magic         = (int)deal_magic;
   datetime transaction_time  = (datetime)HistoryDealGetInteger(newest_deal_ticket,DEAL_TIME);
   ulong deal_reason          = HistoryDealGetInteger(newest_deal_ticket, DEAL_REASON);
   ulong deal_type            = HistoryDealGetInteger(newest_deal_ticket, DEAL_TYPE);
   ulong deal_entry            = HistoryDealGetInteger(newest_deal_ticket, DEAL_ENTRY);
   double deal_price          = HistoryDealGetDouble(newest_deal_ticket, DEAL_PRICE);
   double deal_profit         = HistoryDealGetDouble(newest_deal_ticket, DEAL_PROFIT);
   string symbol              = HistoryDealGetString(newest_deal_ticket, DEAL_SYMBOL);
   double volume              = HistoryDealGetDouble(newest_deal_ticket, DEAL_VOLUME);
   double commission          = HistoryDealGetDouble(newest_deal_ticket, DEAL_COMMISSION);
   double swap                = HistoryDealGetDouble(newest_deal_ticket, DEAL_SWAP);


// Examples
/*
   if((deal_entry == DEAL_ENTRY_IN)) {
      printf ("in");
   }
   if((deal_entry == DEAL_ENTRY_OUT)) {
      printf ("out");
   }
   if( (deal_reason == DEAL_REASON_EXPERT) ) {
      printf ("Reason Expert");
   }
   if( (deal_reason == DEAL_REASON_SL) ) {
      printf ("Reason SL");
   }
*/
   
   if((deal_entry == DEAL_ENTRY_IN) && ((deal_type == DEAL_TYPE_BUY ) || (deal_type == DEAL_TYPE_SELL)) ){
      // do something
   }


   if((deal_entry == DEAL_ENTRY_OUT) && (deal_reason == DEAL_REASON_EXPERT) && ((deal_type == DEAL_TYPE_BUY ) || (deal_type == DEAL_TYPE_SELL)) ){
      // do something
   }
   

   if( (deal_reason == DEAL_REASON_SL) ) {
      // do something
   }
}
Vladimir Karputov
Moderator
257730
Vladimir Karputov  
Jorg1 :

@Vladimir Karputov : Thanks a lot, but your solution needs special includes / classes to work:

 #include  <Trade\SymbolInfo.mqh>
 #include  <Trade\DealInfo.mqh>
 //--- 
CSymbolInfo    m_symbol;                     // object of CSymbolInfo class 
CDealInfo      m_deal;                       // object of CDealInfo class 

These are no "non-special classes." These are trading classes from the Standard Library. The standard library comes with a terminal.

Using the Standard Library greatly reduces the number of lines of code. Using trading classes allows you to write very concise code.

Joerg Hartgen
1306
Joerg Hartgen  

@Vladimir Karputov: OK, I understand.

I've got another problem concerning OnTradeTransaction. I got stuck with it since hours, so I want to ask you for help:

I'm opening several positions in the same symbol at the same time and I identify them with different magic numbers. I call them "trade types". For example there is a trade type "30" and a trade type "130"

Concerning OnTradeTransaction I found out:

1. If the transaction represents the opening of a position:

m_deal_magic = 0;

if((deal_entry == DEAL_ENTRY_IN) && (deal_reason == DEAL_REASON_EXPERT) && ((deal_type == DEAL_TYPE_BUY ) || (deal_type == DEAL_TYPE_SELL)) ){ 
        m_deal_magic          = m_deal.Magic(); // Right
}

then m_deal_magic is right.

But

2. If the transaction represents the closing of a position:

m_deal_magic = 0;

if((deal_entry == DEAL_ENTRY_OUT) && (deal_reason == DEAL_REASON_EXPERT) && ((deal_type == DEAL_TYPE_BUY ) || (deal_type == DEAL_TYPE_SELL)) ){
        m_deal_magic          = m_deal.Magic(); // Wrong
}

then m_deal_magic will be wrong. In this case the value of m_deal_magic will be the value of m_deal_magic of the last opened position.

I found this out by analyzing the transactions that belong to the same DEAL_POSITION_ID.


The problem is the same if I don't use the DealInfo library.

Can you please help me how to find out the correct magic number of the transaction that represents a deal that closes a position?

Vladimir Karputov
Moderator
257730
Vladimir Karputov  
Jorg1 :


Show your code - how do you close a position?

Joerg Hartgen
1306
Joerg Hartgen  

In this case I'm closing the positions "at market":

            // Close the position
            m_position.SelectByTicket (TicketNo);
           
            if(m_trade.PositionClose(m_position.Ticket())) {
            }
            else {
                Print("Close position trade type ", PositionMagic, " error: ",GetLastError());
            }
         }
Vladimir Karputov
Moderator
257730
Vladimir Karputov  
Jorg1 :

In this case I'm closing the positions "at market":

If you use SEVERAL strategies - why don't you change the MAgic Number of the m_trade object before closing ???

Joerg Hartgen
1306
Joerg Hartgen  

This would work if I could set a magic number that is specific for a DEAL_POSITION_ID. But this is not possible.

When I close a position there could be an SL or TP on the trade server in between. Then the magic number will be wrong.

I also use TP to close positions.

Vladimir Karputov
Moderator
257730
Vladimir Karputov  
Jorg1 :

This would work if I could set a magic number that is specific for a  DEAL_POSITION_ID . But this is not possible.

When I close a position there could be an SL or TP on the trade server in between. Then the magic number will be wrong.

I also use TP to close positions.

You have two strategies. Strategy # 0 has Magic '1556', and strategy # 1 has Magic '7548'.

If you want to close a position that was opened according to Strategy # 0 - you must assign the object m_trade Magic '1556'

m_trade.SetExpertMagicNumber(1556);

, if you want to close the position that was opened according to Strategy # 1 - you must assign the object m_trade Magic  ' 7548 '

m_trade.SetExpertMagicNumber(7548);

Did you do it? No, you didn’t do this.