//+------------------------------------------------------------------+
//|                                             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  PaleVioletRed
#property  indicator_color2  LimeGreen
#property  indicator_color3  DarkSlateGray
#property  indicator_width1  2
#property  indicator_width2  2
#property  indicator_width3  2


//---- 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;

//---- 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];
      }   
      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,0,y);
      valUp[i]        = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,RPeriod,UsePercent,Smoothing,PriceSmoothing,PriceSmoothingPhase,1,y);          
      RateOfChange[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,RPeriod,UsePercent,Smoothing,PriceSmoothing,PriceSmoothingPhase,2,y);
   }
return(0);
}
//+------------------------------------------------------------------
//|     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("");
}
