//+------------------------------------------------------------------+
//|                               !!!-MT5 X-XARDg-INSIDE BAR stops button 1.03.mq5 |
//|                                                                  |
//|                                                                  |
//+------------------------------------------------------------------+
#property description "[!!!-MT5 X-XARDg-INSIDE BAR]"
#define Version "[XARDg-INSIDE BAR]"
//+------------------------------------------------------------------------------------------------------------------+
#property link        "https://forex-station.com/viewtopic.php?p=1295409935#p1295409935"
#property description "THIS IS A FREE INDICATOR"
#property description "                                                      "
#property description "Welcome to the World of Forex"
#property description "Let light shine out of darkness and illuminate your world"
#property description "and with this freedom leave behind your cave of denial"
#property version       "1.03"
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots 3

#property indicator_type1   DRAW_ARROW
#property indicator_color1  C'246,103,83'
#property indicator_width1  2

#property indicator_type2   DRAW_ARROW
#property indicator_color2  C'246,103,83'
#property indicator_width2  2

#property indicator_type3   DRAW_ARROW
#property indicator_color3  clrDimGray
#property indicator_width3  0

input string Indicator=Version;
//+------------------------------------------------------------------------------------------------------------------+
input ENUM_TIMEFRAMES    TF_find_in            = PERIOD_H4;   
input string             note1                 = "------------------------------";
input color              UpperLineColor        = C'246,103,83';
input color              MiddleLineColor       = clrDimGray; 
input color              LowerLineColor        = C'246,103,83';
input int                UpperLineWidth        = 2;
input int                MiddleLineWidth       = 0;
input int                LowerLineWidth        = 2;
input int                UpperLineCode         = 251; 
input int                MiddleLineCode        = 251; 
input int                LowerLineCode         = 251; 

input string             button_note1          = "------------------------------";
input ENUM_BASE_CORNER   btn_corner            = CORNER_LEFT_UPPER; 
input string             btn_text              = "IB";              
input string             btn_Font              = "Arial";
input int                btn_FontSize          = 10;                
input color              btn_text_ON_color     = clrWhite;
input color              btn_text_OFF_color    = clrRed;
input color              btn_background_color  = clrDimGray;
input color              btn_border_color      = clrBlack;
input int                button_x              = 140;               
input int                button_y              = 33;                
input int                btn_Width             = 60;                
input int                btn_Height            = 20;                
input string             button_note2          = "------------------------------";

bool                      show_data             = true;
string IndicatorName, IndicatorObjPrefix;

bool showInsideBar=true;
double HighBuff[],LowBuff[],MidBuff[],LastHigh,LastLow; 
int length=5,len=0,Type;
ENUM_TIMEFRAMES TF_find;
string buttonId;
bool recalc = true;

//+------------------------------------------------------------------------------------------------------------------+
string GenerateIndicatorName(const string target)
{
   string name = target;
   int tryNum = 2;
   while (ChartWindowFind(0, name) != -1)
   {
      name = target + " #" + IntegerToString(tryNum++);
   }
   return name;
}

//+------------------------------------------------------------------------------------------------------------------+
void createButton(string buttonID,string buttonText,int width,int height,string font,int fontSize,color bgColor,color borderColor,color txtColor)
{
   ObjectDelete    (0,buttonID);
   ObjectCreate    (0,buttonID,OBJ_BUTTON,0,0,0);
   ObjectSetInteger(0,buttonID,OBJPROP_COLOR,txtColor);
   ObjectSetInteger(0,buttonID,OBJPROP_BGCOLOR,bgColor);
   ObjectSetInteger(0,buttonID,OBJPROP_BORDER_COLOR,borderColor);
   ObjectSetInteger(0,buttonID,OBJPROP_XSIZE,width);
   ObjectSetInteger(0,buttonID,OBJPROP_YSIZE,height);
   ObjectSetString (0,buttonID,OBJPROP_FONT,font);
   ObjectSetString (0,buttonID,OBJPROP_TEXT,buttonText);
   ObjectSetInteger(0,buttonID,OBJPROP_FONTSIZE,fontSize);
   ObjectSetInteger(0,buttonID,OBJPROP_SELECTABLE,0);
   ObjectSetInteger(0,buttonID,OBJPROP_CORNER,btn_corner);
   ObjectSetInteger(0,buttonID,OBJPROP_HIDDEN,1);
   ObjectSetInteger(0,buttonID,OBJPROP_XDISTANCE,9999);
   ObjectSetInteger(0,buttonID,OBJPROP_YDISTANCE,9999);
}

//+------------------------------------------------------------------------------------------------------------------+
void updatePlotTypes()
{
   if (show_data && Type != DRAW_NONE)
   {
      ObjectSetInteger(0,buttonId,OBJPROP_COLOR,btn_text_ON_color);
      PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_ARROW);
      PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_ARROW);
      PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_ARROW);
   }
   else if (show_data)
   {
      ObjectSetInteger(0,buttonId,OBJPROP_COLOR,btn_text_ON_color);
      PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_NONE);
      PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_NONE);
      PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_NONE);
   }
   else
   {
      ObjectSetInteger(0,buttonId,OBJPROP_COLOR,btn_text_OFF_color);
      PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_NONE);
      PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_NONE);
      PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_NONE);
   }
}

//+------------------------------------------------------------------------------------------------------------------+
int init2()
{
   if(showInsideBar) Type=DRAW_ARROW; else Type=DRAW_NONE;

   SetIndexBuffer(0,HighBuff,INDICATOR_DATA); 
   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,Type);
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,UpperLineWidth);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,UpperLineColor);
   PlotIndexSetInteger(0,PLOT_ARROW,UpperLineCode);
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);

   SetIndexBuffer(1,LowBuff,INDICATOR_DATA);  
   PlotIndexSetInteger(1,PLOT_DRAW_TYPE,Type);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,LowerLineWidth);
   PlotIndexSetInteger(1,PLOT_LINE_COLOR,LowerLineColor);
   PlotIndexSetInteger(1,PLOT_ARROW,LowerLineCode);
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,EMPTY_VALUE);

   SetIndexBuffer(2,MidBuff,INDICATOR_DATA);  
   PlotIndexSetInteger(2,PLOT_DRAW_TYPE,Type);
   PlotIndexSetInteger(2,PLOT_LINE_WIDTH,MiddleLineWidth);
   PlotIndexSetInteger(2,PLOT_LINE_COLOR,MiddleLineColor);
   PlotIndexSetInteger(2,PLOT_ARROW,MiddleLineCode);
   PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,EMPTY_VALUE);

   ArrayInitialize(HighBuff,EMPTY_VALUE); 
   ArrayInitialize(LowBuff,EMPTY_VALUE);
   ArrayInitialize(MidBuff,EMPTY_VALUE);
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------------------------------------------------------+
int OnInit()
{
   TF_find = TF_find_in;
   if(TF_find==PERIOD_CURRENT) TF_find=_Period;

   IndicatorName = GenerateIndicatorName(btn_text);
   IndicatorObjPrefix = "__" + IndicatorName + "__";
   IndicatorSetString(INDICATOR_SHORTNAME, IndicatorName);
   IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
   
   double val;
   if (GlobalVariableGet(IndicatorName + "_visibility", val))
      show_data = val != 0;

   buttonId = IndicatorObjPrefix + "InsideBar2020";
   createButton(buttonId, btn_text, btn_Width, btn_Height, btn_Font, btn_FontSize, btn_background_color, btn_border_color, btn_text_ON_color);
   ObjectSetInteger(0, buttonId, OBJPROP_YDISTANCE, button_y);
   ObjectSetInteger(0, buttonId, OBJPROP_XDISTANCE, button_x);

   init2();
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0, IndicatorObjPrefix);
}

//+------------------------------------------------------------------------------------------------------------------+
void handleButtonClicks()
{
   show_data = !show_data;
   GlobalVariableSet(IndicatorName + "_visibility", show_data ? 1.0 : 0.0);
   recalc = true;
   updatePlotTypes();
   ChartRedraw();
   
   ObjectSetInteger(0, buttonId, OBJPROP_STATE, false);
}

//+------------------------------------------------------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   if (id == CHARTEVENT_OBJECT_CLICK && sparam == buttonId)
   {
      handleButtonClicks();
   }
}

//+------------------------------------------------------------------------------------------------------------------+
int start2(int rates_total, int prev_calculated, const datetime &time[])
{
   int limit=0;  
   if(prev_calculated == 0 || recalc)
   {
      ArrayInitialize(HighBuff,EMPTY_VALUE); 
      ArrayInitialize(LowBuff,EMPTY_VALUE);
      ArrayInitialize(MidBuff,EMPTY_VALUE);
      limit=iBars(_Symbol,TF_find)-2;
      len=0;
   }
   else
   {
      limit=length + 5;
      if(limit > iBars(_Symbol,TF_find)-2) limit = iBars(_Symbol,TF_find)-2;
      
      // Initialize state by searching backwards for any active inside bar prior to limit
      len=0;
      int total_bars = iBars(_Symbol,TF_find);
      for(int j = limit + 1; j <= limit + length; j++)
      {
         if(j + 1 >= total_bars) break;
         double iLow_j = iLow(_Symbol,TF_find,j);
         double iLow_j1 = iLow(_Symbol,TF_find,j+1);
         double iHigh_j = iHigh(_Symbol,TF_find,j);
         double iHigh_j1 = iHigh(_Symbol,TF_find,j+1);
         
         if(iLow_j > iLow_j1 && 
            iHigh_j < iHigh_j1 && 
            iHigh_j - iLow_j > _Point/2)
         {
            LastHigh = iHigh_j;
            LastLow = iLow_j;
            len = j - limit;
            break;
         }
      }
      
      datetime time_limit = iTime(_Symbol,TF_find,limit);
      if(time_limit > 0)
      {
         int bar_now_limit = iBarShift(_Symbol,_Period,time_limit,false);
         if(bar_now_limit >= 0 && bar_now_limit < rates_total)
         {
            for(int k = 0; k <= bar_now_limit; k++)
            {
               HighBuff[k] = EMPTY_VALUE;
               LowBuff[k] = EMPTY_VALUE;
               MidBuff[k] = EMPTY_VALUE;
            }
         }
      }
   }
   for(int i=limit; i>=0; i--)
   {
      datetime time1=iTime(_Symbol,TF_find,i);
      if(time1 == 0) continue;
      datetime time2=time1+PeriodSeconds(TF_find);
      int bar_now=iBarShift(_Symbol,_Period,time1,false);
      
      if(bar_now < 0) continue;
      
      // Fix for when time1 falls between bars on lower timeframe
      while(bar_now >= 0 && time[bar_now] < time1)
      {
         bar_now--;
      }
      if(bar_now < 0) continue;
      
      if(i + 1 >= iBars(_Symbol, TF_find)) continue;

      // Only search for inside bars on completed/closed HTF bars (i > 0)
      bool is_inside_bar = false;
      if(i > 0)
      {
         double iLow_i = iLow(_Symbol,TF_find,i);
         double iLow_i1 = iLow(_Symbol,TF_find,i+1);
         double iHigh_i = iHigh(_Symbol,TF_find,i);
         double iHigh_i1 = iHigh(_Symbol,TF_find,i+1);
         
         if(iLow_i > iLow_i1 && 
            iHigh_i < iHigh_i1 && 
            iHigh_i - iLow_i > _Point/2)
         {
            is_inside_bar = true;
         }
      }
      
      if(is_inside_bar)
      {
         double iLow_i = iLow(_Symbol,TF_find,i);
         double iHigh_i = iHigh(_Symbol,TF_find,i);
         LastHigh = iHigh_i; 
         LastLow = iLow_i; 
         len=1;
         
         if(bar_now < rates_total-3 && 
            ((HighBuff[bar_now+1]!=LastHigh && HighBuff[bar_now+2]!=EMPTY_VALUE) ||
             (LowBuff[bar_now+1]!=LastLow && LowBuff[bar_now+2]!=EMPTY_VALUE)))
         {
            HighBuff[bar_now+1] = EMPTY_VALUE;
            LowBuff[bar_now+1] = EMPTY_VALUE;
         }
            
         while (bar_now < rates_total-2 && time[bar_now]>=time1 && time[bar_now]<time2)
         {
            HighBuff[bar_now] = LastHigh;
            LowBuff[bar_now] = LastLow; 
            MidBuff[bar_now]=(HighBuff[bar_now]+LowBuff[bar_now])/2;
            bar_now--;
            if (bar_now < 0) break;
         }
      } 
      else 
      {
         if(len>0 && len<length)
         {
            while (bar_now < rates_total-2 && time[bar_now]>=time1 && time[bar_now]<time2)
            {
               HighBuff[bar_now] = LastHigh;
               LowBuff[bar_now] = LastLow; 
               MidBuff[bar_now]=(HighBuff[bar_now]+LowBuff[bar_now])/2; 
               bar_now--;
               if (bar_now < 0) break;
            }  
            len++;
         } 
         else if(len>=length)
         {
            len=0;
            if(bar_now >= 0 && bar_now < rates_total)
            {
               HighBuff[bar_now] = EMPTY_VALUE;
               LowBuff[bar_now] = EMPTY_VALUE;
               MidBuff[bar_now]=(HighBuff[bar_now]+LowBuff[bar_now])/2;
            }
         }
      }
   }  
   return(0);
}

//+------------------------------------------------------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   if (rates_total < 2) return 0;
   if (iBars(_Symbol, TF_find) < 2) return 0; 

   ArraySetAsSeries(time, true);
   ArraySetAsSeries(HighBuff, true);
   ArraySetAsSeries(LowBuff, true);
   ArraySetAsSeries(MidBuff, true);

   if (recalc || prev_calculated == 0)
   {
       start2(rates_total, prev_calculated, time);
       updatePlotTypes();
       recalc = false;
   }
   else 
   {
       start2(rates_total, prev_calculated, time);
   }

   return rates_total;
}
