//+------------------------------------------------------------------+
//|                             Hodrick Prescott Filter noLambda.mq4 |
//|                                                           mladen |
//|                                                                  |
//|  original by Kurt Annen                                          |
//|                                                                  |
//|  changed the original to calculate lambda                        |
//|  and not entering it directly as the original                    |
//|  HP filter works                                                 |
//+------------------------------------------------------------------+
#property copyright "copyleft mladen"
#property link      "mladenfx@gmail.com"

#property indicator_separate_window
#property indicator_buffers    2
#property indicator_color1     clrLimeGreen
#property indicator_color2     clrRed
#property indicator_width1     2
#property indicator_width2     2
#property indicator_minimum    0
#property indicator_maximum    1
#property strict

//
//
//
//
//

input int                FiltPer      = 25;
input int                NumberOfBars = 0;
input ENUM_APPLIED_PRICE Price        = PRICE_CLOSE;
input int                Shift        = 0;

double hp[],histoUp[],histoDn[],valc[],sourceValues[],calcValues[],a[],b[],c[],Lambda;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int OnInit()
{
   IndicatorBuffers(4);
   SetIndexBuffer(0,histoUp); SetIndexShift(0,Shift); SetIndexStyle(0,DRAW_HISTOGRAM);
   SetIndexBuffer(1,histoDn); SetIndexShift(1,Shift); SetIndexStyle(1,DRAW_HISTOGRAM);
   SetIndexBuffer(2,hp);      SetIndexShift(2,Shift);
   SetIndexBuffer(3,valc);
         ArrayResize(sourceValues,NumberOfBars);
         ArrayResize(calcValues  ,NumberOfBars);
         ArrayResize(a           ,NumberOfBars);
         ArrayResize(b           ,NumberOfBars);
         ArrayResize(c           ,NumberOfBars);
   Lambda=0.0625/pow(sin(M_PI/FiltPer),4);
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason){     }


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int start()
{
   static datetime barTime;
   int counted_bars=IndicatorCounted();
   int i,n,limit;

   //
   //
   //
   //
   //

   if (NumberOfBars==0)
         n = Bars;
   else  n = NumberOfBars;
   if (n > Bars) n = Bars;
   if (ArraySize(sourceValues) != n)
   {
      ArrayResize(sourceValues,n);
      ArrayResize(calcValues,n);
      ArrayResize(a,n);
      ArrayResize(b,n);
      ArrayResize(c,n);
   }
      
   //
   //
   //
   //
   //
      
   if(counted_bars < 0) return(-1);
   if(counted_bars > 0) counted_bars--;
        limit = MathMin(Bars-counted_bars,n-1);
                SetIndexDrawBegin(0,Bars-n);
                if (barTime!=Time[0])
                {
                     barTime=Time[0];
                     limit=n-1;
                }                        

   //
   //
   //
   //
   //

   for(i=limit; i>=0; i--)  sourceValues[i]=iMA(NULL,0,1,0,MODE_SMA,Price,i);
                            hp_filter(sourceValues,n,Lambda,calcValues,true); ArrayCopy(hp,calcValues);
   for(i=n-1; i>=0; i--)
   {
      valc[i]  = (i<Bars-1) ? (hp[i]>hp[i+1]) ? 1 : (hp[i]<hp[i+1]) ? -1 : valc[i+1] : 0; 
      histoUp[i] = (valc[i]== 1) ? 1 : EMPTY_VALUE;
      histoDn[i] = (valc[i]==-1) ? 1 : EMPTY_VALUE;
   }      
return(0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

void hp_filter(double& data[],int nobs,double lambda, double& output[],bool ret=true)
{
   double H1 =0, H2 =0, H3 =0, H4 =0, H5 =0;
   double HH1=0, HH2=0, HH3=0, HH4=0, HH5=0;
   double HB,HC;
   double Z;
   
   if (nobs <= 5) return;
   
   //
   //
   //
   //
   //
   ArrayCopy(output,data);
   
   a[0]= 1.0+lambda;
   b[0]=-2.0*lambda;
   c[0]=     lambda;
   
   for(int i=1;i<nobs-2;i++)
   {
      a[i]= 6.0*lambda+1.0;
      b[i]=-4.0*lambda;
      c[i]=     lambda;                                             
   }

   a[1]      = 1.0+lambda*5.0;
   a[nobs-1] = 1.0+lambda;
   a[nobs-2] = 1.0+lambda*5.0;
   b[nobs-2] =-2.0*lambda;
   b[nobs-1] = 0.0;
   c[nobs-2] = 0.0;
   c[nobs-1] = 0.0;

   //
   //
   //
   //
   //
      
   for (int i=0;i<nobs;i++)
   {
      Z=a[i]-H4*H1-HH5*HH2;
      if (Z==0) break;
         HB   = b[i];
         HH1  = H1;
         H1   = (HB-H4*H2)/Z;
         b[i] = H1;

         HC   = c[i];
         HH2  = H2;
         H2   = HC/Z;
         c[i] = H2;

         a[i] = (output[i]-HH3*HH5-H3*H4)/Z;
         HH3  = H3;
         H3   = a[i];
         H4   = HB-H5*HH1;
         HH5  = H5;
         H5   = HC;
   }
   
   //
   //
   //
   //
   //
   
   H2            = 0;
   H1            = a[nobs-1];
   output[nobs-1]=H1;

   for (int i=nobs-2; i>=0; i--)
   {
      output[i]=a[i]-b[i]*H1-c[i]*H2;
      H2=H1;
      H1=output[i];
   }

   if (ret==false) for(int i=0; i<nobs; i++) output[i] -= data[i];
}