//+------------------------------------------------------------------+
//|                                         PolyFitOscillator_v2.mq4 |
//|                             Copyright © 2007-09, TrendLaboratory |
//|            http://finance.groups.yahoo.com/group/TrendLaboratory |
//|                                   E-mail: igorad2003@yahoo.co.uk |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007-09, TrendLaboratory"
#property link      "http://finance.groups.yahoo.com/group/TrendLaboratory"

#property indicator_separate_window
#property indicator_buffers   5
#property strict

#property indicator_color1    Blue
#property indicator_width1    2
#property indicator_color2    Tomato
#property indicator_width2    2
#property indicator_color3    Blue
#property indicator_color4    Tomato
#property indicator_color5    LightBlue
#property indicator_width5    2

#property indicator_level1    0 
#property indicator_level3    2
#property indicator_level4    3
#property indicator_level6   -2
#property indicator_level7   -3
#property indicator_maximum   3.5
#property indicator_minimum  -3.5

//---- external variables
extern ENUM_APPLIED_PRICE Price =   0;   //Apply to Price(0-Close;1-Open;2-High;3-Low;4-Median;5-Typical;6-Weighted)
extern int     Length      = 150;   //Number of bars for an evaluation
extern int     Degree      =   1;   //Degree of Polynom (no more 12)
extern int     SlopeLength =  20;   //Polynomial Slope Length 
extern int     SlopeDegree =   2;   //Degree of Polynomial Slope (no more 12)
extern int     MA_Length   =   1;   //Period of Preliminary Smoothing
extern int     MA_Mode     =   0;   //Mode of MA:0-SMA,1-EMA,2-Wilders(SMMA),3-LWMA
extern int     CountBars   =1000;   //Maximum Number of Bars(0-all Bars) 
//---- indicator buffers
double UpTrend[];
double DnTrend[];
double UpDiver[];
double DnDiver[];
double Osc[];
double slope[];
//---- global variables
double PriceArray[];
int cBars;
string IndName;
//+---------------------------------------------------------------------------+
//| Custom indicator initialization function                                  |
//+---------------------------------------------------------------------------+
int init()
{
   IndicatorDigits((int)MarketInfo(Symbol(), MODE_DIGITS )+2);
   IndicatorBuffers(6); 
   
   SetIndexStyle(0, DRAW_HISTOGRAM);
   SetIndexBuffer(0, UpTrend);
   SetIndexStyle(1, DRAW_HISTOGRAM);
   SetIndexBuffer(1, DnTrend);
   SetIndexStyle(2, DRAW_HISTOGRAM);
   SetIndexBuffer(2, UpDiver);
   SetIndexStyle(3, DRAW_HISTOGRAM);
   SetIndexBuffer(3, DnDiver);
   SetIndexStyle(4, DRAW_LINE);
   SetIndexBuffer(4, Osc);
   SetIndexBuffer(5, slope);
   
   if(CountBars == 0) cBars = Bars;
   else cBars = CountBars;
   
   SetIndexDrawBegin( 0,Bars-cBars-2);
   SetIndexDrawBegin( 1,Bars-cBars-2);
   SetIndexDrawBegin( 2,Bars-cBars-2);
   SetIndexDrawBegin( 3,Bars-cBars-2);
   SetIndexDrawBegin( 4,Bars-cBars-2);
   
   string short_name="PolyFitOscillator("+(string)Price+","+(string)Length+","+(string)Degree+","+(string)SlopeLength+","+(string)SlopeDegree+")";
   IndicatorShortName(short_name);
   SetIndexLabel(4,"Oscillator");
   SetIndexLabel(0,"UpTrend");
   SetIndexLabel(1,"DnTrend");
   SetIndexLabel(2,"UpDivergence");
   SetIndexLabel(3,"DnDivergence");
   
   IndName = WindowExpertName();
   
   ArrayResize(PriceArray, Length);
   
   return(0);
}

double PolyFit(int mode,int ord,double& price[],int deg,int len,int bar)
{
double   result=0,Sum=0;
double   AX[12,12],BX[12],ZX[12],Pow[12];
int      j,k,Row[12];  
static double CX[12];
      
   if (len<=1) Sum = price[bar];
   else
   {	
      double XK;
      double Prod;
      if(mode == 1 || (mode == 0 && bar == -len+1))
      {
      for (j=1;j<=deg+1;j++) BX[j]=0;
		
         for (k=1;k<=len;k++) 
  	      {
  	      double YK=price[len-k];
  	      XK=k;
  	      Prod=1;
  	         for (j=1;j<=deg+1;j++)
            {
    	      BX[j]+= YK*Prod;
    	      Prod*=XK;
  		      }
         }
      
      for (j=0;j<=2*deg;j++) Pow[j]=0;
	
	   Pow[0]=len;
	
         for (k=1;k<=len;k++)
	      {
  	      XK=k;
  	      Prod=k;
  	         for (j=1;j<=2*deg;j++)
  	         {
    	      Pow[j]+= Prod;    	   
    	      Prod*= XK;
  		      }
         }	
	
	      for (j=1;j<=deg+1;j++)
	      {	
            for (int l=1;l<=deg+1;l++) 
  	         AX[j,l]=Pow[j+l-2];
         }	

	  for (j=1;j<=deg+1;j++) Row[j]=j;
  	
         for (int i=1;i<=deg;i++)
  	      {
  	         for (k=i+1;k<=deg+1;k++)
            {
               if(MathAbs(AX[Row[k],i]) > MathAbs(AX[Row[i],i]))
      	      {	
      	      int Temp=Row[i];
      	      Row[i]=Row[k];
      	      Row[k]=Temp;
               }
            }

            for (k=i+1;k<=deg+1;k++)
    	      {
    	      if(AX[Row[i],i]!=0) AX[Row[k],i]=AX[Row[k],i]/AX[Row[i],i];
    		      for (int l=i+1;l<=deg+1;l++)
      	      AX[Row[k],l]=AX[Row[k],l]-AX[Row[k],i]*AX[Row[i],l];
    		   }
         }

      ZX[1]=BX[Row[1]];
      
         for (k=2;k<=deg+1;k++)
  	      {
  	      Sum=0;
         for (int l=1;l<=k-1;l++) Sum+=AX[Row[k],l]*ZX[l];
  	   
  	      ZX[k]=BX[Row[k]]-Sum;
	      }
     
      if(AX[Row[deg+1],deg+1] != 0) CX[deg+1]=ZX[deg+1]/AX[Row[deg+1],deg+1];
      	
         for (k=deg;k>=1;k--)
  	      {
  	      Sum=0;
	    		
  	      for (int l=k+1;l<=deg+1;l++) Sum += AX[Row[k],l]*CX[l]; 
  	      CX[k]=(ZX[k]-Sum)/AX[Row[k],k];
	      }
      }
   
   int mult = 1;
   
   if (ord >= 1)
      for (k = 1; k<=ord; k++) mult *= (deg-k+1); 

	Sum= mult*CX[deg+1];
	
	if(deg > ord) 
	   for (k=deg;k>=ord+1;k--) 
      {
	   int mult1 = 1;
	     if ( ord > 0 )
	     for (int i = 1; i<=ord; i++) mult1*=(k-i);
	  
	   Sum = mult1*CX[k]+Sum*(len+bar);
      }         
      	  
	//Sum=CX[deg+1];
	//for (k=deg;k>=1;k--) Sum=CX[k]+Sum*(len + bar);
   }
   return (Sum);
}	
//+------------------------------------------------------------------+
//| PolyFitOscillator_v2                                                |
//+------------------------------------------------------------------+
int start()
{
   int counted_bars=IndicatorCounted();
      if(counted_bars < 0)   return(-1);
      if(counted_bars > 0)   counted_bars--;
           int limit = MathMin(Bars-counted_bars,Bars-1);
        
   int len = Length+MA_Length;
   
   for(int shift=limit;shift>=0;shift-- )
   {
      double StdDev=0;
      double poly=0;
      if(shift < cBars)
      {
         for(int j=0;j<Length;j++) 
         PriceArray[j] = iMA(NULL,0,MA_Length,0,MA_Mode,Price,shift + j);
      
         double Sum=0;
         for(int j=Length-1;j>=0;j--)
         {
         poly = PolyFit(0,0,PriceArray,Degree,Length,-j); 
         double del = PriceArray[j] - poly; 
         Sum += del*del;
         }
        
         if (Length-1 > 0 && Sum > 0)
         {
            if(Length < 32) StdDev = MathSqrt(Sum/(Length-1));   
            else
            StdDev = MathSqrt(Sum/Length);       
         }
     
      if(StdDev != 0) Osc[shift] = (iMA(NULL,0,MA_Length,0,MA_Mode,Price,shift) - poly)/StdDev;    
      
      slope[shift] = NormalizeDouble(PolyFit(1,1,PriceArray,SlopeDegree,SlopeLength,0),Digits+2);
      }
   }      
      
   for(int shift=limit;shift>=0;shift-- )
   {
      UpTrend[shift] = EMPTY_VALUE;
      DnTrend[shift] = EMPTY_VALUE;
      UpDiver[shift] = EMPTY_VALUE;
      DnDiver[shift] = EMPTY_VALUE;
      
      if(shift < cBars)
      {   
         if(slope[shift] > 0)
         { 
            if(slope[shift] > slope[shift+1]) {UpTrend[shift] = Osc[shift]; UpDiver[shift] = EMPTY_VALUE;}
            if(slope[shift] <=slope[shift+1]) {UpDiver[shift] = Osc[shift]; UpTrend[shift] = EMPTY_VALUE;}
         }
              
         if(slope[shift] < 0)
         {
            if(slope[shift] < slope[shift+1]) {DnTrend[shift] = Osc[shift]; DnDiver[shift] = EMPTY_VALUE;}
            if(slope[shift] >=slope[shift+1]) {DnDiver[shift] = Osc[shift]; DnTrend[shift] = EMPTY_VALUE;}
         }   
      }      
   }

   return(0);
}
//+---------------------------------------------------------------------------+


