Invalid Stops using my multisymbol Expert

 

Hello everyone,

I'm encountering a peculiar issue with adjusting my Stop Loss in a trailing manner and am hoping someone can shed some light on this for me.

Below is the function I use for trailing the Stop Loss:

void CPM::TrailingStopLoss(string pSymbol,ulong pMagic,int pTSLFixedPoints)
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {

      //Reset of request and result values
      ZeroMemory(request);
      ZeroMemory(result);
      

      ulong positionTicket = PositionGetTicket(i);
      PositionSelectByTicket(positionTicket);

      string posSymbol        = PositionGetString(POSITION_SYMBOL);
      ulong posMagic          = PositionGetInteger(POSITION_MAGIC);
      ulong posType           = PositionGetInteger(POSITION_TYPE);
      double currentStopLoss  = PositionGetDouble(POSITION_SL);
      double tickSize         = SymbolInfoDouble(posSymbol,SYMBOL_TRADE_TICK_SIZE);
      double point            = SymbolInfoDouble(posSymbol,SYMBOL_POINT);

      double newStopLoss;
      long stoplevel = SymbolInfoInteger(posSymbol, SYMBOL_TRADE_STOPS_LEVEL);
     
      if(posSymbol == pSymbol && posMagic == pMagic && posType == POSITION_TYPE_BUY)
        {
         double bidPrice = SymbolInfoDouble(posSymbol,SYMBOL_BID);
         newStopLoss = bidPrice - (pTSLFixedPoints * point);
         newStopLoss = AdjustBelowStopLevel(posSymbol,bidPrice,newStopLoss);
         newStopLoss = round(newStopLoss/tickSize) * tickSize;

         if(newStopLoss > currentStopLoss)
           {
            request.action    = TRADE_ACTION_SLTP;
            request.position  = positionTicket;
            request.comment   = "TSL." + " | " + posSymbol + " | " + string(pMagic);
            request.sl        = newStopLoss;
            request.tp        = PositionGetDouble(POSITION_TP);
           }
        }

      else
         if(posSymbol == pSymbol && posMagic == pMagic && posType == POSITION_TYPE_SELL)
           {
          
            double askPrice = SymbolInfoDouble(posSymbol,SYMBOL_ASK);
            newStopLoss = askPrice + (pTSLFixedPoints * point);
            newStopLoss = AdjustAboveStopLevel(posSymbol,askPrice,newStopLoss);
            newStopLoss = round(newStopLoss/tickSize) * tickSize;
            newStopLoss=NormalizeDouble(newStopLoss,_Digits);
            if(newStopLoss < currentStopLoss)
              {
              
               request.action    = TRADE_ACTION_SLTP;
               request.position  = positionTicket;
               request.comment   = "TSL." + " | " + posSymbol + " | " + string(pMagic);
               request.sl        = newStopLoss;
               request.tp        = PositionGetDouble(POSITION_TP);

              }
           }
      if(request.sl > 0)
        {
         bool sent = OrderSend(request,result);
         if(!sent)
           {
            Print("OrderSend TSL error: ", GetLastError());
            Print("OrderSend succeeded. Result retcode: ", result.retcode, " comment: ", result.comment);
                    
           }
        }
     }
  }

I currently have an open short position with the following details:

  • Opening Price: 0.80571
  • Current Stop Loss: 0.80576

Within the function, I calculate a new Stop Loss value of 0.80671 based on the current ASK price of 0.80571. This places the new Stop Loss 100 points away. The trading symbol in this scenario is AUDUSD.

Despite all parameters appearing correct, an OrderSend call in my backtest returns an "Invalid Stops" error.

Interestingly, the error doesn't occur when running the Expert Advisor on only the AUDUSD pair. The issue arises when running the EA as a multi-symbol strategy on both AUDUSD and EURUSD. Notably, at the time the problem occurs, there's only one trade open—the one I'm attempting to modify.

Any insights or suggestions would be greatly appreciated.

 

Add some extra prints of relevant data and show some log output examples of when it gives the error. Show both the Journal and Experts log.

 

ok I made these both functions to print out a little more: 

void PrintPositionInfo(ulong positionTicket) {
  if(PositionSelectByTicket(positionTicket)) {
    Print("***Position INFO*** ");
    Print("Position Ticket: ", PositionGetInteger(POSITION_TICKET));
    Print("Symbol: ", PositionGetString(POSITION_SYMBOL));
    Print("Type: ", PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY ? "Buy" : "Sell");
    Print("Volume: ", PositionGetDouble(POSITION_VOLUME));
    Print("Open Price: ", PositionGetDouble(POSITION_PRICE_OPEN));
    Print("Stop Loss: ", PositionGetDouble(POSITION_SL));
    Print("Take Profit: ", PositionGetDouble(POSITION_TP));
    Print("Magic Number: ", PositionGetInteger(POSITION_MAGIC));
    // ... und so weiter
  } else {
    Print("Failed to select position by ticket: ", GetLastError());
  }
}
void PrintRequestInfo(MqlTradeRequest &request)
{
 Print("***Request Info***");
 Print("request.sl: ",request.sl);
 Print("request.action: ",request.action);
 Print("request.tp:",request.tp);
 Print("request.position:", request.position);

}

here is what they wrote from the journal , plus the result from the terminal: 

2023.09.03 17:05:40.084 2018.02.01 03:40:00   ***Position INFO*** 
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Position Ticket: 163
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Symbol: EURUSD
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Type: Sell
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Volume: 0.01
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Open Price: 1.2421
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Stop Loss: 1.24311
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Take Profit: 0.0
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Magic Number: 101
2023.09.03 17:05:40.084 2018.02.01 03:40:00   ***Position INFO*** 
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Position Ticket: 162
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Symbol: AUDUSD
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Type: Sell
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Volume: 0.01
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Open Price: 0.80576
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Stop Loss: 0.80679
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Take Profit: 0.0
2023.09.03 17:05:40.084 2018.02.01 03:40:00   Magic Number: 101
2023.09.03 17:05:57.257 2018.02.01 03:40:00   failed modify #162 sell 0.01 AUDUSD sl: 0.80679, tp: 0.00000 -> sl: 0.80665, tp: 0.00000 [Invalid stops]
2023.09.03 17:06:04.134 2018.02.01 03:40:00   ***Request Info***
2023.09.03 17:06:04.134 2018.02.01 03:40:00   request.sl: 0.80665
2023.09.03 17:06:04.134 2018.02.01 03:40:00   request.action: 6
2023.09.03 17:06:04.134 2018.02.01 03:40:00   request.tp:0.0
2023.09.03 17:06:04.134 2018.02.01 03:40:00   request.position:162

the request info is printed out right  after the  Ordersend command ...

is there anything more I can give you ?

 
Filip #: ok I made these both functions to print out a little more: here is what they wrote from the journal , plus the result from the terminal:  is there anything more I can give you ?

You did not output all relevant data, such as current Bid and Ask prices at the time, and Stops Level.

 

Also, for easier readability, print out the actual enumeration mnemonic instead of its value ...

Print( "Type: ", EnumToString( (ENUM_POSITION_TYPE) PositionGetInteger( POSITION_TYPE ) );
Print( "request.action: ", EnumToString( request.action ) );
 
2023.09.03 17:36:19.656 2018.02.01 03:35:00   ***Position INFO*** 
2023.09.03 17:36:19.656 2018.02.01 03:35:00   Position Ticket: 162
2023.09.03 17:36:19.656 2018.02.01 03:35:00   Symbol: AUDUSD
2023.09.03 17:36:19.656 2018.02.01 03:35:00   Type: POSITION_TYPE_SELL
2023.09.03 17:36:19.656 2018.02.01 03:35:00   Volume: 0.01
2023.09.03 17:36:19.656 2018.02.01 03:35:00   Open Price: 0.80576
2023.09.03 17:36:19.656 2018.02.01 03:35:00   Stop Loss: 0.80679
2023.09.03 17:36:19.656 2018.02.01 03:35:00   Take Profit: 0.0
2023.09.03 17:36:19.656 2018.02.01 03:35:00   Magic Number: 101
2023.09.03 17:36:19.656 2018.02.01 03:35:00   current posSymbol:AUDUSD
2023.09.03 17:36:19.656 2018.02.01 03:35:00   Stoplevel:1
2023.09.03 17:36:19.656 2018.02.01 03:35:00   current bidPrice:0.80567
2023.09.03 17:36:19.656 2018.02.01 03:35:00   current askPrice:0.80571
2023.09.03 17:36:19.656 2018.02.01 03:35:00   tickSize:0.00001
2023.09.03 17:36:19.656 2018.02.01 03:35:00   SYMBOL_POINT:0.00001
2023.09.03 17:36:19.656 2018.02.01 03:35:00   ***Request Info***
2023.09.03 17:36:19.656 2018.02.01 03:35:00   request.sl: 0.80671
2023.09.03 17:36:19.656 2018.02.01 03:35:00   request.action: TRADE_ACTION_SLTP
2023.09.03 17:36:19.656 2018.02.01 03:35:00   request.tp:0.0
2023.09.03 17:36:19.656 2018.02.01 03:35:00   request.position:162
2023.09.03 17:36:19.656 2018.02.01 03:35:00   failed modify #162 sell 0.01 AUDUSD sl: 0.80679, tp: 0.00000 -> sl: 0.80671, tp: 0.00000 [Invalid stops]
2023.09.03 17:36:22.079 2018.02.01 03:35:00   OrderSend TSL error: 4756
2023.09.03 17:36:22.531 2018.02.01 03:35:00   OrderSend succeeded. Result retcode: 10016 comment: Invalid stops
ok here it is with enumtostring ;)
 
Filip #: ok here again with the requested infos : 

Your Bid price seems to be the same as the open price. That does not seem to be correct. It would have to be off a bit before the trailing stop would need to be updated, unless only the Ask price changed.

Also, in your original post, your code only checks the Stops Level but not the Freeze Level. You need to check both when modifying stops.

Can you please also show your code for checking (or adjusting) the Stops Level (and Freeze level)?

 

Hi, 

I dont understand your point saying that the bid price is the same like the order open price : 

Open Price: 0.80576

bidPrice:     0.80567

It is different ...;) 

Anyway I did not had any freeze check but the freeze level at least in this moment is 0 , 

but now I built in this code (for sell): 

           if(MathAbs(newStopLoss - askPrice) < stopLevel*point || MathAbs(newStopLoss - askPrice) < freezeLevel*point)
              {
               Print("New SL is within Stop-Level or Freeze-Level. Skipping.");
               Print("current stop distance :",MathAbs(newStopLoss - askPrice)," stop level:",stopLevel);
               Print("current freeze distance :",MathAbs(newStopLoss - askPrice)," freeze level:",freezeLevel);
               continue;
              }

But its never beeing triggered,becuase freeze level is zero and the stoplevel 0.0001 .


the Code for adjusting the correct distance is this: 

double AdjustAboveStopLevel(string pSymbol,double pCurrentPrice,double pPriceToAdjust,int pPointsToAdd = 10)
  {
   double adjustedPrice = pPriceToAdjust;

   double point      = SymbolInfoDouble(pSymbol,SYMBOL_POINT);
   long stopsLevel   = SymbolInfoInteger(pSymbol,SYMBOL_TRADE_STOPS_LEVEL);

   if(stopsLevel > 0)
     {
      double stopsLevelPrice = stopsLevel * point;          //stops level points in price
      stopsLevelPrice = pCurrentPrice + stopsLevelPrice;    //stops price level - distance from bid/ask

      double addPoints = pPointsToAdd * point;              //Points that will be added/subtracted to stops level price to make sure our price covers the distance

      if(adjustedPrice <= stopsLevelPrice + addPoints)
        {
         adjustedPrice = stopsLevelPrice + addPoints;
         Print("Price adjusted above stop level to "+ string(adjustedPrice));
        }
     }

   return adjustedPrice;
  }

so if the distance is illegal, than i add some points ... 

So its still strange the stoplevel distance is )newstoploss - askprice = 0.001000000000000001 and the stopLevel*point = 0.00001 , so my stop distanced is much larger ... why cant I send the modification? 

 

Filip #I dont understand your point saying that the bid price is the same like the order open price : 

Open Price: 0.80576

bidPrice:     0.80567

It is different ...;)

My apologies. I misread the values!
 

Filip #

Anyway I did not had any freeze check but the freeze level at least in this moment is 0 , 

but now I built in this code (for sell): 

But its never beeing triggered,becuase freeze level is zero and the stoplevel 0.0001 .

the Code for adjusting the correct distance is this: 

so if the distance is illegal, than i add some points ... 

So its still strange the stoplevel distance is )newstoploss - askprice = 0.001000000000000001 and the stopLevel*point = 0.00001 , so my stop distanced is much larger ... why cant I send the modification? 

It is somewhat difficult to just look at someone else's code snippets and just spot the problem, especially when you have a different logical approach to my own thinking.

Usually all I do is the set the stop size (not the stop price) to the maximum value of:

  • my calculated stop size,
  • the Stops Level,
  • the Freeze Level.

It is much easier logic and only has a few lines of code.

Then I calculate the stop price from the current quoted price. It just seems more logical and simpler to me that way instead of having several "if" checks.

 

yes this might be... but I dont think that this is here the problem. As i sayed before: If I run the expert just with one symbol, it does not produce such a problem. 

In my testcase I run it with AUDUSD AND EURUSD, is there anything which can influence the positions by a position in the other symbol - or maybe by previous events? 

Reason: