error message popped up because OnTradeTransaction slower than OnTick function

 

Hi I'm learning how to use OnTradeTransaction on partial close and trailing stop. I'm encounter a problem with how OnTradeTransaction handling a position that is closed due to price hit TP or SL level. I notice that when position is closed due to price hit SL or TP level OnTradeTransaction called after the OnTick function. This create a problem in regards resetting a position ticket variable.

I store position ticket when I open a trade and reset it when all the position volume reach 0. But because OnTradeTransaction function called second after the OnTick function for every function that needs to check if there's an open position will result in false and print an error statement even though it is not an error, just OnTradeTransaction function isn't finish to resetting the position ticket variable.

uint  Stoploss = 100;
uint  TakeProfit = 100;
ulong PositionTicket;

double   InitialVolume;
double   InitialPrice;

uint     PartialCloseCount;
double   PartialCloseVolume;
double   PartialClosePrice;
double   CurrentPositionVolume;

CTrade trade;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
//---
   PartialCloseCount = 0;
//---
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
//---

}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick() {
//---
   OpenPosition();
   PartialClose();
}
//+------------------------------------------------------------------+
void OpenPosition () {
   MqlTick tick;
   SymbolInfoTick(_Symbol, tick);

   if(PositionTicket == 0) {
      if(tick.ask - tick.bid > 20*_Point)
         return;

      trade.Buy(0.04, _Symbol, tick.ask, tick.ask - Stoploss*_Point, tick.ask + TakeProfit*_Point);

      PositionTicket = trade.ResultOrder();
      InitialPrice   = trade.ResultPrice();
      InitialVolume  = trade.ResultVolume();
      //CurrentPositionVolume = InitialVolume;
   }
}

//+------------------------------------------------------------------+
void PartialClose() {
   CPositionInfo position;

   if(PositionTicket == 0)
      return;

   else {
      if(!position.SelectByTicket(PositionTicket)) {
         Print("ERROR - failed to SELECT POSITION with ticket #", PositionTicket);
         return;
      } else {
         if(PartialCloseCount == 0) {
            double PartialCloseSLPrice = position.PriceOpen() - ((position.PriceOpen() - position.StopLoss()) / 2);
            if(iClose(_Symbol, PERIOD_CURRENT, 0) < PartialCloseSLPrice) {
               double newVolume = MathRound((position.Volume() / 2),2);
               trade.PositionClosePartial(PositionTicket, newVolume, 10);

               ////... store partial close parameter
               //PartialCloseVolume = trade.ResultVolume();
               //PartialClosePrice  = trade.ResultPrice();

               PartialCloseCount++;
            }
         }
      }
   }
}
//+------------------------------------------------------------------+
void OnTradeTransaction(
   const MqlTradeTransaction& trans,
   const MqlTradeRequest&     request,
   const MqlTradeResult&      result) {

   CPositionInfo position;

   ENUM_TRADE_TRANSACTION_TYPE trans_type = trans.type;
   switch(trans_type) {

   case TRADE_TRANSACTION_DEAL_ADD:

      switch(trans.deal_type) {

      case DEAL_TYPE_BUY :

         //... when position is closed
         if(trans.deal != trans.position) {
            Print("position close");

            if(trans.volume != InitialVolume) {
               Print("this close is partial close");
               PartialCloseVolume = trans.volume;
               PartialClosePrice = trans.price;
               //... deduct current positino volume with partial close volume
               CurrentPositionVolume -= PartialCloseVolume;
            }
            if(trans.volume == InitialVolume) {
               Print("this close is total position close");
               //... reset current position volume
               CurrentPositionVolume -= trans.volume;
            }

            //Print("partial close volume: ", PartialCloseVolume);
            //Print("Partial close price: ", PartialClosePrice);
            //Print("current volume: ", CurrentPositionVolume);

            if(CurrentPositionVolume == 0) {
               //... reset position ticket
               PositionTicket = 0;
               //... reset partial close count
               PartialCloseCount = 0;
            }
         }

         //... when position open
         if(trans.order == trans.position) {
            //Print("***** Position open on ", trans.symbol, " *****");
            CurrentPositionVolume = InitialVolume;

            Print("position open");
            //Print("initial volume: ", InitialVolume);
            //Print("Initial Price: ", InitialPrice);
         }

         break;


      case DEAL_TYPE_SELL :

         //... when position is close
         if(trans.deal != trans.position) {
            //Print("===== Position close on ", trans.symbol, " =====");
            Print("position close");

            if(trans.volume != InitialVolume) {
               Print("this close is partial close");
               PartialCloseVolume = trans.volume;
               PartialClosePrice = trans.price;
               CurrentPositionVolume -= PartialCloseVolume;
            }

            if(trans.volume == InitialVolume) {
               Print("this close is total position close");
               CurrentPositionVolume -= trans.volume;
            }

            //Print("partial close volume: ", PartialCloseVolume);
            //Print("Partial close price: ", PartialClosePrice);
            //Print("current volume: ", CurrentPositionVolume);

            if(CurrentPositionVolume == 0) {
               PositionTicket = 0;
               PartialCloseCount = 0;
            }

         }

         //... when position open
         if(trans.order == trans.position) {
            //Print("***** Position open on ", trans.symbol, " *****");
            CurrentPositionVolume = InitialVolume;
            Print("position open");
            //Print("initial volume: ", InitialVolume);
            //Print("Initial Price: ", InitialPrice);

         }

         break;
      }
   }
}
//+------------------------------------------------------------------+

And here's what's printed in the journal,

CS 0 14:45:31.728 Trade 2022.01.03 01:01:00   market buy 0.04 GBPUSD sl: 1.35211 tp: 1.35411 (1.35293 / 1.35311 / 1.35293)

CS 0 14:45:31.728 Trades 2022.01.03 01:01:00   deal #2 buy 0.04 GBPUSD at 1.35311 done (based on order #2)

CS 0 14:45:31.729 Trade 2022.01.03 01:01:00   deal performed [#2 buy 0.04 GBPUSD at 1.35311]

CS 0 14:45:31.729 Trade 2022.01.03 01:01:00   order performed buy 0.04 at 1.35311 [#2 buy 0.04 GBPUSD at 1.35311]

CS 0 14:45:31.733 Partial Close Behaviour (GBPUSD,M15) 2022.01.03 01:01:00   CTrade::OrderSend: market buy 0.04 GBPUSD sl: 1.35211 tp: 1.35411 [done at 1.35311]

CS 0 14:45:31.733 Partial Close Behaviour (GBPUSD,M15) 2022.01.03 01:01:00   position open

CS 0 14:45:31.832 Trade 2022.01.03 01:13:40   market sell 0.02 GBPUSD, close #2 (1.35254 / 1.35272 / 1.35254)

CS 0 14:45:31.832 Trades 2022.01.03 01:13:40   deal #3 sell 0.02 GBPUSD at 1.35254 done (based on order #3)

CS 0 14:45:31.832 Trade 2022.01.03 01:13:40   deal performed [#3 sell 0.02 GBPUSD at 1.35254]

CS 0 14:45:31.832 Trade 2022.01.03 01:13:40   order performed sell 0.02 at 1.35254 [#3 sell 0.02 GBPUSD at 1.35254]

CS 0 14:45:31.834 Partial Close Behaviour (GBPUSD,M15) 2022.01.03 01:13:40   CTrade::OrderSend: market sell 0.02 position #2 GBPUSD [done at 1.35254]

CS 0 14:45:31.834 Partial Close Behaviour (GBPUSD,M15) 2022.01.03 01:13:40   position close

CS 0 14:45:31.834 Partial Close Behaviour (GBPUSD,M15) 2022.01.03 01:13:40   this close is partial close

CS 0 14:45:33.006 Trade 2022.01.03 01:47:40   stop loss triggered #2 buy 0.02 GBPUSD 1.35311 sl: 1.35211 tp: 1.35411 [#4 sell 0.02 GBPUSD at 1.35211]

CS 0 14:45:33.006 Trades 2022.01.03 01:47:40   deal #4 sell 0.02 GBPUSD at 1.35211 done (based on order #4)

CS 0 14:45:33.006 Trade 2022.01.03 01:47:40   deal performed [#4 sell 0.02 GBPUSD at 1.35211]

CS 0 14:45:33.006 Trade 2022.01.03 01:47:40   order performed sell 0.02 at 1.35211 [#4 sell 0.02 GBPUSD at 1.35211]

CS 0 14:45:33.008 Partial Close Behaviour (GBPUSD,M15) 2022.01.03 01:47:40   ERROR - failed to SELECT POSITION with ticket #2

CS 0 14:45:33.008 Partial Close Behaviour (GBPUSD,M15) 2022.01.03 01:47:40   position close

CS 0 14:45:33.008 Partial Close Behaviour (GBPUSD,M15) 2022.01.03 01:47:40   this close is partial close

CS 0 14:45:33.011 Trade 2022.01.03 01:47:59   market buy 0.04 GBPUSD sl: 1.35120 tp: 1.35320 (1.35207 / 1.35220 / 1.35207)

CS 0 14:45:33.011 Trades 2022.01.03 01:47:59   deal #5 buy 0.04 GBPUSD at 1.35220 done (based on order #5)

CS 0 14:45:33.011 Trade 2022.01.03 01:47:59   deal performed [#5 buy 0.04 GBPUSD at 1.35220]

CS 0 14:45:33.011 Trade 2022.01.03 01:47:59   order performed buy 0.04 at 1.35220 [#5 buy 0.04 GBPUSD at 1.35220]

CS 0 14:45:33.013 Partial Close Behaviour (GBPUSD,M15) 2022.01.03 01:47:59   CTrade::OrderSend: market buy 0.04 GBPUSD sl: 1.35120 tp: 1.35320 [done at 1.35220]

CS 0 14:45:33.013 Partial Close Behaviour (GBPUSD,M15) 2022.01.03 01:47:59   position open


Looked at this part where the print statement is closed due to stoploss and here's an error message from Partial Close function unable to find position ticket because OnTradeTransaction still not finish resetting the position ticket. Is anyone has any solution for this problem?

 

if administrator see this please move this thread to Expert Advisor. I mistaken this thread to be Expert Advisor

 
Well it seems too simple an answer but you could just find the ticket iterating the running trades and avoid using global variable for it.
 
Yashar Seyyedin #:
Well it seems too simple an answer but you could just find the ticket iterating the running trades and avoid using global variable for it.

I used to do it like this but not used it anymore because I think it is not efficient and redundant. As of now I create a new function at the start of the tick using your method, looped through the position and search for position ticket, if it's return error 4753 then will reset the position ticket.

Reason: