why do I have this Invalid Stops?

 
2024.08.16 04:07:13.842 Core 01 2024.03.14 23:47:38   failed instant sell 0.02 EURTRY at 34.89920 sl: 35.89920 tp: 33.89920 [Invalid stops]
 
Invalid stops is not only about the distance but also about the validity of the prices, did you normalize your SL and TP. Is your open price valid (market bid) ?
 
Alain Verleyen #:
Invalid stops is not only about the distance but also about the validity of the prices, did you normalize your SL and TP. Is your open price valid (market bid) ?

Can you please check this if its 0k? I've tried lots of combinations, and all give the same errors.

2024.08.16 20:04:12.713 Core 01 2024.07.11 00:03:00   failed modify #127 buy 0.01 EURJPY sl: 173.331, tp: 177.706 -> sl: 175.954, tp: 177.706 [Invalid stops]
2024.08.16 20:04:12.713 Core 01 2024.07.11 00:03:00   failed modify #121 sell 0.1 XPDUSD sl: 1110.127, tp: 897.527 -> sl: 980.209, tp: 890.453 [Invalid stops]
2024.08.16 20:04:12.713 Core 01 2024.07.12 00:03:00   failed modify #126 buy 0.01 EURTRY sl: 35.12776, tp: 36.92928 -> sl: 36.19744, tp: 36.92928 [Invalid stops]
            double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
            double currentSL = PositionGetDouble(POSITION_SL);
            double currentTP = PositionGetDouble(POSITION_TP);
            ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
            
            double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
            double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
            
            double currentPrice = (posType == POSITION_TYPE_BUY) ? bid : ask; // Corrected: use ask for buy positions
            
            double newSL = currentSL;
            double newTP = currentTP;
            bool modifyPosition = false;
            
            if (posType == POSITION_TYPE_BUY)
            {
                double potentialSL = NormalizeDouble(currentPrice - safeMinDistance, digits);
                double potentialTP = NormalizeDouble(currentPrice + safeMinDistance, digits);
                if (potentialSL > currentSL && potentialSL < bid)
                {
                    newSL = potentialSL;
                    modifyPosition = true;
                }
                if (potentialTP > currentTP)
                {
                    newTP = potentialTP;
                    modifyPosition = true;
                }
            }
            else if (posType == POSITION_TYPE_SELL)
            {
                double potentialSL = NormalizeDouble(currentPrice + safeMinDistance, digits);
                double potentialTP = NormalizeDouble(currentPrice - safeMinDistance, digits);
                if (potentialSL < currentSL && potentialSL > ask)
                {
                    newSL = potentialSL;
                    modifyPosition = true;
                }
                if (potentialTP < currentTP)
                {
                    newTP = potentialTP;
                    modifyPosition = true;
                }
            }
            
            if (modifyPosition)
            {
                // Ensure the new SL and TP are valid
                if ((posType == POSITION_TYPE_BUY && newSL < bid && newTP > ask) || 
                    (posType == POSITION_TYPE_SELL && newSL > ask && newTP < bid))
                {
                    if (trade.PositionModify(ticket, newSL, newTP))
                    {
                        g_positionInfo[posIndex].lastTrailingUpdate = currentTime;
                        Print("Trailing stop/profit updated. Ticket: ", ticket, 
                              ", New SL: ", DoubleToString(newSL, digits),
                              ", New TP: ", DoubleToString(newTP, digits));
                    }
                    else
                    {
                        int errorCode = GetLastError();
                        Print("Failed to update trailing stop/profit. Ticket: ", ticket, 
                              ", Error: ", errorCode, " - ", GetErrorDescription(errorCode));
                    }
                }
            }
 
You need to make sure that your position is in profit before you attempt to modify the stop to be close to the entry price. You could retrieve POSITION_PRICE_OPEN and make sure that the bid is above the entry price (in the condition) on a buy, and of course then you need to make sure the ask is at least some distance below the entry price on a sell position. It's a good idea to retrieve the spread value as well. You have "openPrice" variable defined, but you're not using it in the conditions 
 

try that (edited for breakeven example - since I don't know your specification)

        double safeMinDistance = 20*_Point;
        
        bool modifyPosition = false;
 
            if (posType == POSITION_TYPE_BUY && bid > (openPrice + safeMinDistance) && !modifyPosition)
            {
                double potentialSL = NormalizeDouble(openPrice, digits);
              
                newSL = potentialSL;
                        
                double potentialTP = NormalizeDouble(currentPrice + safeMinDistance), digits);
                if (potentialTP > currentTP)
                {
                    newTP = potentialTP;
                }
                
                 modifyPosition = true;                 
            }
            else if (posType == POSITION_TYPE_SELL && ask < (openPrice -  safeMinDistance) && !modifyPosition)
            {
                double potentialSL = NormalizeDouble(openPrice, digits);             
                
                newSL = potentialSL;
                
                
                double potentialTP = NormalizeDouble(currentPrice - safeMinDistance, digits);
                if (potentialTP < currentTP)
                {
                    newTP = potentialTP;
                }
                
                 modifyPosition = true;         
            }


There's no point using the spread at this point after you already have an open price, because the position was already opened with the spread - you can creatively add somewhere, anyway, it won't fix an issue. The spread (in points) would be better to use for when you're placing the position; buy at (ask - spread) and sell at (bid + spread).


edit -

You may run into a new problem now, for example, how do you reset modifyPosition back to false in an appropriate way (not every tick)? 

I had a problem with invalid stops before, and you can see my solution in this thread:

https://www.mql5.com/en/forum/467427

PosititionModify keeps trying to modify the same position over and over again
PosititionModify keeps trying to modify the same position over and over again
  • 2024.05.23
  • Conor Mcnamara
  • www.mql5.com
Looking at the journal, you can see it is trying to modify the same position with the same SL and TP every tick: 2024.05.23 13:15:36.661 2024.05...
 
Conor Mcnamara #:
You need to make sure that your position is in profit before you attempt to modify the stop to be close to the entry price. You could retrieve POSITION_PRICE_OPEN and make sure that the bid is above the entry price (in the condition) on a buy, and of course then you need to make sure the ask is at least some distance below the entry price on a sell position. It's a good idea to retrieve the spread value as well. You have "openPrice" variable defined, but you're not using it in the conditions 

Hi, thanks for responding. I cant see the error ... what am I missing?

            double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
            double currentSL = PositionGetDouble(POSITION_SL);
            double currentTP = PositionGetDouble(POSITION_TP);
            ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
            
            double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
            double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
            
            double currentPrice = (posType == POSITION_TYPE_BUY) ? bid : ask;
            
            double newSL = currentSL;
            double newTP = currentTP;
            bool modifyPosition = false;
            
            // Ensure the position is in profit before modifying
            if (posType == POSITION_TYPE_BUY && bid > openPrice + safeMinDistance)
            {
                double potentialSL = NormalizeDouble(currentPrice - safeMinDistance - spread, digits);
                if (potentialSL > currentSL && potentialSL > openPrice)
                {
                    newSL = potentialSL;
                    modifyPosition = true;
                }
                
                double potentialTP = NormalizeDouble(currentPrice + safeMinDistance, digits);
                if (potentialTP > currentTP)
                {
                    newTP = potentialTP;
                    modifyPosition = true;
                }
            }
            else if (posType == POSITION_TYPE_SELL && ask < openPrice - safeMinDistance)
            {
                double potentialSL = NormalizeDouble(currentPrice + safeMinDistance + spread, digits);
                if (potentialSL < currentSL && potentialSL < openPrice)
                {
                    newSL = potentialSL;
                    modifyPosition = true;
                }
                
                double potentialTP = NormalizeDouble(currentPrice - safeMinDistance, digits);
                if (potentialTP < currentTP)
                {
                    newTP = potentialTP;
                    modifyPosition = true;
                }
            }
            
 

new post above with edit


another thing that will make the invalid stop is if your "potential SL" is higher than your "potential TP" which can easily happen if you don't make another rule in the logic to prevent that from being a case

 
Javier Santiago Gaston De Iriarte Cabrera #:

Can you please check this if its 0k? I've tried lots of combinations, and all give the same errors.


Perhaps you should check the code again:

Current price for Sell = Bid

Current price for Buy= Ask


Also, calculate the minimum distance by considering the maximum value between SYMBOL_TRADE_STOPS_LEVEL and  SYMBOL_TRADE_FREEZE_LEVEL


 
               double potentialSL = NormalizeDouble(currentPrice - safeMinDistance - spread, digits);

You buy at the Ask and sell at the Bid. Pending Buy Stop orders become market orders when hit by the Ask.

  1. Your buy order's TP/SL (or Sell Stop's/Sell Limit's entry) are triggered when the Bid / OrderClosePrice reaches it. Using Ask±n, makes your SL shorter and your TP longer, by the spread. Don't you want the specified amount used in either direction?

  2. Your sell order's TP/SL (or Buy Stop's/Buy Limit's entry) will be triggered when the Ask / OrderClosePrice reaches it. To trigger close at a specific Bid price, add the average spread.
              MODE_SPREAD (Paul) - MQL4 programming forum - Page 3 #25

  3. Prices (open, SL, and TP) must be a multiple of ticksize. Using Point means code breaks on 4 digit brokers (if any still exists), exotics (e.g. USDZAR where spread is over 500 points), and metals. Compute what a logical PIP is and use that, not points.
              How to manage JPY pairs with parameters? - MQL4 programming forum (2017)
              Slippage defined in index points - Expert Advisors and Automated Trading - MQL5 programming forum (2018)

  4. The charts show Bid prices only. Turn on the Ask line to see how big the spread is (Tools → Options (control+O) → charts → Show ask line.)

    Most brokers with variable spreads widen considerably at end of day (5 PM ET) ± 30 minutes.
    My GBPJPY shows average spread = 26 points, average maximum spread = 134.
    My EURCHF shows average spread = 18 points, average maximum spread = 106.
    (your broker will be similar).
              Is it reasonable to have such a huge spreads (20 PIP spreads) in EURCHF? - General - MQL5 programming forum (2022)