#property indicator_chart_window
#property indicator_buffers 1

#property indicator_color1 clrRed      // WRB symbol
#property indicator_width1 1

#define UNFILLED_PREFIX "HG_UNFILLED_"
#define FILLED_PREFIX "HG_FILLED_"
#define PREFIX "HG_"

extern bool UseWholeBars = true;
extern int WRB_LookBackBarCount = 3;
extern int WRB_WingDingsSymbol = 108;
extern color HGcolor1 = clrNONE;
extern color HGcolor2 = clrNONE;
extern ENUM_LINE_STYLE HGstyle = STYLE_SOLID;
extern int StartCalculationFromBar = 1000;
extern bool HollowBoxes = false;
extern bool DoAlerts = false;
//---- buffers
double WRB[];

int totalBarCount = -1;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
   //---- indicators
   IndicatorBuffers(1);
   IndicatorShortName("WRB+HG");
   
   SetIndexStyle(0, DRAW_ARROW); 
   SetIndexArrow(0, WRB_WingDingsSymbol); 
   SetIndexLabel(0, "WRB");
   SetIndexBuffer(0, WRB); 
   ArrayInitialize(WRB, EMPTY_VALUE);
   return(0);
}
  

//+------------------------------------------------------------------+
//| Delete all objects with given prefix                             |
//+------------------------------------------------------------------+
void ObDeleteObjectsByPrefix(string Prefix)
{
   int L = StringLen(Prefix);
   int i = 0; 
   while(i < ObjectsTotal())
   {
       string ObjName = ObjectName(i);
       if(StringSubstr(ObjName, 0, L) != Prefix) 
       { 
           i++; 
           continue;
       }
       ObjectDelete(ObjName);
   }
}


//+------------------------------------------------------------------+
//|  intersect: Check two bars intersect or not                      |
//+------------------------------------------------------------------+
int intersect(double H1, double L1, double H2, double L2)
{
   if ( (L1>H2) || (H1<L2) ) return (0);
   if ( (H1>=H2) && (L1>=L2) ) return (1);
   if ( (H1<=H2) && (L1<=L2) ) return (2);
   if ( (H1>=H2) && (L1<=L2) ) return (3);
   if ( (H1<=H2) && (L1>=L2) ) return (4);
//   return(0);
}  
  
//+------------------------------------------------------------------+
//|  checkHGFilled: Check if the hidden gap is filled or not         |
//+------------------------------------------------------------------+
void checkHGFilled(int barNumber)
{
   int j, i;
   string ObjectText;
   string Prefix = UNFILLED_PREFIX;
   double box_H, box_L;
   double HGFillPA_H, HGFillPA_L;
   datetime startTime;
   color objectColor;

   int L = StringLen(Prefix);
   i = 0; 
   while(i < ObjectsTotal()) // loop over all unfilled boxes
   {
       string ObjName = ObjectName(i);
       if(StringSubstr(ObjName, 0, L) != Prefix) 
       { 
           i++; 
           continue;
       }
       box_H=ObjectGet(ObjName, OBJPROP_PRICE1); // get HG high and low values
       box_L=ObjectGet(ObjName, OBJPROP_PRICE2);
       objectColor=ObjectGet(ObjName, OBJPROP_COLOR);
       startTime=ObjectGet(ObjName, OBJPROP_TIME1);
              
       HGFillPA_H = High[barNumber];
       HGFillPA_L = Low[barNumber];
       j = 0;
       while ( (intersect(High[barNumber+j], Low[barNumber+j], box_H, box_L)!=0) && (barNumber+j<Bars) && (startTime<Time[barNumber+j]))
       {
         if (High[barNumber+j] > HGFillPA_H)  HGFillPA_H = High[barNumber+j];
         if (Low[barNumber+j]  < HGFillPA_L)  HGFillPA_L = Low[barNumber+j];
         if ( (HGFillPA_H>box_H) && (HGFillPA_L<box_L) )
         {
            ObjectDelete(ObjName);
                        
            ObjectText = FILLED_PREFIX + TimeToStr(startTime,TIME_DATE|TIME_MINUTES);            
            ObjectCreate(ObjectText, OBJ_RECTANGLE, 0, startTime, box_H, Time[barNumber], box_L);
            ObjectSet(ObjectText, OBJPROP_STYLE, HGstyle);
            ObjectSet(ObjectText, OBJPROP_COLOR, objectColor);
            ObjectSet(ObjectText, OBJPROP_BACK, !HollowBoxes);
            break;
         }
         j++;
       }
       
       i++;
   }

}


//+------------------------------------------------------------------+
//| checkWRB: Check if the given bar is a WRB or not                 |
//| The lookback period can be changed by user input                 |
//+------------------------------------------------------------------+
bool checkWRB(int i)
{
      int j;
      bool WRB_test;
      double body, bodyPrior;
      
      WRB_test = true;
      if (UseWholeBars) body = High[i] - Low[i];
      else body = MathAbs(Open[i] - Close[i]);
      for (j = 1;j <= WRB_LookBackBarCount; j++)
      {
        if (UseWholeBars) bodyPrior = High[i + j] - Low[i + j];
        else bodyPrior = MathAbs(Open[i+j]-Close[i+j]);
        if (bodyPrior>body)
        {
           WRB_test = false;
           break;
        }            
      }
         
      if (WRB_test)
      {
         if (UseWholeBars) WRB[i] = (High[i] + Low[i]) / 2;
         else WRB[i] = (Open[i] + Close[i]) / 2;
      }
      else WRB[i] = EMPTY_VALUE;

      return(WRB_test);
}

//+------------------------------------------------------------------+
//| checkHG: Checks HG status of the previous bar.                   |
//+------------------------------------------------------------------+
void checkHG(int i)
{
   string ObjectText;
   double H,L,H2,L2,H1,L1,A,B;
   int j;
   color HGcolor=HGcolor1;

   // HG-TEST ( test the previous bar i+1)
   if (WRB[i+1]!=EMPTY_VALUE) // First rule to become a HG is to become a WRB
   {
      H2 = High[i+2];
      L2 = Low[i+2];
      H1 = High[i];
      L1 = Low[i];
            
      if (UseWholeBars)
      {
         H = High[i + 1];
         L = Low[i + 1];
      }
      else if (Open[i+1]>Close[i+1])
      {
         H = Open[i+1];
         L = Close[i+1];
      }
      else
      {
         H = Close[i+1];
         L = Open[i+1];
      }
      
      // Older bar higher than the newer.
      if (L2 > H1)
      {
         A = MathMin(L2, H);
         B = MathMax(H1, L);
      }
      else if (L1 > H2)
      {
         A = MathMin(L1, H);
         B = MathMax(H2, L);
      }
      else return;
           
      if (A > B)
      {
         int Length = StringLen(UNFILLED_PREFIX);
         j = 0; 
         while(j < ObjectsTotal()) // loop over all unfilled boxes
         {
             ObjectText = ObjectName(j);
             if(StringSubstr(ObjectText, 0, Length) != UNFILLED_PREFIX) 
             { 
                 j++; 
                 continue;
             }
             // Switch colors if the new Hidden Gap is intersecting with previous Hidden Gap.
             if (intersect(ObjectGet(ObjectText, OBJPROP_PRICE1),ObjectGet(ObjectText, OBJPROP_PRICE2),A,B)!=0)
             {
               HGcolor = ObjectGet(ObjectText, OBJPROP_COLOR);
               if (HGcolor==HGcolor1) HGcolor=HGcolor2;
               else HGcolor=HGcolor1;               
               break;
             }
             j++;
         }
      
         ObjectText = UNFILLED_PREFIX + TimeToStr(Time[i+1],TIME_DATE|TIME_MINUTES);
         ObjectCreate(ObjectText, OBJ_RECTANGLE, 0, Time[i+1], A, TimeCurrent() + 10 * 365 * 24 * 60 * 60, B);
         ObjectSet(ObjectText, OBJPROP_STYLE, HGstyle);
         ObjectSet(ObjectText, OBJPROP_COLOR, HGcolor);
         ObjectSet(ObjectText, OBJPROP_BACK, !HollowBoxes);               
      }
   } //End of HG-Test
}
    
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
{
   ObDeleteObjectsByPrefix(PREFIX);
   return(0);
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
void start()
{
   if (DoAlerts) CheckAlert();
   
   // A new bar started.
   if (totalBarCount != Bars)
   {
      int begin = Bars - IndicatorCounted();
      // Need at least WRB_LookBackBarCount bars from the end of the chart to work.
      if (begin > Bars - WRB_LookBackBarCount) begin = Bars - WRB_LookBackBarCount;
      // Maximum number of bars to calculate is StartCalculationFromBar.
      if (begin > StartCalculationFromBar) begin = StartCalculationFromBar;
      
      for (int i = begin; i > 0; i--)
      {
         checkWRB(i);
         checkHG(i);
         checkHGFilled(i);
      }
      totalBarCount = Bars;
   }
   // Additional check to see if current bar made the Hidden Gap filled.
   checkHGFilled(0);
   WRB[0] = EMPTY_VALUE;
}

void CheckAlert()
{
   int total = ObjectsTotal();
   // Loop over all unfilled boxes.
   for (int j = 0; j < total; j++)
   {
      string ObjectText = ObjectName(j);
      // Object marked as alerted.
      if (StringSubstr(ObjectText, StringLen(ObjectText) - 1, 1) == "A")
      {
         // Try to find a dupe object (could be result of a bug) and delete it.
         string ObjectNameWithoutA = StringSubstr(ObjectText, 0, StringLen(ObjectText) - 1);
         if (ObjectFind(ObjectNameWithoutA) >= 0) ObjectDelete(ObjectNameWithoutA);
         continue;
      }
      int Length = StringLen(UNFILLED_PREFIX);
      if (StringSubstr(ObjectText, 0, Length) != UNFILLED_PREFIX) continue;
      
      double Price1 = ObjectGet(ObjectText, OBJPROP_PRICE1);
      double Price2 = ObjectGet(ObjectText, OBJPROP_PRICE2);
      double bHigh = MathMax(Price1, Price2);
      double bLow = MathMin(Price1, Price2);
      
      // Current price above lower border
      if ((Ask > bLow) && (Bid < bHigh))
      {
         Alert(Symbol() + ": " + "WRB rectangle breached.");
         PlaySound("alert.wav");
         ObjectSetString(0, ObjectText, OBJPROP_NAME, ObjectText + "A");
         return;
      }
   }
}
//+------------------------------------------------------------------+