//+------------------------------------------------------------------+
//|                                        Range Break Indicator.mq4 |
//|                                         Copyright 2018, Odera FX |
//|                                              chidera67@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, Odera FX"
#property link      "chidera67@gmail.com"
#property version   "1.03"
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 clrBlue
#property indicator_color2 clrRed
#property indicator_type1 DRAW_ARROW
#property indicator_type2 DRAW_ARROW

enum ENUM_GAP
  { OFF, //Off
    ON,  //On
    GAP, //Gap
    OVERLAP //Overlap
   
  };

enum ENUM_FILTER
  {NONE,                 //NONE Applied
   RETRACE_BY_PIPS1,     //Retrace by pips (Previous bar open)
   RETRACE_TO_OPEN,      //Retrace to Open
   RETRACE_BY_PIPS0      //Retrace to By Pips (Current bar open)
  };
  
input color                BuyCol         = clrBlue;                              //Buy Marker Color
input color                SellCol        = clrRed;                               //Sell Marker Color
input int                  dist           = 0;                                    //Arrow Distance
input string               hint0          = "----------Filter Settings--------";  //Filter Settings
input int                  TimeFilterSecs = 60;                                   //Time Filter Seconds
input ENUM_FILTER          RetraceFilter  = NONE;                                 //Retracement Filter
input int                  RetracePips    = 20;                                   //Retracement Pips
input string               hint           = "---------Gap Filter Settings------"; //Gap Filter Settings
input ENUM_GAP             GapType        = OFF;                                  //Gap Filter Type
input int                  GapMaxPips     = 50;                                   //Max Allowed Gap Size


double Buy[],Sell[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   SetIndexBuffer(0,Buy);
   SetIndexArrow(0,233);
   
   SetIndexBuffer(1,Sell);
   SetIndexArrow(1,234);
//--- indicator buffers mapping
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
   //bool newbar = false;
   static bool inplay = false;
//---
   if (prev_calculated > 3)
   {if (rates_total > prev_calculated) 
    {//newbar = true;
     inplay = false;
    }
    if (open[1] > close [1]) //if the last bar is a bear bar
    {//if (!IsEqual(close[1],open[0]))
     {if (Gapped(open[0],close[1])) return(rates_total);
      if (Bid > open[1]) //price has broken previous bar open
      {if (!Expired())
       {if (RetraceFilter == NONE)
        {Buy[0] = low[0] - (dist*_Point);
         PlaceMarker(0,OP_BUY);
        }
        else 
        inplay = true;
       }
      }
      if (inplay && !Expired())
      {if (RetraceFilter == RETRACE_BY_PIPS1)
       {if (Bid <= open[1] - (RetracePips * _Point))
        {Buy[0] = low[0] - (dist*_Point);
         PlaceMarker(0,OP_BUY);
        }
       }
       else if (RetraceFilter == RETRACE_BY_PIPS0)
       {if (Bid <= open[0] - (RetracePips * _Point))
        {Buy[0] = low[0] - (dist*_Point);
         PlaceMarker(0,OP_BUY);
        }
       }
       else if (RetraceFilter == RETRACE_TO_OPEN)
       {if (Bid <= open[0])
        {Buy[0] = low[0] - (dist*_Point);
         PlaceMarker(0,OP_BUY);
        }
       }
      }
     }
    }
    else if (open[1] < close[1]) // if the bar is a bull bar
    {//if (!IsEqual(close[1],open[0]))
     {if (Gapped(open[0],close[1])) return(rates_total);
      if (Bid < open[1]) //price has broken previous bar open
      {if (!Expired())
       {if (RetraceFilter == NONE)
        {Sell[0] = high[0] + (dist*_Point);
         PlaceMarker(0,OP_SELL);
        }
        else 
        inplay = true;
       }
      }
      if (inplay && !Expired())
      {if (RetraceFilter == RETRACE_BY_PIPS1)
       {if (Bid >= open[1] + (RetracePips * _Point))
        {Sell[0] = high[0] + (dist*_Point);
         PlaceMarker(0,OP_SELL);
        }
       }
       else if (RetraceFilter == RETRACE_BY_PIPS0)
       {if (Bid >= open[0] + (RetracePips * _Point))
        {Sell[0] = high[0] + (dist*_Point);
         PlaceMarker(0,OP_SELL);
        }
       }
       else if (RetraceFilter == RETRACE_TO_OPEN)
       {if (Bid >= open[0])
        {Sell[0] = high[0] + (dist*_Point);
         PlaceMarker(0,OP_SELL);
        }
       }
      }
     }
    }
   }
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
void OnDeinit(const int reason)
  {ObjectsDeleteAll(0,"RBI");
   
  }
//+------------------------------------------------------------------+
void PlaceMarker(int shift,int type)
{string name = "RBI Marker "+TimeToString(Time[shift],TIME_DATE|TIME_MINUTES);
 color marcol = (type == OP_BUY)? BuyCol:SellCol;
 if (ObjectFind(0,name) < 0) 
 {ObjectCreate(0,name,OBJ_TREND,0,Time[shift+1],Bid,Time[shift]+PeriodSeconds(),Bid);
  ObjectSetDouble(0,name,OBJPROP_PRICE1,Bid);
  ObjectSetDouble(0,name,OBJPROP_PRICE2,Bid);
  ObjectSetInteger(0,name,OBJPROP_RAY,false);
  ObjectSetInteger(0,name,OBJPROP_WIDTH,2);
  ObjectSetInteger(0,name,OBJPROP_COLOR,marcol);
  ChartRedraw();
 }
}
bool IsEqual(double number1,double number2)
  {
   if(NormalizeDouble(number1-number2,8)==0) return(true);
   else return(false);
  }
bool Gapped(double open0, double close1)
{if (GapType == OFF) return false;
 if (IsEqual(close1,open0)) return false;
 if (GapType == ON)
 {if (fabs(open0-close1) > GapMaxPips*_Point) return true;
  else return false;
 }
 else if (GapType == GAP) //in the direction
 {if (Open[1] > Close[1]) //bear bar
  {if (close1 - open0 > GapMaxPips*_Point) return true;
   else return false;
  }
  else if (Open[1] < Close[1]) //bull bar
  {if (open0 - close1 > GapMaxPips*_Point) return true;
   else return false;
  }
 }
 else if (GapType == OVERLAP)// open0 < close1
 {if (Open[1] > Close[1]) // bear bar
  {if (open0 - close1 > GapMaxPips*_Point) return true;
   else return false;
  }
  else if (Open[1] < Close[1]) //bull bar
  {if (open0 - close1 > GapMaxPips*_Point) return true;
   else return false;
  }
 }
 return false;
}
bool Expired()
{long secelapsed =(long) TimeCurrent() - Time[0];
 if (secelapsed < TimeFilterSecs) return false;
 return true;
}
          