Help needed with invalid stops

 
It works when I use case #2 but any of the other cases it gives me error invalid stops. Any suggestions? 
// ---- Open Buy Orders
bool OpenBuy(int mode,int orders)
{                    
   string   error_desc = "";
   double   BuyPrice = 0, BuyStop = 0, BuyProfit = 0, Stop, Profit, maxloss = 0;
   
   minstop = SymbolInfoInteger(Symbol(),SYMBOL_TRADE_STOPS_LEVEL)/dRatio;  
         
   BuyPrice = NormalizeDouble(Ask,_Digits); 
   
      
      switch(StopLossMode)
      {
      case 0:  if(InitialStopLoss > 0) BuyStop = BuyPrice - InitialStopLoss*_point; else BuyStop = 0; break;
      case 1:  if(InitialStopLoss > 0) BuyStop = BuyPrice - (InitialStopLoss*atr[0]); else BuyStop = 0; break;
      case 2:  if(InitialStopLoss > 0) BuyStop = mean[0] - (InitialStopLoss*stdev[0]); else BuyStop = 0; break;
      case 3:  if(InitialStopLoss > 0) BuyStop = BuyPrice - NormalizeDouble(InitialStopLoss*stdev[0],_Digits); else BuyStop = 0; break;

      }
   
   if(BuyStop > 0 && Bid - BuyStop < minstop*_point) BuyStop = NormalizeDouble(Bid - minstop*_point,_Digits); 
      
      switch(TakeProfitMode)
      {
      case 0:  if(InitialTakeProfit > 0) BuyProfit = BuyPrice + InitialTakeProfit*_point; else BuyProfit = 0; break;
      case 1:  if(InitialTakeProfit > 0) BuyProfit = BuyPrice + (InitialTakeProfit*atr[0]); else BuyProfit = 0; break;
      case 2:  if(InitialTakeProfit > 0) BuyProfit = mean[0] + (InitialTakeProfit*stdev[0]); else BuyProfit = 0; break;
      case 3:  if(InitialTakeProfit > 0) BuyProfit = BuyPrice + NormalizeDouble(InitialTakeProfit*stdev[0],_Digits); else BuyProfit = 0; break;
      }
      
     if(Risk > 0 && BuyStop > 0) 
      {
      /*
      tick_val  = pipValue(_Symbol); 
      tick_size = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE)*dRatio;
      maxloss   = (BuyPrice - BuyStop)*tick_val/tick_size; 
      */
     // Print(__FUNCTION__+" "+SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE));
      if(OrderCalcProfit(ORDER_TYPE_BUY,Symbol(),1.0,BuyPrice,BuyStop,maxloss))
      {
         maxloss = -maxloss;    
      }   
      }
   
   double lots = MoneyManagement(maxloss);
   
   if(!CheckMoneyForTrade(_Symbol,lots,OP_BUY)) return(false); 
   if(!CheckVolumeValue(lots,error_desc)) {Print(error_desc); return(false);}
   
   Stop = BuyStop; Profit = BuyProfit;   
   if(!CheckStopLoss_Takeprofit(OP_BUY,Stop,Profit)) return(false);
      
   bool result = false;
      
   if(mode == OP_BUY     ) result = trade.Buy(lots,_Symbol,BuyPrice,Stop,Profit,Expert_Name); 
  
   
      if(!result)
      {
         if(DebugModeOn) Print("OpenBuy() failed. Return code=",trade.ResultRetcode(),". Code description: ",trade.ResultRetcodeDescription());
      }
      else
      {
         if(DebugModeOn) Print("OpenBuy() executed successfully. Return code=",trade.ResultRetcode(), " (",trade.ResultRetcodeDescription(),")");
      GlobalVariableSet(_Symbol+" "+(string)Magic+" buy",BuyPrice); 
      pc_stoploss = 0;
      return(true);  
      }
   
   return(false);
} 
 

Print all the prices of the orders plus ask and bid and check (in a hurry and approximately):

  1. Buy > Ask +mrq, S<Bid, TP>Ask,
  2. Sell < Bid - mrq, SL > Ask, TP<Bid.
mrq = minimum requirement see the specifications for the symbol.
 
BuyPrice = NormalizeDouble(Ask,_Digits); 
   
      
      switch(StopLossMode)
      {
      case 0:  if(InitialStopLoss > 0) BuyStop = BuyPrice - InitialStopLoss*_point; else BuyStop = 0; break;
  1. You used NormalizeDouble, It's use is usually wrong, as it is in your case.

    1. Floating point has an infinite number of decimals, it's you were not understanding floating point and that some numbers can't be represented exactly. (like 1/10.)
                Double-precision floating-point format - Wikipedia, the free encyclopedia

      See also The == operand. - MQL4 programming forum (2013)

    2. Print out your values to the precision you want with DoubleToString - Conversion Functions - MQL4 Reference.

    3. SL/TP (stops) need to be normalized to tick size (not Point) — code fails on non-currencies.
                On 5Digit Broker Stops are only allowed to be placed on full pip values. How to find out in mql? - MQL4 programming forum (2011)

      And abide by the limits Requirements and Limitations in Making Trades - Appendixes - MQL4 Tutorial and that requires understanding floating point equality Can price != price ? - MQL4 programming forum (2012)

    4. Open price for pending orders need to be adjusted. On Currencies, Point == TickSize, so you will get the same answer, but it won't work on non-currencies. So do it right.
                Trailing Bar Entry EA - MQL4 programming forum (2013)
                Bid/Ask: (No Need) to use NormalizeDouble in OrderSend - MQL4 programming forum (2012)

    5. Lot size must also be adjusted to a multiple of LotStep and check against min and max. If that is not a power of 1/10 then NormalizeDouble is wrong. Do it right.
                (MT4 2013)) (MT5 2022))

    6. MathRound() and NormalizeDouble() are rounding in a different way. Make it explicit.
                MT4:NormalizeDouble - MQL5 programming forum (2017)
                How to Normalize - Expert Advisors and Automated Trading - MQL5 programming forum (2017)

    7. Prices you get from the terminal are already correct (normalized).

    8. PIP, Point, or Tick are all different in general.
                What is a TICK? - MQL4 programming forum (2014)

  2. 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. 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)

 
Carl Schreiber #:

Print all the prices of the orders plus ask and bid and check (in a hurry and approximately):

  1. Buy > Ask +mrq, S<Bid, TP>Ask,
  2. Sell < Bid - mrq, SL > Ask, TP<Bid.
mrq = minimum requirement see the specifications for the symbol.

It's all good in that regards. I think the issue is actually coming from the lots calculations below. I noticed the EA works well in FX but I am trying to using it with Futures contracts where the lot step is more restricted. Looking at this part of the code I see there is a mechanism to deal with lots max and lots min but not so much with lots step. What sort of logic sentence can I add to it so that it rounds up the position size to the closest lower step? If the step is 1 and position size calculation is 1.6, I would prefer to trade 1 lot if that makes sense


// ---- Money Management
double MoneyManagement(double maxloss)
{
   double lots = 0, initlots;
   
   lot_min  = SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN);
   lot_step = SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP);
   lot_max  = SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
   contract = SymbolInfoDouble(Symbol(),SYMBOL_TRADE_CONTRACT_SIZE);    
   
   
   //if(Risk > 0 && maxloss > 0) initlots = AccountInfoDouble(ACCOUNT_MARGIN_FREE)*0.01*Risk/maxloss; else initlots = Lots; 
   Print(__FUNCTION__+" "+(string)Risk+" "+(string)maxloss);
   if(Risk > 0 && maxloss > 0) initlots = AccountInfoDouble(ACCOUNT_MARGIN_FREE)*(Risk/maxloss/100.0); else initlots = Lots; 
   
   
   
   lots = NormalizeDouble(initlots/lot_step,0)*lot_step;
   
   if(lots > lot_max) lots = lot_max;  
   if(lots < lot_min) lots = lot_min;
   
   return(lots);
}   
 

Just for the fun of it, I asked ChatGBT and this is the output it came up with. 


double MoneyManagement(double maxloss)
{
   double lots = 0, initlots;
   
   lot_min  = SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN);
   lot_step = SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP);
   lot_max  = SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
   contract = SymbolInfoDouble(Symbol(),SYMBOL_TRADE_CONTRACT_SIZE);    
   
   Print(__FUNCTION__+" "+(string)Risk+" "+(string)maxloss);
   if(Risk > 0 && maxloss > 0) initlots = AccountInfoDouble(ACCOUNT_MARGIN_FREE)*(Risk/maxloss/100.0); else initlots = Lots; 
   
   lots = MathCeil(initlots/lot_step)*lot_step;
   
   if(lots > lot_max) lots = lot_max;  
   if(lots < lot_min) lots = lot_min;
   
   return(lots);
}

along with the following explanation :


"In this updated code, the MathCeil() function is used to round up the value of initlots/lot_step to the nearest integer, and then the result is multiplied by lot_step to get the final lots value. Note that we use the NormalizeDouble() function to ensure that the input to MathCeil() is an integer multiple of lot_step ."

 
William Roeder #:
  1. You used NormalizeDouble, It's use is usually wrong, as it is in your case.

    1. Floating point has an infinite number of decimals, it's you were not understanding floating point and that some numbers can't be represented exactly. (like 1/10.)
                Double-precision floating-point format - Wikipedia, the free encyclopedia

      See also The == operand. - MQL4 programming forum (2013)

    2. Print out your values to the precision you want with DoubleToString - Conversion Functions - MQL4 Reference.

    3. SL/TP (stops) need to be normalized to tick size (not Point) — code fails on non-currencies.
                On 5Digit Broker Stops are only allowed to be placed on full pip values. How to find out in mql? - MQL4 programming forum (2011)

      And abide by the limits Requirements and Limitations in Making Trades - Appendixes - MQL4 Tutorial and that requires understanding floating point equality Can price != price ? - MQL4 programming forum (2012)

    4. Open price for pending orders need to be adjusted. On Currencies, Point == TickSize, so you will get the same answer, but it won't work on non-currencies. So do it right.
                Trailing Bar Entry EA - MQL4 programming forum (2013)
                Bid/Ask: (No Need) to use NormalizeDouble in OrderSend - MQL4 programming forum (2012)

    5. Lot size must also be adjusted to a multiple of LotStep and check against min and max. If that is not a power of 1/10 then NormalizeDouble is wrong. Do it right.
                (MT4 2013)) (MT5 2022))

    6. MathRound() and NormalizeDouble() are rounding in a different way. Make it explicit.
                MT4:NormalizeDouble - MQL5 programming forum (2017)
                How to Normalize - Expert Advisors and Automated Trading - MQL5 programming forum (2017)

    7. Prices you get from the terminal are already correct (normalized).

    8. PIP, Point, or Tick are all different in general.
                What is a TICK? - MQL4 programming forum (2014)

  2. 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. 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)

Thank you William! Very informative. Obviously I have plenty of wrong in my code and plenty to read now on how to fix it but at least your guide is cutting me hours of research. Thank you!

 

I made changes to the code but still giving errors when trading anything other than currencies. Can someone be a bit more specific about what I need to change 


// ---- Open Sell Orders
bool OpenSell(int mode,int orders)
{                    
   string   error_desc = "";
   double   SellPrice = 0, SellStop = 0, SellProfit = 0, Stop, Profit, maxloss = 0;
   
   minstop = SymbolInfoInteger(Symbol(),SYMBOL_TRADE_STOPS_LEVEL)/dRatio;   
   
   SellPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
     
      
      switch(StopLossMode)
      {
      case 0:  if(InitialStopLoss > 0) SellStop = SellPrice + InitialStopLoss*_point; else SellStop = 0; break;
      case 1:  if(InitialStopLoss > 0) SellStop = SellPrice + (InitialStopLoss*atr[0]); else SellStop = 0; break;
      case 2:  if(InitialStopLoss > 0) SellStop = mean[0] + (InitialStopLoss*stdev[0]); else SellStop = 0; break;
      case 3:  if(InitialStopLoss > 0) SellStop = SellPrice + NormalizeDouble(InitialStopLoss*stdev[0],_Digits); else SellStop = 0; break;
      }
    
   if(SellStop > 0 && SellStop - Ask < minstop*_point) SellStop = Ask + minstop*_point; 
// ---- Money Management
double MoneyManagement(double maxloss)
{
   double lots = 0, initlots;
   
   lot_min  = SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN);
   lot_step = SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP);
   lot_max  = SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
   contract = SymbolInfoDouble(Symbol(),SYMBOL_TRADE_CONTRACT_SIZE);    
   
   
   //if(Risk > 0 && maxloss > 0) initlots = AccountInfoDouble(ACCOUNT_MARGIN_FREE)*0.01*Risk/maxloss; else initlots = Lots; 
   Print(__FUNCTION__+" "+(string)Risk+" "+(string)maxloss);
   if(Risk > 0 && maxloss > 0) initlots = AccountInfoDouble(ACCOUNT_MARGIN_FREE)*(Risk/maxloss/100.0); else initlots = Lots; 
   
   
   
   lots = MathRound(lots/lot_step) * lot_step;
   
   if(lots > lot_max) lots = lot_max;  
   if(lots < lot_min) lots = lot_min;
   
   return(lots);
} 
 

Can any of you @whroeder1 @gooly recommend me a developer to fix my code professionally, meaning paid job. It looks like there are a lot of people making the same mistakes as far as using  NormalizeDouble and other functions. I need my EA to work for Futures symbols, not just FX.

Would any of you be interested in the job?

 
Ricardo Dacosta #: Can any of you @whroeder1 @gooly recommend me a developer to fix my code professionally, meaning paid job. It looks like there are a lot of people making the same mistakes as far as using  NormalizeDouble and other functions. I need my EA to work for Futures symbols, not just FX. Would any of you be interested in the job?

Such recommendations are against the forum rules. This is also the reason why the Freelance section works with a "double blind" system.

So, either contact developers directly if you know them or use the Freelance section and verify their capabilities.

Trading applications for MetaTrader 5 to order
Trading applications for MetaTrader 5 to order
  • 2023.03.06
  • www.mql5.com
The largest freelance service with MQL5 application developers
Reason: