NormalizedDouble() error - Trailing stop function

 

I've encountered an "invalid parameters" error when invoking the following trailing stop function. Upon using the debugger, I observed that the NormalizeDouble function appears to work correctly for the ASK and newStopLoss prices but not for any of other prices. I believe that I've employed the same syntax and code structure for all prices. Could there be an oversight or a subtle difference in the implementation that I might have missed?


//+------------------------------------------------------------------+
//| Trailing stop                                                    |
//+------------------------------------------------------------------+
void applyTrailingStop(void)
{
  MqlTick currentTick;
 if(SymbolInfoTick(_Symbol, currentTick))
  {
    double Bid = NormalizeDouble(currentTick.bid,_Digits);
    double Ask = NormalizeDouble(currentTick.ask,_Digits);
    int totalOrders = PositionsTotal();
    double trailingStopPointsapply = trailingStopPoints * _Point;

    for(int i = 0; i < totalOrders; i++)
    {
     ulong ticket =PositionGetInteger(POSITION_TICKET);
      const string symbol = PositionGetString(POSITION_SYMBOL);
      if(symbol != _Symbol)
        continue; // Skip positions of other symbols

      if(PositionGetInteger(POSITION_MAGIC) != magicNumber)
        continue; // Skip positions with a different magic number

      double openPrice = NormalizeDouble(PositionGetDouble(POSITION_PRICE_OPEN),_Digits);
      double stopLoss = NormalizeDouble(PositionGetDouble(POSITION_SL),_Digits);
      double postionTP = NormalizeDouble(PositionGetDouble(POSITION_TP),_Digits);

      double newStopLoss = 0;
      if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
      {
        newStopLoss = NormalizeDouble(normalizePrice(Bid - trailingStopPointsapply), _Digits);
        if(newStopLoss > openPrice && (stopLoss < openPrice || newStopLoss > stopLoss) && newStopLoss != stopLoss && checkStopLossTakeProfitLevels(openPrice, newStopLoss, postionTP))
        {
          if(!trade.PositionModify(ticket, newStopLoss, postionTP))
          {
            PrintFormat("Error: Failed to modify position. Error code: %d", GetLastError());
          }
        }
      }
      else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
      {
        newStopLoss = NormalizeDouble(Ask + trailingStopPointsapply, _Digits);
        if(newStopLoss < openPrice && (stopLoss > openPrice || newStopLoss < stopLoss) && newStopLoss != stopLoss  && checkStopLossTakeProfitLevels(openPrice, newStopLoss, postionTP))
        {
          if(!trade.PositionModify(ticket, newStopLoss, postionTP))
          {
            PrintFormat("Error: Failed to modify position. Error code: %d", GetLastError());
          }
        }
      }
    }
  }
}


I only get this error when testing with Random latency. With zero latency, I am all clear


 
Where appears your error "invalid parameters? Your function has no parameters: void applyTrailingStop(void)!
 
  1. Do not normalise quote prices provided by the platform (ie. OHLC prices, Bid, Ask, etc). They are already normalised.
  2. For calculated prices, do not normalise based on digits or on point. Use the tick size. You have already been informed about this at least twice:
    https://www.mql5.com/en/forum/444428#comment_46094491
    https://www.mql5.com/en/forum/445072#comment_46126937
 
Carl Schreiber #:
Where appears your error "invalid parameters? Your function has no parameters: void applyTrailingStop(void)!

in the testing log



 
Rafael Santos #:

in the testing log



In addition,  I only get this error when testing with Random latency. With zero latency, I am all clear

 
Fernando Carreiro #:
  1. Do not normalise quote prices provided by the platform (ie. OHLC prices, Bid, Ask, etc). They are already normalised.
  2. For calculated prices, do not normalise based on digits or on point. Use the tick size. You have already been informed about this at least twice:
    https://www.mql5.com/en/forum/444428#comment_46094491
    https://www.mql5.com/en/forum/445072#comment_46126937
"I have diligently attempted the recommended solutions, incorporating both the normalized price and the normalizedDouble function. However, the issue remains unresolved. While I acknowledge the guidance previously provided, I am pleased to report that I overcame the invalid stop errors with Alain's valuable assistance. Given that the current challenge appears distinct from prior issues, I am seeking further expertise to address this matter effectively. Your insightful suggestions and recommendations would be greatly appreciated.
 
Rafael Santos #:
"I have diligently attempted the recommended solutions, incorporating both the normalized price and the normalizedDouble function. However, the issue remains unresolved. While I acknowledge the guidance previously provided, I am pleased to report that I overcame the invalid stop errors with Alain's valuable assistance. Given that the current challenge appears distinct from prior issues, I am seeking further expertise to address this matter effectively. Your insightful suggestions and recommendations would be greatly appreciated.

Updated code same results:




void applyTrailingStop(void)
{
  MqlTick currentTick;
 if(SymbolInfoTick(_Symbol, currentTick))
  {
    double Bid = currentTick.bid;
    double Ask = currentTick.ask;
    int totalOrders = PositionsTotal();
    double trailingStopPointsapply = trailingStopPoints * _Point;

    for(int i = 0; i < totalOrders; i++)
    {
     ulong ticket =PositionGetInteger(POSITION_TICKET);
      const string symbol = PositionGetString(POSITION_SYMBOL);
      if(symbol != _Symbol)
        continue; // Skip positions of other symbols

      if(PositionGetInteger(POSITION_MAGIC) != magicNumber)
        continue; // Skip positions with a different magic number

      double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
      double stopLoss = PositionGetDouble(POSITION_SL);
      double positionTP = PositionGetDouble(POSITION_TP);

      double newStopLoss = 0;
      if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
      {
        newStopLoss = normalizePrice(Bid - trailingStopPointsapply);
        if(newStopLoss > openPrice && (stopLoss < openPrice || newStopLoss > stopLoss) && newStopLoss != stopLoss && checkStopLossTakeProfitLevels(openPrice, newStopLoss, positionTP))
        {
          if(!trade.PositionModify(ticket, newStopLoss, positionTP))
          {
            PrintFormat("Error: Failed to modify position. Error code: %d", GetLastError());
          }
        }
      }
      else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
      {
        newStopLoss = normalizePrice(Ask + trailingStopPointsapply);
        if(newStopLoss < openPrice && (stopLoss > openPrice || newStopLoss < stopLoss) && newStopLoss != stopLoss  && checkStopLossTakeProfitLevels(openPrice, newStopLoss, positionTP))
        {
          if(!trade.PositionModify(ticket, newStopLoss, positionTP))
          {
            PrintFormat("Error: Failed to modify position. Error code: %d", GetLastError());
          }
        }
      }
    }
  }
}
 
afael Santos #: Updated code same results:

What is the same results? Are you referring to the values in the debugger having many decimal points?

That is normal. Floating point numbers are binary numbers and cannot represent decimal numbers precisely. One is base 2 and the other is base 10.

Forum on trading, automated trading systems and testing trading strategies

MathRound fails for one particular number

Fernando Carreiro, 2018.01.01 22:08

He means that the value "0.69" cannot be exactly represented given the way a floating point number works (based on binary and not decimal representation) - hence, why the value gets represented as "0.68999999..." (see below).

You can never really "normalize" it and it is the main reason why both @whroeder1 and myself contest the use of the NormalizeDouble() function. It should in the very least be renamed to something like "RoundDigits()" because it is more of a "rounding" function and does not "normalize" in any way or fashion.


https://www.h-schmidt.net/FloatConverter/IEEE754.html

EDIT: Please note that the above images are for examples of representation in the 4-byte "float", and not the 8-byte "double" which offers more precision but still cannot represent the value "0.69" exactly due to the "binary" nature of the format.

EDIT2: For future readers that have difficulty understanding (or accepting) this concept, of decimal values not having an exact representation with a "float" or a "double", here is an article worth reading:

Why 0.1 Does Not Exist In Floating-Point

Many new programmers become aware of binary floating-point after seeing their programs give odd results: “Why does my program print 0.10000000000000001 when I enter 0.1?”; “Why does 0.3 + 0.6 = 0.89999999999999991?”; “Why does 6 * 0.1 not equal 0.6?” Questions like these are asked every day, on online forums like stackoverflow.com.

The answer is that most decimals have infinite representations in binary. Take 0.1 for example. It’s one of the simplest decimals you can think of, and yet it looks so complicated in binary:


Decimal 0.1 In Binary ( To 1369 Places

The bits go on forever; no matter how many of those bits you store in a computer, you will never end up with the binary equivalent of decimal 0.1.

... Read the rest of the article at: http://www.exploringbinary.com/why-0-point-1-does-not-exist-in-floating-point/

Forum on trading, automated trading systems and testing trading strategies

how to convert double with zeros in front to integer?

Fernando Carreiro, 2023.01.11 14:03

Take some time to learn how floating point number work and are stored:

To help understand (debugging purposes) the format of real number also look at the follow printing formats — PrintFormat

a

double

A real number in format [−]0xh.hhhh p±dd, where h.hhhh – mantissa in the form of hexadecimal digits, using "abcdef", dd - One or more digits of exponent. Number of decimal places is determined by the accuracy specification

A

double

A real number in format [−]0xh.hhhh P±dd, where h.hhhh – mantissa in the form of hexadecimal digits, using "ABCDEF", dd - One or more digits of exponent. Number of decimal places is determined by the accuracy specification

 
Fernando Carreiro #:
afael Santos #: Updated code same results:

What is the same results? Are you referring to the values in the debugger having many decimal points?

That is normal. Floating point numbers are binary numbers and cannot represent decimal numbers precisely. One is base 2 and the other is base 10.

This is valuable insight—many thanks, Fernando! Your explanation has successfully dispelled my misconception that the normalized double or normalized price were not functioning correctly. The truncation or normalization of the ask and new stop loss prices initially caused some confusion. I will continue to work on this matter. Perhaps my inquiry should have been focused on understanding the cause of the invalid parameters error during random latency settings.
 

Forum on trading, automated trading systems and testing trading strategies


//+------------------------------------------------------------------+
//| Trailing stop                                                    |
//+------------------------------------------------------------------+
void applyTrailingStop(void)
{
  MqlTick currentTick;
 if(SymbolInfoTick(_Symbol, currentTick))
  {
    double Bid = NormalizeDouble(currentTick.bid,_Digits);
    double Ask = NormalizeDouble(currentTick.ask,_Digits);
    int totalOrders = PositionsTotal();
    double trailingStopPointsapply = trailingStopPoints * _Point;

    for(int i = 0; i < totalOrders; i++)
    {
     ulong ticket =PositionGetInteger(POSITION_TICKET);
      const string symbol = PositionGetString(POSITION_SYMBOL);
      if(symbol != _Symbol)
        continue; // Skip positions of other symbols

      if(PositionGetInteger(POSITION_MAGIC) != magicNumber)
        continue; // Skip positions with a different magic number

      double openPrice = NormalizeDouble(PositionGetDouble(POSITION_PRICE_OPEN),_Digits);
      double stopLoss = NormalizeDouble(PositionGetDouble(POSITION_SL),_Digits);
      double postionTP = NormalizeDouble(PositionGetDouble(POSITION_TP),_Digits);

      double newStopLoss = 0;
      if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
      {
        newStopLoss = NormalizeDouble(normalizePrice(Bid - trailingStopPointsapply), _Digits);
        if(newStopLoss > openPrice && (stopLoss < openPrice || newStopLoss > stopLoss) && newStopLoss != stopLoss && checkStopLossTakeProfitLevels(openPrice, newStopLoss, postionTP))
        {
          if(!trade.PositionModify(ticket, newStopLoss, postionTP))
          {
            PrintFormat("Error: Failed to modify position. Error code: %d", GetLastError());
          }
        }
      }
      else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
      {
        newStopLoss = NormalizeDouble(Ask + trailingStopPointsapply, _Digits);
        if(newStopLoss < openPrice && (stopLoss > openPrice || newStopLoss < stopLoss) && newStopLoss != stopLoss  && checkStopLossTakeProfitLevels(openPrice, newStopLoss, postionTP))
        {
          if(!trade.PositionModify(ticket, newStopLoss, postionTP))
          {
            PrintFormat("Error: Failed to modify position. Error code: %d", GetLastError());
          }
        }
      }
    }
  }
}

The error lies in the highlighted function. The market moves too much in the opposite direction with random latency, so the calculated sl price becomes invalid.

Could you please provide the code?
 
amrali #:

The error lies in the highlighted function. The market moves too much in the opposite direction with random latency, so the calculated sl price becomes invalid.

Could you please provide the code?

Hello Amrali,  I'll be happy to provide it to you. Please feel free to point out any discrepancies or potential issues. 


I wanted to mention that I've called the checkStopLossTakeProfitLevels function within the checkForOpen function to initiate the initial trade, and I haven't encountered errors in both exact execution and random latency scenarios. However, errors seem to occur during random latency when the trailing stop function is invoked.

More information: https://www.mql5.com/en/forum/444428

//+------------------------------------------------------------------+
//|                                                        Test2.mq5 |
//|                        Copyright 2023,Santos Family Holdings LLC |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023,Santos Family Holdings LLC"
#property version   "1.0"

#include <Trade\Trade.mqh>
#include <Trade\AccountInfo.mqh>
#include <MovingAverages.mqh>

input int magicNumber = 11162022;// Magic Number

input int startHour = 0; //Start Hour
input int startMinute = 0; //Start Minute
input int endHour = 23; // End Hour
input int endMinute = 59; // End minute

input double maxDailyDrawdownPercent = 10.0; // Maximum daily drawdown percent

input double lotSize = 0.1; // Lot size
input int stopLossPoints =3000; // Stoploss in points
input int takeProfitPoints =13000; // Take profit in points
input int trailingStopPoints = 1000; //Trailing stoploss in points

input bool tradeMonday = true; //Trade on Monday
input bool tradeTuesday = true; //Trade on Tuesday
input bool tradeWednesday = true; //Trade on Wednesday
input bool tradeThursday = true; //Trade on Thursday
input bool tradeFriday = true; //Trade on Friday

//Global Variables
double PointValue =0;

//Trade classes and Handles
CTrade trade;
CAccountInfo AccInfo;
int ma6Handle, ma26Handle, ma58Handle, ma60Handle;

//+------------------------------------------------------------------+
//| Oninit                                                           |
//+------------------------------------------------------------------+
int OnInit()
  {
//Set Magic number and Filing type
   trade.SetTypeFillingBySymbol(_Symbol);
   trade.SetExpertMagicNumber(magicNumber);

// Initialize moving averages
   ma6Handle = iMA(_Symbol, PERIOD_CURRENT, 6, 0, MODE_SMA, PRICE_CLOSE);
   ma26Handle = iMA(_Symbol, PERIOD_CURRENT, 26, 0, MODE_SMA, PRICE_CLOSE);
   ma58Handle = iMA(_Symbol, PERIOD_CURRENT, 58, 0, MODE_SMA, PRICE_CLOSE);
   ma60Handle = iMA(_Symbol, PERIOD_CURRENT, 60, 0, MODE_SMA, PRICE_CLOSE);
   if(ma6Handle == INVALID_HANDLE || ma26Handle == INVALID_HANDLE || ma58Handle == INVALID_HANDLE || ma60Handle == INVALID_HANDLE)
     {
      return INIT_FAILED;
     }
   else
     {
      Print("Moving average indicator handles have been initialized ");
     }

//Check valid lotsize
   if(!checkValidVolume(lotSize))
     {
      Print("Invalid Volume, Check lot size: ",lotSize);
      return INIT_FAILED;
     }
   else
     {
      Print("Lot size is withing the symbol requirements, lot size: ", lotSize);
     }
//Check if trading is allowed
   bool tradeAllowed= TerminalInfoInteger(TERMINAL_TRADE_ALLOWED);
   if(!tradeAllowed)
     {
      Print("Terminal check: Trading is not allowed");
      return INIT_FAILED;
     }
   else
     {
      Print("Terminal check: Trading is allowed");
     }
//Allow EA to hadle 3 and 5 digit symbols
   double MyPoint=_Point;
   if(_Digits==3 || _Digits==5)
      MyPoint=_Point*10;
   PointValue= MyPoint;
   if(!PointValue)
     {
      Print("Current symbol point value Error: ",GetLastError());
      return INIT_FAILED;
     }
   else
     {
      Print("The current symbol point value is: ",PointValue);
     }

//Check for sufficient price history
   if(!Bars(_Symbol,_Period)>100)
     {
      Print("There is not enough price history available on this chart.");
      return INIT_FAILED;
     }
   else
     {Print("There is enough price data for trading on this chart");}

//Check stop loss levels
   if(stopLossPoints < SYMBOL_TRADE_STOPS_LEVEL || takeProfitPoints < SYMBOL_TRADE_STOPS_LEVEL)
     {
      Print("Invalid Stop loss or Take Profit. The minimum stop loss and take profit level for the current symbol is: ",SYMBOL_TRADE_STOPS_LEVEL);
      return INIT_FAILED;
     }
   else
     {Print("The stop loss and take profit are above the minimum stop level requirements for the current symbol. Minimum level allowed is : ", SYMBOL_TRADE_STOPS_LEVEL);}

   return INIT_SUCCEEDED;
  }
//+------------------------------------------------------------------+
//| Check for open                                                   |
//+------------------------------------------------------------------+
void CheckForOpen(void)
  {
// Run Checks before placing trades
   if(!isTradingTime())
     {Print("It is not time to trade, Start Hour: ", startHour,"Start Minute: ", startMinute);}
   else
     {
      if(!isTradingDay())
        {Print("Today is not an active trading day, check inputs for more information");}
      else
        {
         if(!checkMaxDailyDrawdown())
           {Print("The Max Daily drawdown has been reached There will be no more trading for today");}
         else
           {
            // Update moving average values
            double ma6Value[2], ma26Value[2], ma58Value[2], ma60Value[2];
            if(CopyBuffer(ma6Handle, 0, 0, 2, ma6Value) != 2 ||
               CopyBuffer(ma26Handle, 0, 0, 2, ma26Value) != 2 ||
               CopyBuffer(ma58Handle, 0, 0, 2, ma58Value) != 2 ||
               CopyBuffer(ma60Handle, 0, 0, 2, ma60Value) != 2)
              {
               Print("Error updating moving average values.");
               return;
              }

            ENUM_ORDER_TYPE signal=WRONG_VALUE;
            if(//---Buy conditions
               //example condition for testing
               ma6Value[0] > ma60Value[0]


            )
               signal=ORDER_TYPE_BUY;    // Set buy order type

            if(//---Sell Conditions
               //example condition for testing
               ma6Value[0] < ma60Value[0]


            )
               signal=ORDER_TYPE_SELL;    // Set sell order type

            // get the current Actual ask/bid price
            MqlTick currentTick;
            if(SymbolInfoTick(_Symbol, currentTick))
              {
               double bidPrice = currentTick.bid;
               double askPrice = currentTick.ask;

               if(signal==ORDER_TYPE_BUY)
                 {
                  double entryPrice = normalizePrice(askPrice);
                  double stopLoss = normalizePrice(entryPrice - stopLossPoints * PointValue);
                  double takeProfit = normalizePrice(entryPrice + takeProfitPoints * PointValue);
                  Print("Buy Order Entry Price: ", entryPrice," Buy Order Stoploss: ",stopLoss," Buy Order Take profit: ",takeProfit," Symbol trade stops level: ", SYMBOL_TRADE_STOPS_LEVEL*_Point," Symbol Freeze Level: ", SYMBOL_TRADE_FREEZE_LEVEL*_Point," checkStopLossTakeProfitLevels(): ", checkStopLossTakeProfitLevels(entryPrice,stopLoss,takeProfit));
                  double marginCheck = AccInfo.MarginCheck(_Symbol,ORDER_TYPE_BUY,lotSize,entryPrice);
                  double freeMarginCheck = AccInfo.FreeMargin();
                  //Print("marginCheck: ", marginCheck,"freeMarginCheck: ",freeMarginCheck);

                  //Check margin and stop levels
                  if(marginCheck < freeMarginCheck && checkStopLossTakeProfitLevels(entryPrice,stopLoss,takeProfit))
                    {
                     //Open buy trade
                     if(!trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,lotSize,entryPrice,stopLoss,takeProfit))
                       {Print("Buy trade Error code ", GetLastError());}
                    }
                 }
               else
                 {
                  if(signal==ORDER_TYPE_SELL)
                    {
                     double entryPrice = normalizePrice(bidPrice);
                     double stopLoss = normalizePrice(entryPrice + stopLossPoints * PointValue);
                     double takeProfit = normalizePrice(entryPrice - takeProfitPoints * PointValue);
                     Print("Sell Order Entry Price: ", entryPrice," Sell Order Stoploss: ",stopLoss," Sell Order Take profit: ",takeProfit," Symbol trade stops level: ", SYMBOL_TRADE_STOPS_LEVEL*_Point," Symbol Freeze Level: ", SYMBOL_TRADE_FREEZE_LEVEL*_Point," checkStopLossTakeProfitLevels(): ", checkStopLossTakeProfitLevels(entryPrice,stopLoss,takeProfit));
                     double marginCheck = AccInfo.MarginCheck(_Symbol,ORDER_TYPE_SELL,lotSize,entryPrice);
                     double freeMarginCheck = AccInfo.FreeMargin();
                     //Print("marginCheck: ", marginCheck,"freeMarginCheck: ",freeMarginCheck);

                     //Check margin and stop levels
                     if(marginCheck < freeMarginCheck && checkStopLossTakeProfitLevels(entryPrice,stopLoss,takeProfit))
                       {
                        //Open sell trade
                        if(!trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,lotSize,entryPrice,stopLoss,takeProfit))
                          {Print("Sell trade Error code ", GetLastError());}
                       }
                    }

                 }
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|OnTick                                                            |
//+------------------------------------------------------------------+
void OnTick()
  {
//---If there are no open orders, check for open conditions
   if(TotalOrdersCount() <= 0)
      CheckForOpen();

//---Update trailing stop
 //  if(trailingStopPoints > 0 && TotalOrdersCount() > 0)
    //  applyTrailingStop();


//---Comments
//---Ask-Bid-Spread -Bar Time remaining
   double Ask,Bid,Spread;
   string remainingTime = TimeRemaining();
   Ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
   Bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
   Spread= NormalizeDouble(MathAbs(Ask-Bid),_Digits);
//--- Output values in three lines
   Comment(StringFormat("Ask = %G\nBid = %G\nSpread = %G\nBar closes in: %s\n",Ask,Bid,Spread,remainingTime));


  }
//+------------------------------------------------------------------+
//| Check for active trading time                                    |
//+------------------------------------------------------------------+
bool isTradingTime()
  {
   MqlDateTime mqlDateTime;
   TimeToStruct(TimeCurrent(), mqlDateTime);
   int currentHour = mqlDateTime.hour;
   int currentMinute = mqlDateTime.min;

   int startTimeInMinutes = startHour * 60 + startMinute;
   int endTimeInMinutes = endHour * 60 + endMinute;
   int currentTimeInMinutes = currentHour * 60 + currentMinute;

   if(startTimeInMinutes <= currentTimeInMinutes && currentTimeInMinutes <= endTimeInMinutes)
     {
      return true;
     }

   return false;
  }
//+------------------------------------------------------------------+
//| Check volume                                                     |
//+------------------------------------------------------------------+
bool checkValidVolume(double volume)
  {
   double minVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double volumeStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

   if(volume < minVolume || volume > maxVolume)
     {
      return false;
     }

   double volumeDifference = volume - minVolume;
   double stepCount = MathRound(volumeDifference / volumeStep);

   if(MathAbs(volumeDifference - stepCount * volumeStep) > 0.0001)
     {
      return false;
     }

   return true;
  }
//+------------------------------------------------------------------+
//| Check SL TP Levels                                               |
//+------------------------------------------------------------------+
bool checkStopLossTakeProfitLevels(double entryPrice, double stopLoss, double takeProfit)
{
  double minStopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * _Point;
  double freezeLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_FREEZE_LEVEL) * _Point;

  if(MathAbs(entryPrice - stopLoss) < minStopLevel || MathAbs(entryPrice - takeProfit) < minStopLevel)
  {
    return false;
  }

  if(MathAbs(entryPrice - stopLoss) < freezeLevel || MathAbs(entryPrice - takeProfit) < freezeLevel)
  {
    return false;
  }

  return true;
}
//+------------------------------------------------------------------+
//| Check for active trading day                                     |
//+------------------------------------------------------------------+
bool isTradingDay()
  {
   datetime currentTime = TimeCurrent();
   MqlDateTime mqlDateTime;
   TimeToStruct(currentTime, mqlDateTime);
   ENUM_DAY_OF_WEEK currentDayOfWeek = (ENUM_DAY_OF_WEEK)mqlDateTime.day_of_week;

   switch(currentDayOfWeek)
     {
      case MONDAY:
         return tradeMonday;
      case TUESDAY:
         return tradeTuesday;
      case WEDNESDAY:
         return tradeWednesday;
      case THURSDAY:
         return tradeThursday;
      case FRIDAY:
         return tradeFriday;
      default:
         return false;
     }
  }
//+------------------------------------------------------------------+
//|Check max daily drawdown                                          |
//+------------------------------------------------------------------+
bool checkMaxDailyDrawdown(void)
  {
   static datetime lastTradingDay = 0;
   static double initialBalance = 0;

   datetime currentDay = TimeCurrent() / 86400;
   if(currentDay > lastTradingDay)
     {
      lastTradingDay = currentDay;
      initialBalance = AccountInfoDouble(ACCOUNT_BALANCE);
     }

   double currentBalance = AccountInfoDouble(ACCOUNT_BALANCE);
   double drawdown = initialBalance - currentBalance;
   double drawdownPercent = (drawdown / initialBalance) * 100;
//Print("Calculated draw down percent is :", drawdownPercent,"the max daily drawdown percent is: ",maxDailyDrawdownPercent);
   if(maxDailyDrawdownPercent == 0)
     {
      return true;
     }
   else
     {
      return drawdownPercent <= maxDailyDrawdownPercent;
     }

  }
//+------------------------------------------------------------------+
//| Trailing stop                                                    |
//+------------------------------------------------------------------+
void applyTrailingStop(void)
{
  MqlTick currentTick;
 if(SymbolInfoTick(_Symbol, currentTick))
  {
    double Bid = currentTick.bid;
    double Ask = currentTick.ask;
    int totalOrders = PositionsTotal();
    double trailingStopPointsapply = trailingStopPoints * _Point;

    for(int i = 0; i < totalOrders; i++)
    {
     ulong ticket =PositionGetInteger(POSITION_TICKET);
      const string symbol = PositionGetString(POSITION_SYMBOL);
      if(symbol != _Symbol)
        continue; // Skip positions of other symbols

      if(PositionGetInteger(POSITION_MAGIC) != magicNumber)
        continue; // Skip positions with a different magic number

      double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
      double stopLoss = PositionGetDouble(POSITION_SL);
      double positionTP = PositionGetDouble(POSITION_TP);

      double newStopLoss = 0;
      if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
      {
        newStopLoss = normalizePrice(Bid - trailingStopPointsapply);
        if(newStopLoss > openPrice && (stopLoss < openPrice || newStopLoss > stopLoss) && newStopLoss != stopLoss && checkStopLossTakeProfitLevels(openPrice, newStopLoss, positionTP))
        {
          if(!trade.PositionModify(ticket, newStopLoss, positionTP))
          {
            PrintFormat("Error: Failed to modify position. Error code: %d", GetLastError());
          }
        }
      }
      else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
      {
        newStopLoss = normalizePrice(Ask + trailingStopPointsapply);
        if(newStopLoss < openPrice && (stopLoss > openPrice || newStopLoss < stopLoss) && newStopLoss != stopLoss  && checkStopLossTakeProfitLevels(openPrice, newStopLoss, positionTP))
        {
          if(!trade.PositionModify(ticket, newStopLoss, positionTP))
          {
            PrintFormat("Error: Failed to modify position. Error code: %d", GetLastError());
          }
        }
      }
    }
  }
}

//+------------------------------------------------------------------+
//|Total Orders count                                                |
//+------------------------------------------------------------------+
int TotalOrdersCount()
  {
   int result=0;
   int posTotal=PositionsTotal();
   for(int posIndex=posTotal-1; posIndex>=0; posIndex--)
     {
      ulong ticket=PositionGetTicket(posIndex);
      if(PositionSelectByTicket(ticket) && PositionGetInteger(POSITION_MAGIC)==magicNumber)
         result++;
     }
   return (result);
  }
//+------------------------------------------------------------------+
//| Normalize price according to tick size                           |
//+------------------------------------------------------------------+
double normalizePrice(double price)
{
  double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
  return(MathRound(price / tickSize) * tickSize);
}
//+------------------------------------------------------------------+
//|Time Remaining on current bar                                     |
//+------------------------------------------------------------------+
string TimeRemaining()
  {
   datetime currentTime = TimeCurrent();
   datetime currentBarOpenTime = iTime(_Symbol, PERIOD_CURRENT, 0);
   int periodInSeconds = PeriodSeconds(PERIOD_CURRENT);
   datetime currentBarCloseTime = currentBarOpenTime + periodInSeconds;

   int remainingTime = (int)(currentBarCloseTime - currentTime);
   int hours = remainingTime / 3600;
   int minutes = (remainingTime % 3600) / 60;
   int seconds = remainingTime % 60;

   string remainingTimeString = StringFormat("%02d:%02d:%02d", hours, minutes, seconds);
   return remainingTimeString;
  }

//+------------------------------------------------------------------+
[Invalid Stops]- Print("Stop Level is: ", stops_level); returning 0 - How to fix an invalid stop error in my EA code
[Invalid Stops]- Print("Stop Level is: ", stops_level); returning 0 - How to fix an invalid stop error in my EA code
  • 2023.03.28
  • www.mql5.com
Hello, i am encountering the  " invalid stops " error message in my ea code. I would like to know if you have any suggestions as to what might be causing this error message to appear, and how i can go about resolving it
Reason: