//+------------------------------------------------------------------+
//|                                          nBarsZoneOscillator.mq4 |
//|                     2021 Created By Created by XplosionKibo @ FF |
//|                                                                  |
//+------------------------------------------------------------------+

#property copyright "Copyright 2021-07-30, XplosionKibo @ FF"
#property strict
#include <stdlib.mqh>
#include <stderror.mqh>

//--- indicator settings
#property indicator_separate_window
#property indicator_buffers 5

enum fi
{
   fi0,     // nBars
   fi1,     // nBars + True Range
   fi2      // nBars + Average
};
//+------------------------------------------------------------------+
//| Inputs variables                                                 |
//+------------------------------------------------------------------+
extern string                 IndicatorName        =  "nBarsZoneOscillator";
extern int                    Zone_Cal_Length      =  13;
extern ENUM_MA_METHOD         Zone_Cal_Method      =  MODE_EMA;
extern ENUM_APPLIED_PRICE     Zone_Cal_Price       =  PRICE_MEDIAN;
extern fi                     Filter_Type          =  fi2;           
extern int                    Average_Period       =  13;
extern ENUM_MA_METHOD         Average_Method       =  MODE_EMA;
extern int                    Signal_Period        =  8;
extern ENUM_MA_METHOD         Signal_Method        =  MODE_EMA;
extern color                  Signal_Color         =  clrDarkSlateBlue;
extern ENUM_LINE_STYLE        Signal_Style         =  STYLE_DOT;
extern int                    Signal_Thickness     =  0;
extern int                    BarsToLoad           =  1000;       
extern color                  Histogram_PColor     =  C'0,79,0';
extern color                  Histogram_NColor     =  clrMaroon;
extern color                  Histogram_RPColor    =  clrOliveDrab;
extern color                  Histogram_RNColor    =  clrSienna;
extern int                    Histogram_Width      =  1;
extern double                 Range_Level          =  0.1618;
extern ENUM_LINE_STYLE        Level_Style          =  STYLE_DOT;
extern color                  Level_Color          =  C'57,57,57';
extern int                    Level_Thickness      =  0;
extern bool                   Message_Alerts       =  true;
extern bool                   Send_Email           =  false;
extern bool                   Audible_Alerts       =  true;
extern bool                   Push_Notifications   =  false;
extern string                 Sound_File           =  "alert.wav";
extern int                    Alert_Shift          =  1;

//--- indicator buffers

double   nbarsbull[],nbarsbear[],h_plus[],h_minus[],h_rng_pluse[],h_rng_minuse[],signal[],
         diff[],bull[],bear[],tr[],x1[],x2[],x3[];

string   TS; color XC;
datetime time_alert;

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
    void myAlert(string xtf, string message)
   {
   int handle;
   Print(IndicatorName+" @ "+"M("+IntegerToString(Period(),0)+")"+" | "+message);
   if(Audible_Alerts) PlaySound(Sound_File);
   if(Message_Alerts) Alert(IndicatorName+" @ "+"M("+IntegerToString(Period(),0)+")"+" | "+message);
   if(Send_Email) SendMail("nBarsZoneOscillator",IndicatorName+" @ "+"M("+IntegerToString(Period(),0)+")"+" | "+message);
   handle = FileOpen("nBarsZoneOscillator.txt", FILE_TXT|FILE_READ|FILE_WRITE|FILE_SHARE_READ|FILE_SHARE_WRITE,';');
   if(handle != INVALID_HANDLE)
      {
   FileSeek(handle, 0, SEEK_END);
   FileWrite(handle, IndicatorName+" @ "+"M("+IntegerToString(Period(),0)+")"+" | "+message);
   FileClose(handle);
      }
   if(Push_Notifications) SendNotification(IndicatorName+" @ "+"M("+IntegerToString(Period(),0)+")"+" | "+message);
   }
  
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {   
   IndicatorBuffers(14);
   SetIndexBuffer(0, h_plus);
   SetIndexEmptyValue(0, EMPTY_VALUE);
   SetIndexStyle(0, DRAW_HISTOGRAM,EMPTY,Histogram_Width,Histogram_PColor);
   SetIndexBuffer(1, h_minus);
   SetIndexEmptyValue(1, EMPTY_VALUE);
   SetIndexStyle(1, DRAW_HISTOGRAM,EMPTY,Histogram_Width,Histogram_NColor);
   SetIndexBuffer(2, h_rng_pluse);
   SetIndexEmptyValue(2, EMPTY_VALUE);
   SetIndexStyle(2, DRAW_HISTOGRAM,EMPTY,Histogram_Width,Histogram_RPColor);
   SetIndexBuffer(3, h_rng_minuse);
   SetIndexEmptyValue(3, EMPTY_VALUE);
   SetIndexStyle(3, DRAW_HISTOGRAM,EMPTY,Histogram_Width,Histogram_RNColor);
   SetIndexBuffer(4, signal);
   SetIndexEmptyValue(4, EMPTY_VALUE);
   SetIndexStyle(4, DRAW_LINE,Signal_Style,Signal_Thickness,Signal_Color);
   SetIndexBuffer(5, tr);
   SetIndexEmptyValue(5, EMPTY_VALUE);
   SetIndexStyle(5, DRAW_NONE);      
   SetIndexBuffer(6, nbarsbull);
   SetIndexEmptyValue(6, EMPTY_VALUE);
   SetIndexStyle(6, DRAW_NONE);
   SetIndexBuffer(7, nbarsbear);
   SetIndexEmptyValue(7, EMPTY_VALUE);
   SetIndexStyle(7, DRAW_NONE);
   SetIndexBuffer(8, diff);
   SetIndexEmptyValue(8, EMPTY_VALUE);
   SetIndexStyle(8, DRAW_NONE);
   SetIndexBuffer(9, bull);
   SetIndexEmptyValue(9, EMPTY_VALUE);
   SetIndexStyle(9, DRAW_NONE);
   SetIndexBuffer(10, bear);
   SetIndexEmptyValue(10, EMPTY_VALUE);
   SetIndexStyle(10, DRAW_NONE);
   SetIndexBuffer(11, x1);
   SetIndexEmptyValue(11, EMPTY_VALUE);
   SetIndexStyle(11, DRAW_NONE);
   SetIndexBuffer(12, x2);
   SetIndexEmptyValue(12, EMPTY_VALUE);
   SetIndexStyle(12, DRAW_NONE);
   SetIndexBuffer(13, x3);
   SetIndexEmptyValue(13, EMPTY_VALUE);
   SetIndexStyle(13, DRAW_NONE);
   SetLevelValue(0,  Range_Level);
   SetLevelValue(1, -Range_Level);
   SetLevelStyle(Level_Style,Level_Thickness,Level_Color);    
   
   IndicatorShortName("("+IntegerToString(Zone_Cal_Length,1)+") "+IndicatorName);  
         
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[])

  {
   int limit = rates_total - prev_calculated;
   //--- counting from 0 to rates_total
   ArraySetAsSeries(h_plus,         true);      ArraySetAsSeries(h_minus,        true);
   ArraySetAsSeries(h_rng_pluse,    true);      ArraySetAsSeries(h_rng_minuse,   true);
   ArraySetAsSeries(signal,         true);      ArraySetAsSeries(tr,             true);
   ArraySetAsSeries(nbarsbull,      true);      ArraySetAsSeries(nbarsbear,      true);
   ArraySetAsSeries(diff,           true);      ArraySetAsSeries(bull,           true);
   ArraySetAsSeries(bear,           true);      ArraySetAsSeries(x1,             true);
   ArraySetAsSeries(x2,             true);      ArraySetAsSeries(x3,             true);   
          
   //--- initial zero
   if(prev_calculated < 1)
   {
   ArrayInitialize(h_plus,       EMPTY_VALUE);  ArrayInitialize(h_minus,      EMPTY_VALUE);
   ArrayInitialize(h_rng_pluse,  EMPTY_VALUE);  ArrayInitialize(h_rng_minuse, EMPTY_VALUE);
   ArrayInitialize(signal,       EMPTY_VALUE);  ArrayInitialize(tr,           EMPTY_VALUE);
   ArrayInitialize(nbarsbull,    EMPTY_VALUE);  ArrayInitialize(nbarsbear,    EMPTY_VALUE);
   ArrayInitialize(diff,         EMPTY_VALUE);  ArrayInitialize(bull,         EMPTY_VALUE);
   ArrayInitialize(bear,         EMPTY_VALUE);  ArrayInitialize(x1,           EMPTY_VALUE);
   ArrayInitialize(x2,           EMPTY_VALUE);  ArrayInitialize(x3,           EMPTY_VALUE);
   }
   else
   limit++;
     
   //---tr loop
   int i;
   for( i = BarsToLoad-2; i >= 0; i--)
      {
   if (i >= MathMin(BarsToLoad-2, rates_total-1-50)) continue;      
           
      x1[i] = (High[i]-Low[i]);
      x2[i] = (High[i]-Close[i+1]);
      x3[i] = (Close[i+1]-Low[i]);
      tr[i] = MathMax(MathMax(x1[i],x2[i]),x3[i]);   
      }       
   
   //---b&b loop
   for( i = BarsToLoad-2; i >= 0; i--)
      {
   if (i >= MathMin(BarsToLoad-2, rates_total-1-50)) continue;      
      
      if(Zone_Cal_Price==PRICE_CLOSE && Filter_Type==fi0)
      {bull[i]=Close[i]>=Close[i+1];bear[i]=Close[i]<=Close[i+1];}
      if(Zone_Cal_Price==PRICE_CLOSE && Filter_Type==fi1)
      {bull[i]=(Close[i]+tr[i])>=(Close[i+1]+tr[i+1]);bear[i]=(Close[i]-tr[i])<=(Close[i+1]-tr[i+1]);}
      if(Zone_Cal_Price==PRICE_CLOSE && Filter_Type==fi2)
      {bull[i]=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_CLOSE,i)>=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_CLOSE,i+1);   
       bear[i]=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_CLOSE,i)<=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_CLOSE,i+1);}   

      if(Zone_Cal_Price==PRICE_OPEN && Filter_Type==fi0)
      {bull[i]=Open[i]>=Open[i+1];bear[i]=Open[i]<=Open[i+1];}
      if(Zone_Cal_Price==PRICE_OPEN && Filter_Type==fi1)
      {bull[i]=(Open[i]+tr[i])>=(Open[i+1]+tr[i+1]);bear[i]=(Open[i]-tr[i])<=(Open[i+1]-tr[i+1]);}
      if(Zone_Cal_Price==PRICE_OPEN && Filter_Type==fi2)
      {bull[i]=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_OPEN,i)>=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_OPEN,i+1);   
       bear[i]=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_OPEN,i)<=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_OPEN,i+1);}  
      
      if(Zone_Cal_Price==PRICE_HIGH && Filter_Type==fi0)
      {bull[i]=High[i]>=High[i+1];bear[i]=High[i]<=High[i+1];}
      if(Zone_Cal_Price==PRICE_HIGH && Filter_Type==fi1)
      {bull[i]=(High[i]+tr[i])>=(High[i+1]+tr[i+1]);bear[i]=(High[i]-tr[i])<=(High[i+1]-tr[i+1]);}
      if(Zone_Cal_Price==PRICE_HIGH && Filter_Type==fi2)
      {bull[i]=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_HIGH,i)>=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_HIGH,i+1);   
       bear[i]=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_HIGH,i)<=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_HIGH,i+1);}  
          
      if(Zone_Cal_Price==PRICE_LOW && Filter_Type==fi0)
      {bull[i]=Low[i]>=Low[i+1];bear[i]=Low[i]<=Low[i+1];}
      if(Zone_Cal_Price==PRICE_LOW && Filter_Type==fi1)
      {bull[i]=(Low[i]+tr[i])>=(Low[i+1]+tr[i+1]);bear[i]=(Low[i]-tr[i])<=(Low[i+1]-tr[i+1]);}
      if(Zone_Cal_Price==PRICE_LOW && Filter_Type==fi2)
      {bull[i]=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_LOW,i)>=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_LOW,i+1);   
       bear[i]=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_LOW,i)<=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_LOW,i+1);}  
          
      if(Zone_Cal_Price==PRICE_MEDIAN && Filter_Type==fi0)
      {bull[i]=(High[i]+Low[i])/2>=(High[i+1]+Low[i+1])/2;bear[i]=(High[i]+Low[i])/2<=(High[i+1]+Low[i+1])/2;}
      if(Zone_Cal_Price==PRICE_MEDIAN && Filter_Type==fi1)
      {bull[i]=(High[i]+Low[i])/2+tr[i]>=(High[i+1]+Low[i+1])/2+tr[i+1];
      bear[i]=(High[i]+Low[i])/2-tr[i]<=(High[i+1]+Low[i+1])/2-tr[i+1];}
      if(Zone_Cal_Price==PRICE_MEDIAN && Filter_Type==fi2)
      {bull[i]=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_MEDIAN,i)>=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_MEDIAN,i+1);   
       bear[i]=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_MEDIAN,i)<=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_MEDIAN,i+1);}        
           
      if(Zone_Cal_Price==PRICE_TYPICAL && Filter_Type==fi0)
      {bull[i]=((High[i]+Low[i]+Close[i])/3)>=((High[i+1]+Low[i+1]+Close[i+1])/3);
       bear[i]=((High[i]+Low[i]+Close[i])/3)<=((High[i+1]+Low[i+1]+Close[i+1])/3);}
      if(Zone_Cal_Price==PRICE_TYPICAL && Filter_Type==fi1)
      {bull[i]=((High[i]+Low[i]+Close[i])/3+tr[i])>=((High[i+1]+Low[i+1]+Close[i+1])/3+tr[i+1]);
       bear[i]=((High[i]+Low[i]+Close[i])/3-tr[i])<=((High[i+1]+Low[i+1]+Close[i+1])/3-tr[i+1]);}
      if(Zone_Cal_Price==PRICE_TYPICAL && Filter_Type==fi2)
      {bull[i]=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_TYPICAL,i)>=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_TYPICAL,i+1);   
       bear[i]=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_TYPICAL,i)<=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_TYPICAL,i+1);}        
      
      if(Zone_Cal_Price==PRICE_WEIGHTED && Filter_Type==fi0)
      {bull[i]=((High[i]+Low[i]+Close[i]*2)/4)>=((High[i+1]+Low[i+1]+Close[i+1]*2)/4);
       bear[i]=((High[i]+Low[i]+Close[i]*2)/4)<=((High[i+1]+Low[i+1]+Close[i+1]*2)/4);}
      if(Zone_Cal_Price==PRICE_WEIGHTED && Filter_Type==fi1)
      {bull[i]=((High[i]+Low[i]+Close[i]*2)/4+tr[i])>=((High[i+1]+Low[i+1]+Close[i+1]*2)/4+tr[i+1]);
       bear[i]=((High[i]+Low[i]+Close[i]*2)/4-tr[i])<=((High[i+1]+Low[i+1]+Close[i+1]*2)/4-tr[i+1]);}
      if(Zone_Cal_Price==PRICE_WEIGHTED && Filter_Type==fi2)
      {bull[i]=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_WEIGHTED,i)>=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_WEIGHTED,i+1);   
       bear[i]=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_WEIGHTED,i)<=iMA(NULL,0,Average_Period,0,Average_Method,PRICE_WEIGHTED,i+1);}  
     }
                 
   //---nBars loop   
   for( i = BarsToLoad-2; i >= 0; i--)
      {  
   if (i >= MathMin(BarsToLoad-2, rates_total-1-50)) continue;   
     
       nbarsbull[i] = iMAOnArray(bull,0,Zone_Cal_Length,0,Zone_Cal_Method,i);
       nbarsbear[i] = iMAOnArray(bear,0,Zone_Cal_Length,0,Zone_Cal_Method,i);
      }
     
   //--- main loop
   for( i = BarsToLoad-2; i >= 0; i--)
      {      
   if (i >= MathMin(BarsToLoad-2, rates_total-1-50)) continue;   
         
      diff[i]=nbarsbull[i]-nbarsbear[i];
      
      if (diff[i]>0 && diff[i]> Range_Level) {h_plus[i]= diff[i];}       else {h_plus[i]= EMPTY_VALUE;}  
      if (diff[i]>0 && diff[i]< Range_Level) {h_rng_pluse[i]= diff[i];}  else {h_rng_pluse[i]=EMPTY_VALUE;}
      if (diff[i]<0 && diff[i]<-Range_Level) {h_minus[i]= diff[i];}      else {h_minus[i]=EMPTY_VALUE;}
      if (diff[i]<0 && diff[i]>-Range_Level) {h_rng_minuse[i]= diff[i];} else {h_rng_minuse[i]=EMPTY_VALUE;}
      }
   //---signal loop   
   for( i = BarsToLoad-2; i >= 0; i--)
      {  
   if (i >= MathMin(BarsToLoad-2, rates_total-1-50)) continue;
      signal[i] = iMAOnArray(diff,0,Signal_Period,0,Signal_Method,i);   
      }
    
   //--- alert loop
   for( i=Alert_Shift+1; i>=0; i--)
   {
   if(diff[i+Alert_Shift]>0 && diff[i+1+Alert_Shift]<0)  
   {if(i==0 && Time[0]!=time_alert) { myAlert("indicator", "Crossing Up The Zero Line! "); time_alert=Time[0];}}
   
   if(diff[i+Alert_Shift]<0 && diff[i+1+Alert_Shift]>0)  
   {if(i==0 && Time[0]!=time_alert) { myAlert("indicator", "Crossing Down The Zero Line!"); time_alert=Time[0];}}
   }   

 return(rates_total);
   }
//+------------------------------------------------------------------+
