Problem with Invalid Stops; however, levels are adequate. Still Getting error

 

Hello All, 

I generally do not ask for help. Nevertheless, I have been wrestling with this problem for several weeks and have been unable to get past it. I have been translating my EA's to MQL5 from MQL4. These work perfectly in MQL4. However, when executing, I keep getting an invalid stops. I have already done all of the obvious which is print out the levels, adjust the stops if they are inside the levels, etc. I even contacted the broker to see if there was with the specific symbol (I am using USA30 with Hot Forex). 


//+------------------------------------------------------------------+

//|Place Buy Order, modified version for step by step debugging      |

//+------------------------------------------------------------------+

ulong PlaceBuyOrderModifyOrder(double currentLot)

{

   ulong OrderNumber = 0;

   int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);

   double currentPrice = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), digits);

   

   if (m_trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, currentLot, currentPrice, 0, 0, BotComment))

   {

      Print (OrderNumber + " BUY successful " + currentPrice + " - Stop Loss: 0.00 Take Profit: 0.00" + " Lots: " + currentLot);

      OrderNumber = m_trade.ResultOrder();

      double openPrice = m_trade.RequestPrice();   //Get the price of the Market order

      

      //Modify Stop Loss and Take Profit based on order price

      //GET ATR

      double ATR[1];

      

      if(CopyBuffer(ATRHandle,0,1,1,ATR)!=1)

      {

      return 0;

      }   

      

      double ATRValue = NormalizeDouble(ATR[0], 5);

      

      _stop = GetStopLevel(ATR[0], "buy", openPrice);

      _profit1 = NormalizeDouble(openPrice + (ATR[0] * FirstTakeProfitMultiplier), digits);      

      

      //Just informational, delete after use

      

      // Retrieve the stop level in points

      int stopLevelPoints = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);

   

      // Retrieve the point size for the symbol

      double pointSize = SymbolInfoDouble(_Symbol, SYMBOL_POINT);

   

      // Calculate the minimum stop price distance

      double stopLevelPrice = stopLevelPoints * pointSize;      

      double bidPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);

      double askPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);   

      double minStopLossPrice = bidPrice - stopLevelPrice;

      double minTakeProfitPrice = askPrice + stopLevelPrice;    

      

      //End informational   

      

      if (m_trade.PositionModify(OrderNumber, _stop, _profit1))

         Print (OrderNumber + " modified! New SL: " , _stop, " Take Profit: " , _profit1);

      else

         Print ("MODIFY ORDER ERROR OCCURRED: ", m_trade.ResultRetcode(), " Order Price: ", openPrice, " Min SL Price: ", minStopLossPrice);   

   }

   else

   {

      OrderNumber = -1;

      Print ("ERROR OCCURRED: ", m_trade.ResultRetcode());   

   }

   

   return OrderNumber;

}



//+------------------------------------------------------------------+

//| Calculate Stop Loss && TP with adjusted price if needed          |

//| entryType = "buy" or "sell"                                      |

//| entryPrice = the price at which the order was entered            |

//+------------------------------------------------------------------+  

double GetStopLevel(double ATR, string entryType, double entryPrice)

{

   int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);

   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);

   double stopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * point;

   double stopPrice = 0;

   double currentPrice = 0;

   double addPoints = 10 * point;

   

   double _newStopPrice = 0;

   

   if (entryType == "buy")

   {      

      //Calculated Stop Level Stop Price

      stopPrice =  entryPrice - stopLevel;

      

      //ATR Stop and Profit

      _stop = NormalizeDouble(entryPrice - (ATR * StopLossMultiplier), digits);

       

      if (_stop < (stopPrice - addPoints))

         return _stop;

      else

      {

         _newStopPrice = stopPrice - addPoints;

         return _newStopPrice;

      }

   }

   else

   {

      //Calculated Stop Level Stop Price

      stopPrice = entryPrice + stopLevel;

      

      //ATR Stop and Profit

      _stop = NormalizeDouble(entryPrice + (ATR * StopLossMultiplier), digits);

      

      if (_stop > (stopPrice + addPoints))

         return _stop;

      else

      {

         _newStopPrice = stopPrice + addPoints;

         return _newStopPrice;

      }      

   }

}

One specific entry is:

2024.06.11 06:22:31.938 2023.04.04 10:15:00   deal performed [#2 sell 0.67 USA30 at 33619.80]

 When I go to modify the order, I get: 

2024.06.11 06:22:31.941 2023.04.04 10:15:00   failed modify #2 sell 0.67 USA30 sl: 0.00, tp: 0.00 -> sl: 33636.30, tp: 33562.05 [Invalid stops]

My debug Print, however, shows that the Stop Loss is way outside of the imposed minimum: 

2024.06.11 06:22:31.941 2023.04.04 10:15:00   MODIFY ORDER ERROR OCCURRED: 10016 Order Price: 33619.8 Min SL Price: 33619.200000000004


Any ideas? 

 

Just in case someone stumbles on this....

My mistake was that I did not take Tick Size into consideration. To fix:


      double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);

      

      _stop = MathCeil(GetStopLevel(ATR[0], "sell", openPrice) / tickSize) * tickSize;

      _profit1 = MathFloor(NormalizeDouble(openPrice - (ATR[0] * FirstTakeProfitMultiplier), digits) / tickSize) * tickSize;     

 
Did that fix the issue? Another thing to be aware of is that the minimum distance requirement from the broker?
 

For other users who may have the same question:

//+--------------------------------------------------------------------------------------------------------------------+
//| This function normalizes and adjusts the price to the TICK SIZE                                                    |
//+--------------------------------------------------------------------------------------------------------------------+
bool NormalizePrice(string symbol, double &price)
  {
//--- Local variables
   long   decimal_digits = 0;
   double tick_size = 0.0;

//--- Get the minimal price change
   if(!SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE, tick_size))
     {
      Print(__FUNCTION__, " - Error getting the SYMBOL_TRADE_TICK_SIZE: ", GetLastError(), " - ", symbol);
      return(false);
     }

//--- Get the number of decimal digits
   if(!SymbolInfoInteger(symbol, SYMBOL_DIGITS, decimal_digits))
     {
      Print(__FUNCTION__, " - Error getting the SYMBOL_DIGITS: ", GetLastError(), " - ", symbol);
      return(false);
     }

//--- Return the price normalized
   if(tick_size == 0.0)
     {
      price = NormalizeDouble(price, (int)decimal_digits);
     }
//--- Return the price normalized and adjusted to the TICK SIZE
   else
     {
      price = NormalizeDouble(MathRound(price / tick_size) * tick_size, (int)decimal_digits);
     }

//--- Successful normalization
   return(true);
  }