//+------------------------------------------------------------------+
//|                                             ROC Smoothed MTF.mq4
//|                                    Copyright © 2006, Robert Hill   
//                                  modified by Boxter
//+------------------------------------------------------------------+

#property  copyright "Copyright © 2006, Robert Hill"
//---- indicator settings
#property  indicator_separate_window
#property  indicator_buffers 3
#property  indicator_color1  Red
#property  indicator_color2  Blue
#property  indicator_color3  DarkSlateGray
#property  indicator_width1  5
#property  indicator_width2  5
#property  indicator_width3  1


//---- indicator parameters
extern ENUM_TIMEFRAMES TimeFrame           = PERIOD_CURRENT;
extern int             RPeriod             = 5;
extern bool            UsePercent          = true;
extern bool            Smoothing           = true;
extern int             PriceSmoothing      =   6;
extern int             PriceSmoothingPhase =   0;
extern bool               alertsOn               = true;
extern bool               alertsOnCurrent        = true;
extern bool               alertsMessage          = true;
extern bool               alertsSound            = false;
extern bool               alertsEmail            = false;
extern bool               alertsPushNotification = false;

//---- indicator buffers
double RateOfChange[];
double trend[];
double valUp[];
double valDn[];
string indicatorFileName;
bool   returnBars;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init(){
//---- drawing settings
   IndicatorBuffers(4);
   SetIndexBuffer(0, valDn); SetIndexStyle(0,DRAW_HISTOGRAM);
   SetIndexBuffer(1, valUp); SetIndexStyle(1,DRAW_HISTOGRAM);
   SetIndexBuffer(2, RateOfChange);
   SetIndexBuffer(3, trend);
       
    indicatorFileName = WindowExpertName();
    returnBars        = TimeFrame==-99;
    TimeFrame         = MathMax(TimeFrame,_Period);
   IndicatorShortName(timeFrameToString(TimeFrame)+ " ROC2 Smoothed MTF(" + RPeriod + ")");
//---- initialization done
   return(0);
  }
  
//+------------------------------------------------------------------+
//| ROC calculation                          |
//+------------------------------------------------------------------+
int start(){
   int limit,r,i;
   double ROC, CurrentClose, PrevClose;
   int counted_bars = IndicatorCounted();
//---- check for possible errors
   if(counted_bars < 0) 
       return(-1);
//---- last counted bar will be recounted
   if(counted_bars > 0) 
       counted_bars--;
   limit = MathMin(Bars - counted_bars,Bars-1);
   
   if (returnBars) { valDn[0] = limit+1; return(0); }

//Current TF calculation   
   if (TimeFrame==Period()){
      for(r=limit,i=Bars-r-1; r>=0; r--,i++){
         CurrentClose = iClose(NULL, 0, r);
         PrevClose    = iClose(NULL, 0, r + RPeriod);
         ROC = CurrentClose - PrevClose;
         
         if(Smoothing==1) ROC = iSmooth(ROC,PriceSmoothing,PriceSmoothingPhase,r,0);
         if(UsePercent){  if(PrevClose != 0)RateOfChange[r] = 100 * ROC / PrevClose;}
         else                               RateOfChange[r] = ROC;
         valUp[r] = EMPTY_VALUE;
         valDn[r] = EMPTY_VALUE;
         trend[r] = trend[r+1];
            if (RateOfChange[r]>0) trend[r] =  1;
            if (RateOfChange[r]<0) trend[r] = -1;
            if (trend[r] ==  1) valUp[r] = RateOfChange[r];
            if (trend[r] == -1) valDn[r] = RateOfChange[r];
      }
      manageAlerts();   
      return(0);
   }
  
//mtf Calculation
   limit = MathMax(limit,MathMin(Bars-1,iCustom(NULL,TimeFrame,indicatorFileName,-99,0,0)*TimeFrame/Period()));
   for(i=limit; i>=0; i--){
      int y = iBarShift(NULL,TimeFrame,Time[i]);     
      valDn[i]        = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,RPeriod,UsePercent,Smoothing,PriceSmoothing,PriceSmoothingPhase,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,alertsPushNotification,0,y);
      valUp[i]        = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,RPeriod,UsePercent,Smoothing,PriceSmoothing,PriceSmoothingPhase,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,alertsPushNotification,1,y);          
      RateOfChange[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,RPeriod,UsePercent,Smoothing,PriceSmoothing,PriceSmoothingPhase,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,alertsPushNotification,2,y);
   }
return(0);
}

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

void manageAlerts()
{
   if (alertsOn)
   {
      int whichBar = 1; if (alertsOnCurrent) whichBar = 0;
      Comment(trend[whichBar],"   ",trend[whichBar+1]);
      if (trend[whichBar] != trend[whichBar+1])
      {
         if (trend[whichBar] ==  1) doAlert(whichBar,"up");
         if (trend[whichBar] == -1) doAlert(whichBar,"down");
      }
   }
}

//
//
//
//
//

void doAlert(int forBar, string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   string message;
   
   if (previousAlert != doWhat || previousTime != Time[forBar]) {
       previousAlert  = doWhat;
       previousTime   = Time[forBar];

       //
       //
       //
       //
       //

       message =  timeFrameToString(_Period)+" "+Symbol()+" at "+TimeToStr(TimeLocal(),TIME_SECONDS)+" ROC2 smoothed crossed zero line "+doWhat;
          if (alertsMessage)          Alert(message);
          if (alertsEmail)            SendMail(StringConcatenate(Symbol(),"ROC2 smoothed"),message);
          if (alertsPushNotification) SendNotification(message);
          if (alertsSound)            PlaySound("alert2.wav");
   }
}

//+------------------------------------------------------------------
//|     Smooth function                                                            
//+------------------------------------------------------------------
double wrk[][50];

#define bsmax  5
#define bsmin  6
#define volty  7
#define vsum   8
#define avolty 9

double iSmooth(double price, double length, double phase, int i, int s=0){
   if (ArrayRange(wrk,0) != Bars) ArrayResize(wrk,Bars);
   
   int r = Bars-i-1; 
   if (r==0) { for(int k=0; k<7; k++) wrk[0][k+s]= price; for(; k<10; k++) wrk[0][k+s]= 0; return(price); }
   
   double len1 = MathMax(MathLog(MathSqrt(0.5*(length-1)))/MathLog(2.0)+2.0,0);
   double pow1 = MathMax(len1-2.0,0.5);
   double del1 = price - wrk[r-1][bsmax+s];
   double del2 = price - wrk[r-1][bsmin+s];
	
   wrk[r][volty+s] = 0;
   if(MathAbs(del1) > MathAbs(del2)) wrk[r][volty+s] = MathAbs(del1); 
   if(MathAbs(del1) < MathAbs(del2)) wrk[r][volty+s] = MathAbs(del2); 
   wrk[r][vsum+s] =	wrk[r-1][vsum+s] + 0.1*(wrk[r][volty+s]-wrk[r-10][volty+s]);
      
   double avgLen = MathMin(MathMax(4.0*length,30),150);
   if (r<avgLen){
      double avg = wrk[r][vsum+s];  
      for (k=1; k<avgLen && (r-k)>=0 ; k++) avg += wrk[r-k][vsum+s];
      avg /= k;
   }
   else avg = (wrk[r-1][avolty+s]*avgLen-wrk[r-toInt(avgLen)][vsum+s]+wrk[r][vsum+s])/avgLen;
                                                          
   wrk[r][avolty+s] = avg;                                           
   if (wrk[r][avolty+s] > 0)double dVolty = wrk[r][volty+s]/wrk[r][avolty+s]; 
   else dVolty = 0;   
	if (dVolty > MathPow(len1,1.0/pow1)) dVolty = MathPow(len1,1.0/pow1);
   if (dVolty < 1)                      dVolty = 1.0;
	        
   double pow2 = MathPow(dVolty, pow1);
   double len2 = MathSqrt(0.5*(length-1))*len1;
   double Kv   = MathPow(len2/(len2+1), MathSqrt(pow2));		
	
   if (del1 > 0) wrk[r][bsmax+s] = price; else wrk[r][bsmax+s] = price - Kv*del1;
   if (del2 < 0) wrk[r][bsmin+s] = price; else wrk[r][bsmin+s] = price - Kv*del2;

   double R     = MathMax(MathMin(phase,100),-100)/100.0 + 1.5;
   double beta  = 0.45*(length-1)/(0.45*(length-1)+2);
   double alpha = MathPow(beta,pow2);

   wrk[r][0+s] = price + alpha*(wrk[r-1][0+s]-price);
   wrk[r][1+s] = (price - wrk[r][0+s])*(1-beta) + beta*wrk[r-1][1+s];
   wrk[r][2+s] = (wrk[r][0+s] + R*wrk[r][1+s]);
   wrk[r][3+s] = (wrk[r][2+s] - wrk[r-1][4+s])*MathPow((1-alpha),2) + MathPow(alpha,2)*wrk[r-1][3+s];
   wrk[r][4+s] = (wrk[r-1][4+s] + wrk[r][3+s]); 

   return(wrk[r][4+s]);
}

int toInt(double value) { return(value); }   

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}
