ORB strategy issue

 

Hello everyone, I am new to coding and have limited experience, but I recently came across an ORB EA strategy online that I like. However, there is some issue with it. I
The EA is supposed to draw and set the open range high, but it appears to be slightly shifted above the highest high, which is causing problems with the entry orders. 


I've attached screen shot of the chart example

 I would really appreciate your help. 
Thank you in advance for your support!


#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

//+------------------------------------------------------------------+
//| Include                                   |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>


//+------------------------------------------------------------------+
//| Inputs                                   |
//+------------------------------------------------------------------+
input group "==== General Inputs ===="
input long InpMagicNumber = 12345;  // magic number
input double InpLots = 0.01;        // lot size
input int InpStopLoss = 100;        // stop loss 
input int InpTakeProfit = 100;      // take profit 

input group "==== Range Inputs ===="
input int InpRangeStart = 300;      // range start in minutes
input int InpRangeDurration = 120;  // range durration in minutes
input int InpRangeClose = 600;     // range close in minutes

enum BREAKOUT_MOBDE_ENUM{
    ONE_SIGNAL,                     // one breakout per range
    TWO_SIGNALS                     // high and low breakout
    };
input BREAKOUT_MOBDE_ENUM InpBreakoutMode = ONE_SIGNAL; //breakout mode

input group "==== Day of the week filter ===="
input bool InpMonday = true;        // range on monday
input bool InpTuesday = true;       // range on tuesday
input bool InpWednesday = true;     // range on wednsday
input bool InpThursday = true;      // range on thursday
input bool InpFriday = true;        // range on friday



//+------------------------------------------------------------------+
//| Global Variables                                  |
//+------------------------------------------------------------------+
struct RANGE_STRUCT{
   datetime start_time;  //start of the range   
   datetime end_time;    // end of the range  
   datetime close_time;  // close of the range  
   double high;          //high of the range  
   double low;           // low of the tange  
   bool f_entry;         //falg if we are inside of the range
   bool f_high_breakout;
   bool f_low_breakout;

   RANGE_STRUCT() : start_time(0), end_time(0), close_time(0), high(0), low(DBL_MAX), f_entry(false), f_high_breakout(false), f_low_breakout(false) {}; 
};

RANGE_STRUCT range;
MqlTick prevTick, lastTick;
CTrade trade;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   // check user inputs
   if(!CheckInputs()) {return INIT_PARAMETERS_INCORRECT;}
   
   // set magicnumber
   trade.SetExpertMagicNumber(InpMagicNumber);
   
   // calculate new range if inputs changed
   if(_UninitReason==REASON_PARAMETERS && CountOpenPositions()==0){  // no position open ++++
      CalculateRange();
   }
   
   DrawObjects();

   return(INIT_SUCCEEDED);
  }
  
  
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){

   //delete objects
   ObjectsDeleteAll(NULL,"range");
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){

   // Get current tick
   prevTick = lastTick;
   SymbolInfoTick(_Symbol, lastTick);

   //range calculation
   if(lastTick.time>= range.start_time && lastTick.time < range.end_time){
      //set flag
      range.f_entry = true;
      // new high 
      if(lastTick.ask > range.high){
         range.high = lastTick.ask;
         DrawObjects();
      }
      // new low 
      if(lastTick.bid < range.low){
         range.low = lastTick.bid;
         DrawObjects();
      }  
   }
   
   //close positions
   if(InpRangeClose>=0 && lastTick.time >= range.close_time){
      if(!ClosePositions()) {return;}
   
   }

   //calculate ne range if
   if(((InpRangeClose>=0 && lastTick.time>=range.close_time)                      //close time reached
      ||(range.f_high_breakout && range.f_low_breakout)                          // both breakout flags are true 
      || range.end_time==0                                                       // range not calculated
      || (range.end_time!=0 && lastTick.time>range.end_time &&!range.f_entry))  //there was a range but no tick inside 
      && CountOpenPositions() ==0){
      
      CalculateRange();     
   }
   
      //check for breakouts
      CheckBreakouts();
}   


// check user inputs
bool CheckInputs(){
   if(InpMagicNumber <= 0){
   Alert("MagicNumber <= 0");
   return false;
   }
   
   if(InpLots <= 0 || InpLots >100){
   Alert("InpLots <= 0 or InpLots >1");
   return false;
   }  
   
   if(InpStopLoss <0 || InpStopLoss >1000){
   Alert("Stop loss < 0 or stop loss > 1000");
   return false;
   }   
   
   if(InpTakeProfit <0 || InpTakeProfit >1000){
   Alert("Take profit < 0 or take profit > 1000");
   return false;
   }   
     
   if(InpRangeClose <0 && InpStopLoss ==0){
   Alert("Close time and stop loss if off");
   return false;
   }      
    
   if(InpRangeStart < 0 || InpRangeStart >=1440){
   Alert("InpRangeStar < 0 or InpRangeStar >1440");
   return false;
   }
   
   if(InpRangeDurration <= 0 || InpRangeDurration >=1440){
   Alert("InpRangeDurration <= 0 or InpRangeDurration >1440");
   return false;
   }
   
   if(InpRangeClose < 0 || InpRangeClose >=1440 || (InpRangeStart+InpRangeDurration)%1440 ==InpRangeClose){
   Alert("InpRangeClose < 0 or InpRangeClose >1440 or ed time == close time");
   return false;
   }

   if(InpMonday+InpTuesday+InpWednesday+InpThursday+InpFriday ==0){
   Alert("Range is prohibited on the week");
   return false;
   }   

   return true;
}

// calculate new range
void CalculateRange()
{
   // reset range variables
   range.start_time = 0;
   range.end_time = 0;
   range.close_time = 0;
   range.high = 0;
   range.low = DBL_MAX;
   range.f_entry = false;
   range.f_high_breakout = false;
   range.f_low_breakout = false;

   // calculate range start time
   int time_cycle = 86400;
   range.start_time = (lastTick.time - (lastTick.time % time_cycle)) + InpRangeStart*60;
   for (int i=0; i<8; i++){
      MqlDateTime tmp;
      TimeToStruct(range.start_time,tmp);
      int dow = tmp.day_of_week; 
      if(lastTick.time>=range.start_time || dow==6 || dow==0 || (dow==1 && !InpMonday) || (dow==2 && !InpThursday) || (dow==3 && !InpWednesday)
       || (dow==4 && !InpThursday)  || (dow==5 && !InpFriday)){
         range.start_time += time_cycle;
      }
    }
    
   // calculate range end time
   range.end_time = range.start_time + InpRangeDurration*60;
   for (int i=0; i<2; i++){
      MqlDateTime tmp;
      TimeToStruct(range.end_time,tmp);
      int dow = tmp.day_of_week;
      if(dow==6 || dow==0){
         range.end_time += time_cycle;
         }
      }

   // calculate range close 
   if(InpRangeClose>=0){
      range.close_time = (range.end_time - (range.end_time % time_cycle)) + InpRangeClose*60;
      for (int i=0; i<3; i++){
         MqlDateTime tmp;
         TimeToStruct(range.close_time,tmp);
         int dow = tmp.day_of_week;
         if(range.close_time<=range.end_time || dow==6 || dow==0){
            range.close_time += time_cycle;
         }
      }
    }
    DrawObjects();
}

// Count all open positions
int CountOpenPositions(){
   
   int counter = 0;
   int total = PositionsTotal();
   for(int i=total-1; i>=0; i--){
      ulong ticket = PositionGetTicket(i);
      if(ticket<=0) {Print("Failed to get position tciket"); return -1;}
      if(!PositionSelectByTicket(ticket)) {Print("Failed to select position by ticket"); return -1;}
      ulong magicnumber;
      if(!PositionGetInteger(POSITION_MAGIC,magicnumber)) {Print("Failed to get postion magicnumber"); return -1;}
      if (InpMagicNumber==magicnumber) {counter++;}
   }

return counter;
}

// Check for breakouts
void CheckBreakouts(){
   
   //check if we are after the range end
   if(lastTick.time >= range.end_time && range.end_time>0 && range.f_entry){
      
      //check for high breakout
      if(!range.f_high_breakout && lastTick.ask >= range.high){
         range.f_high_breakout = true;
         if(InpBreakoutMode==ONE_SIGNAL) {range.f_low_breakout = true;}
         
         //calculate stop loss and take profit
         double sl = InpStopLoss ==0 ? 0 : NormalizeDouble(lastTick.bid - ((range.high-range.low) * InpStopLoss * 0.01), _Digits);
         double tp = InpTakeProfit == 0 ? 0 :  NormalizeDouble(lastTick.bid + InpTakeProfit * _Point, _Digits); 
      
         if (sl != 0 && tp !=0){
            //open buy position
            trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,InpLots,lastTick.ask,sl,tp,"Time range EA");}
      }
    
      //check for low breakout
      if(!range.f_low_breakout && lastTick.bid <= range.low){
         range.f_low_breakout = true;
                  if(InpBreakoutMode==ONE_SIGNAL) {range.f_high_breakout = true;}
         
         //calculate stop loss and take profit
         double sl = InpStopLoss ==0 ? 0 :  NormalizeDouble(lastTick.ask + ((range.high-range.low) * InpStopLoss * 0.01), _Digits);
         double tp = InpTakeProfit == 0 ? 0 : NormalizeDouble(lastTick.ask - InpTakeProfit * _Point, _Digits);
      
      
         if (sl != 0 && tp != 0) {  
         //open sell position
         trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,InpLots,lastTick.bid,sl,tp,"Time range EA");}
      }   
   }
}


// Close all open positions
bool ClosePositions(){

   int total = PositionsTotal();
   for(int i=total-1; i>=0; i--){
      if(total!=PositionsTotal()) {total=PositionsTotal(); i=total; continue;}
      ulong ticket = PositionGetTicket(i);   //Select position
      if(ticket<=0) {Print("Failed to get postion ticket"); return false;}
      if(!PositionSelectByTicket(ticket)) {Print("Failed to select position by ticket"); return false;}
      long magicnumber;
      if(!PositionGetInteger(POSITION_MAGIC,magicnumber)) {Print("Failed to get position number"); return false;}
      if(magicnumber == InpMagicNumber){
         trade.PositionClose(ticket);
         if(trade.ResultRetcode() !=TRADE_RETCODE_DONE){
         Print("Failed to close position. Result: "+(string)trade.ResultRetcode()+":"+trade.ResultRetcodeDescription());
         return false;
         }           
      }
   }      

   return true;
}


//Draw chart objects
void DrawObjects()
{
   //start time
   ObjectDelete(NULL,"range start");
   if(range.start_time>0){
      ObjectCreate(NULL,"range start",OBJ_VLINE,0,range.start_time,0);
      ObjectSetString(NULL,"range start", OBJPROP_TOOLTIP,"start of the range \n"+TimeToString(range.start_time,TIME_DATE|TIME_MINUTES));
      ObjectSetInteger(NULL,"range start",OBJPROP_COLOR,clrOrange);
      ObjectSetInteger(NULL,"range start",OBJPROP_WIDTH,2);
      ObjectSetInteger(NULL,"range start",OBJPROP_BACK,true);
   }
   //end time 
   ObjectDelete(NULL,"range end");
   if(range.end_time>0){
      ObjectCreate(NULL,"range end",OBJ_VLINE,0,range.end_time,0);
      ObjectSetString(NULL,"range end", OBJPROP_TOOLTIP,"end of the range \n"+TimeToString(range.end_time,TIME_DATE|TIME_MINUTES));
      ObjectSetInteger(NULL,"range end",OBJPROP_COLOR,clrOrange);
      ObjectSetInteger(NULL,"range end",OBJPROP_WIDTH,2);
      ObjectSetInteger(NULL,"range end",OBJPROP_BACK,true);
   }
   //close time 
   ObjectDelete(NULL,"range close");
   if(range.close_time>0){
      ObjectCreate(NULL,"range close",OBJ_VLINE,0,range.close_time,0);
      ObjectSetString(NULL,"range close", OBJPROP_TOOLTIP,"close of the range \n"+TimeToString(range.close_time,TIME_DATE|TIME_MINUTES));
      ObjectSetInteger(NULL,"range close",OBJPROP_COLOR,clrRed);
      ObjectSetInteger(NULL,"range close",OBJPROP_WIDTH,2);
      ObjectSetInteger(NULL,"range close",OBJPROP_BACK,true);
   }
   
   //high 
   ObjectsDeleteAll(NULL,"range high");
   if(range.high>0){
      ObjectCreate(NULL,"range high",OBJ_TREND,0,range.start_time,range.high,range.end_time,range.high);
      ObjectSetString(NULL,"range high", OBJPROP_TOOLTIP,"high of the range \n"+DoubleToString(range.high,_Digits));
      ObjectSetInteger(NULL,"range high",OBJPROP_COLOR,clrOrange);
      ObjectSetInteger(NULL,"range high",OBJPROP_WIDTH,2);
      ObjectSetInteger(NULL,"range high",OBJPROP_BACK,true);

      ObjectCreate(NULL,"range high ",OBJ_TREND,0,range.end_time,range.high,range.close_time,range.high);
      ObjectSetString(NULL,"range high ", OBJPROP_TOOLTIP,"high of the range \n"+DoubleToString(range.high,_Digits));
      ObjectSetInteger(NULL,"range high ",OBJPROP_COLOR,clrOrange);
      ObjectSetInteger(NULL,"range high ",OBJPROP_BACK,true);
      ObjectSetInteger(NULL,"range high ",OBJPROP_STYLE,STYLE_DOT);
   }

   //low 
   ObjectsDeleteAll(NULL,"range low");
   if(range.low<DBL_MAX){
      ObjectCreate(NULL,"range low",OBJ_TREND,0,range.start_time,range.low,range.end_time,range.low);
      ObjectSetString(NULL,"range low", OBJPROP_TOOLTIP,"low of the range \n"+DoubleToString(range.low,_Digits));
      ObjectSetInteger(NULL,"range low",OBJPROP_COLOR,clrOrange);
      ObjectSetInteger(NULL,"range low",OBJPROP_WIDTH,2);
      ObjectSetInteger(NULL,"range low",OBJPROP_BACK,true);
      
      ObjectCreate(NULL,"range low ",OBJ_TREND,0,range.end_time,range.low,range.close_time,range.low);
      ObjectSetString(NULL,"range low ", OBJPROP_TOOLTIP,"low of the range \n"+DoubleToString(range.low,_Digits));
      ObjectSetInteger(NULL,"range low ",OBJPROP_COLOR,clrOrange);
      ObjectSetInteger(NULL,"range low ",OBJPROP_BACK,true);
      ObjectSetInteger(NULL,"range low ",OBJPROP_STYLE,STYLE_DOT);
   }
   
   // refresh charts
   ChartRedraw();

}