//+------------------------------------------------------------------+
//|                                                     OB ident.mq4 |
//+------------------------------------------------------------------+

#property indicator_chart_window

extern double   MinBarHeight       = 150;
extern double   MaxBarHeight       = 1500;
extern double   CloseWithinXpct    = 25;
extern double   MinBodyPct         = 25;
extern bool     MustFollowOppColor = false;
extern int      EngulfMarginPct    = 100;
extern int      EngulfTolerance    = 20;
extern int      StartHour          = 0;
extern int      EndHour            = 23;

string   ccy;
int      dig, spr, tf;
double   pnt;
datetime prev_time;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()  {

  ccy = Symbol();
  tf  = Period();
  pnt = MarketInfo(ccy,MODE_POINT);
  dig = MarketInfo(ccy,MODE_DIGITS);
  spr = MarketInfo(ccy,MODE_SPREAD);

//  Comment("pnt=" + pnt + "    dig=" + dig + "    spr=" + spr);

  del_obj();
  plot_obj();    
  prev_time = -9999;
  return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()  {
  del_obj();
  return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start() {
  if(prev_time != Time[0])  {
    del_obj();
    plot_obj();    
  }  
  prev_time = Time[0];
  return(0);
}

//+------------------------------------------------------------------+
void del_obj()   {
  for(int i=ObjectsTotal()-1; i>=0; i--)  {
    string objname = ObjectName(i);
    if (ObjectType(objname) == OBJ_ARROW && StringSubstr(objname,0,4) == "obid")   ObjectDelete(objname);
  }  
  return(0);
} 

//+------------------------------------------------------------------+
void plot_obj()   {

  int valid;
  for (int i=1; i<=Bars-1; i++)  {
    int hr = TimeHour(Time[i]);
    if (hr < StartHour || hr > EndHour)  continue;
    bool OutsideBar = true;
    if (High[i] < High[i+1] || Low[i] > Low[i+1])   OutsideBar = false;                                // not an OB

    bool EngulfBody = true;
    if (EngulfTolerance < 0)   
      EngulfBody = false;
    else  {
      double HiOCcurr = MathMax(Open[i], Close[i]);
      double LoOCcurr = MathMin(Open[i], Close[i]);
      double HiOCprev = MathMax(Open[i+1], Close[i+1]);
      double LoOCprev = MathMin(Open[i+1], Close[i+1]);
      if ((HiOCcurr - LoOCcurr) < (HiOCprev - LoOCprev) * EngulfMarginPct /100 )   EngulfBody = false;                                                // not an engulfing body
      if (HiOCcurr < HiOCprev - EngulfTolerance*pnt || LoOCcurr > LoOCprev + EngulfTolerance*pnt)  EngulfBody = false;    // not an engulfing body
      if (Close[i] > Open[i] && High[i] < High[i+1])   EngulfBody = false;                                                // green bar whose high lower than prev high
      if (Close[i] < Open[i] && Low[i]  > Low[i+1])    EngulfBody = false;                                                // red bar whose low higher than prev low
    }  

    if (!OutsideBar && !EngulfBody)   continue;
    if (High[i] - Low[i] < MinBarHeight*pnt || High[i] - Low[i] > MaxBarHeight*pnt)  continue;         // bar length outside max or min
    if (MathAbs(Close[i] - Open[i]) / (High[i] - Low[i]) < MinBodyPct / 100)  continue;                // body not at least X% of candle height
    
    if (Close[i] > Open[i])  {                                                                         // green bar 
      if (!MustFollowOppColor || Close[i+1] < Open[i+1])  {                                            // must be preceded by red bar
        if ((High[i] - Close[i]) / (High[i] - Low[i]) <= CloseWithinXpct / 100)  {                     // close within X% of top of candle
          ObjectCreate("obidl"+i,OBJ_ARROW,0,iTime(ccy,tf,i),iLow(ccy,tf,i)-50*pnt);
          ObjectSet("obidl"+i,OBJPROP_ARROWCODE,241);
          ObjectSet("obidl"+i,OBJPROP_COLOR,White);
          ObjectSet("obidl"+i,OBJPROP_WIDTH,1);
          valid = 0;
          if (High[i+2]  >  High[i+1])  valid += 2;
          if (High[i+3]  >  High[i+2])  valid += 1;
          if (High[i+4]  >= High[i+3])  valid += 1;
          if (High[i+5]  >= High[i+4])  valid += 1;
          if (High[i+10] >  High[i+1])  valid += 1;
          if (valid >= 5)  ObjectSet("obidl"+i,OBJPROP_WIDTH,4);
          if (!OutsideBar) ObjectSet("obidl"+i,OBJPROP_COLOR,Yellow);
    } } }    
    
    if (Close[i] < Open[i])  {                                                                          // red bar
      if (!MustFollowOppColor || Close[i+1] > Open[i+1])  {                                             // must be preceded by green bar
        if ((Close[i] - Low[i]) / (High[i] - Low[i]) <= CloseWithinXpct / 100)  {                       // close within X% of bottom of candle
          ObjectCreate("obidh"+i,OBJ_ARROW,0,iTime(ccy,tf,i),iHigh(ccy,tf,i)+200*pnt);
          ObjectSet("obidh"+i,OBJPROP_ARROWCODE,242);
          ObjectSet("obidh"+i,OBJPROP_COLOR,White);
          ObjectSet("obidh"+i,OBJPROP_WIDTH,1);
          valid = 0;
          if (Low[i+2]  <  Low[i+1])  valid += 2;
          if (Low[i+3]  <  Low[i+2])  valid += 1;
          if (Low[i+4]  <= Low[i+3])  valid += 1;
          if (Low[i+5]  <= Low[i+4])  valid += 1;
          if (Low[i+10] <  Low[i+1])  valid += 1;
          if (valid >= 5)  ObjectSet("obidh"+i,OBJPROP_WIDTH,4);
          if (!OutsideBar) ObjectSet("obidh"+i,OBJPROP_COLOR,Yellow);
    } } }    
  }
  return(0);
} 

