Issue with Stoploss modification (Trailing Stop) in mql5. Error code 4756, retcode 10013

 

Hi,

I have written a Trailing Stop function but I get the error code 4756 and return code 10013 during test. The code below is just for the BUY orders for simplicity (same applies for SELL orders). I call the function from the OnTick() when there are some conditions meet.

void TS_pips()
   {
   MqlTradeRequest request = {0};
   MqlTradeResult  result = {0};
   
   for(int cnt=PositionsTotal(); cnt>=0; cnt--)
      {
      string position_symbol = PositionGetSymbol(cnt);
      ulong position_ticket = PositionGetTicket(POSITION_TICKET);
      long magic = PositionGetInteger(POSITION_MAGIC);
      ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
      double open_price = PositionGetDouble(POSITION_PRICE_OPEN);
      double sl = PositionGetDouble(POSITION_SL);
      double tp = PositionGetDouble(POSITION_TP);

      if(type==POSITION_TYPE_BUY && position_symbol==_Symbol && magic==magic_number)
         {
         if((Bid-open_price)>TrailingStop*vPoint)
            {
            if(sl<(Bid-TrailingStop*vPoint))
               {

               ZeroMemory(request);
               ZeroMemory(result);

               double new_sl = Bid-TrailingStop*vPoint;
               Print("current price= ",Bid," / Open Price=",open_price," / current SL= ",sl," / New SL= ",new_sl);
                              
               request.action = TRADE_ACTION_SLTP;
               request.position = position_ticket;
               request.symbol = position_symbol;
               request.tp = tp;
               request.magic=magic;
               
               if(new_sl>request.sl)
                  {
                  request.sl=new_sl;
                  }
               
               PrintFormat("Modify ticket #%I64d %s %s",position_ticket,position_symbol,EnumToString(type));
               
               if(!OrderSend(request,result))
                  {
                  PrintFormat("OrderSend error %d",GetLastError());
                  }
                  
               PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
               return;
               }
            }
         }
      }
   }
          


The output in the journal tab shows no reason for not executing the request (see a sample of the output below). The first deal #2 is opened (it surprises me that it doesn't start at #1, should it?). Then, it gets some data regarding the prices (current, open, and stop loss levels). These prices are reasonable and shouldn't prevent the changes for moving the SL at the opening price: current price is higher than opening price, current SL is lower than the new_SL and the new_SL is lower than current price. You can see that there are a couple of attempts in the screenshot, but in fact it keeps trying until the order is closed by Take Profit or Stop Loss. The same symptoms happens for the consecutive orders.

I have already checked in the forum and tried several changes but so far I have not succeed in finding the problem, I get the same error codes. Any ideas on how to solve this problem?

Every little help would be much appreciated.

Thanks,

Elio

 
Elio Pajares:

Hi,

I have written a Trailing Stop function but I get the error code 4756 and return code 10013 during test. The code below is just for the BUY orders for simplicity (same applies for SELL orders). I call the function from the OnTick() when there are some conditions meet.


The output in the journal tab shows no reason for not executing the request (see a sample of the output below). The first deal #2 is opened (it surprises me that it doesn't start at #1, should it?). Then, it gets some data regarding the prices (current, open, and stop loss levels). These prices are reasonable and shouldn't prevent the changes for moving the SL at the opening price: current price is higher than opening price, current SL is lower than the new_SL and the new_SL is lower than current price. You can see that there are a couple of attempts in the screenshot, but in fact it keeps trying until the order is closed by Take Profit or Stop Loss. The same symptoms happens for the consecutive orders.

I have already checked in the forum and tried several changes but so far I have not succeed in finding the problem, I get the same error codes. Any ideas on how to solve this problem?

Every little help would be much appreciated.

Thanks,

Elio

As you get invalid request, I'd look first at your symbol stop level. Part of the SymbolInfoInteger().
 

Thanks, just checked it: Stoplevel is 0. See the output including stoplevel and verification of 'Bid-new_SL' that the trailing stop is 15 pips in this case.

The problem still persists, any ideas?

 
               if(new_sl>request.sl)
                  {
                  request.sl=new_sl;
                  }

request.sl wasn't defined, and maybe you'll need to return if that' statement is false?

replace that by the position stoploss.

and as a better error finding practice,

               Print("current price= ",Bid," / Open Price=",open_price," / current SL= ",sl," / New SL= ",new_sl);

that line should be closer to your OrderSend(), once your request is fully filled, and make sure the values in there are the actual values you send in, not left to if() functions to get it right

Documentation on MQL5: Constants, Enumerations and Structures / Named Constants / Predefined Macro Substitutions
Documentation on MQL5: Constants, Enumerations and Structures / Named Constants / Predefined Macro Substitutions
  • www.mql5.com
//| Expert initialization function                                   | //| Expert deinitialization function                                 | //| Expert tick function                                             | //| test1                                                            |...
 

Thank you. I have simplified the code by removing the condition about the SL (to ensure this is not causing any problem, but it shouldn't) and added the line

request.sl= new_sl;

Also placed the print output closer to OrderSend(), just to be sure that the values are the right ones. Now the code looks like this:


void TS_pips()
   {
   MqlTradeRequest request = {0};
   MqlTradeResult  result = {0};
   
   for(int cnt=PositionsTotal(); cnt>=0; cnt--)
      {
      string position_symbol = PositionGetSymbol(cnt);
      ulong position_ticket = PositionGetTicket(POSITION_TICKET);
      long magic = PositionGetInteger(POSITION_MAGIC);
      ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
      double open_price = PositionGetDouble(POSITION_PRICE_OPEN);
      double sl = PositionGetDouble(POSITION_SL);
      double tp = PositionGetDouble(POSITION_TP);

      if(type==POSITION_TYPE_BUY && position_symbol==_Symbol && magic==magic_number)
         {
         if((Bid-open_price)>TrailingStop*vPoint)
            {
            if(sl<(Bid-TrailingStop*vPoint))
               {

               ZeroMemory(request);
               ZeroMemory(result);

               double new_sl = Bid-TrailingStop*vPoint;
                              
               request.action = TRADE_ACTION_SLTP;
               request.position = position_ticket;
               request.symbol = position_symbol;
               request.tp = tp;
               request.magic=magic;
               request.sl= new_sl;
               
               Print("current price= ",Bid," / Open Price=",open_price," / current SL= ",sl," / New SL= ",request.sl);
               PrintFormat("Modify ticket #%I64d %s %s",position_ticket,position_symbol,EnumToString(type));
               
               if(!OrderSend(request,result))
                  {
                  PrintFormat("OrderSend error %d",GetLastError());
                  }
                  
               PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
               return;
               }
            }
         }
      }
   }

But still the same problem and same error codes. The values shown in Print() and PrintFormat() look ok. I don't get why this simple code doesn't work.

 
I looked at all that a bit to fast.
Your sl isn't normalized. As we can see by the amount of decimals in the log.
You have to normalize it to tick size.
 

Thanks La_patates, I already tried to normalize that value in one of the previous attempts. As you can see in previous outputs, the new calculated stoploss price already has 5 decimal digits. For some reason, the calculated value of 'Bid-new_SL' gives a value of 0.00150000XXXXXX, whereas it should be 0.0015, it is a matter of accuracy.

Just in case, I checked the output again and normalized the value. The error is still the same. This is the output I get now:

The 'New SL' is calculated and normalized as:

double new_sl = NormalizeDouble(Bid-TrailingStop*vPoint,_Digits);
 
1. Make sure you normalize to tick size and not digits, they can be different.

2. You're not getting the right position number. You are trying to change #1 but your position is #2 try PositionGetTicket(cnt) instead. The documentation states this function requires position index.

 3. You should start your loop at PositionsTotal -1
 

I tried to isolate where the real issue could come from: invalid prices (wrong price levels, normzalition,...) or position selection.

Few more checks show that the problem is really in the selection of the position. All the other refinements proposed indeed make the code more robust, but no changes to the values I was already calculating as in the first post. Much appreciated anyway!

I have forced position_ticket to be '2', and then the changes in SL are done properly, no errors at all. So, when 'position_ticket=2' match the deal 2, the it works. However, the use of PositionGetTicket(cnt) in order to make use of the loop leads to selecting ticket #1 always, along the whole backtest.

There is just one position open, so 'cnt' is 0 and PositionGetTicket(cnt) returns '1' as you can see in the screenshot underneath.

I am a bit puzzled at this point, because the positions seems to be selected correctly along the backtest (I can get details of each of them, like prices, SL/TP levels, etc) but for some reason the ticket numbering is what is giving the problem. I have copied the output of both situations for reference.

The code looks like this now:

void TS_pips()
   {
   MqlTradeRequest request = {0};
   MqlTradeResult  result = {0};
   
   for(int cnt=PositionsTotal()-1; cnt>=0; cnt--)
      {
      ulong position_ticket=PositionGetTicket(cnt);
      //ulong position_ticket = 2;
      string position_symbol = PositionGetString(POSITION_SYMBOL);
      ulong magic = PositionGetInteger(POSITION_MAGIC);
      ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
      double open_price = PositionGetDouble(POSITION_PRICE_OPEN);
      double sl = PositionGetDouble(POSITION_SL);
      double tp = PositionGetDouble(POSITION_TP);     
      double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);

      if(type==POSITION_TYPE_BUY && position_symbol==_Symbol && magic==magic_number)
         {
         if((Bid-open_price)>TrailingStop*vPoint)
            {
            if(sl<(Bid-TrailingStop*vPoint))
               {  
               Print("Positionticket is: ",position_ticket);
               
               double new_sl = round((Bid-TrailingStop*vPoint)/tickSize)*tickSize;

               ZeroMemory(request);
               ZeroMemory(result);
                              
               request.action = TRADE_ACTION_SLTP;
               request.position = position_ticket;
               request.symbol = position_symbol;
               request.tp = tp;
               request.magic=magic;
               request.sl = new_sl;
               
               Print("current price= ",Bid," / Open Price=",open_price," / current SL= ",sl," / New SL= ",request.sl);
               PrintFormat("Modify ticket #%I64d %s %s",request.position,request.symbol,EnumToString(type));
               
               if(!OrderSend(request,result))
                  {
                  PrintFormat("OrderSend error %d",GetLastError());
                  }
                  
               PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
               return;
               }
            }
         }    
      }
   }

Output using 'PositionGetTicket(cnt)':

Output using forcing 'position_ticket = 2', you can check it is trailing correctly at every price move:


 

Well, after quite some investigation, there seems to be some sort of conflict with a library I was using for converting mql4/mql5 functions and the 'PositionGetTicket()' function.

I will make some extra investigation, but for the moment the code in post #8 works well and can be used by whoever requires a Trailing Stop function. It has several refinements suggested by La_patates (contribution much appreciated!). Most probably it can still be improved to make it even more robust, but it is a good basis for those starting.

 
Elio Pajares:

Well, after quite some investigation, there seems to be some sort of conflict with a library I was using for converting mql4/mql5 functions and the 'PositionGetTicket()' function.

I will make some extra investigation, but for the moment the code in post #8 works well and can be used by whoever requires a Trailing Stop function. It has several refinements suggested by La_patates (contribution much appreciated!). Most probably it can still be improved to make it even more robust, but it is a good basis for those starting.

Glad you got it sorted out! I was running low on ideas as there doesn't seem to be anymore issues preventing operations in there!