//+------------------------------------------------------------------+
//|                             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

//
//
//
//
//

enum enTimeFrames
{
         tf_cu  = 0,                                             // Current time frame
         tf_m1  = PERIOD_M1,                                     // 1 minute
         tf_m5  = PERIOD_M5,                                     // 5 minutes
         tf_m15 = PERIOD_M15,                                    // 15 minutes
         tf_m30 = PERIOD_M30,                                    // 30 minutes
         tf_h1  = PERIOD_H1,                                     // 1 hour
         tf_h4  = PERIOD_H4,                                     // 4 hours
         tf_d1  = PERIOD_D1,                                     // Daily
         tf_w1  = PERIOD_W1,                                     // Weekly
         tf_mn1 = PERIOD_MN1,                                    // Monthly
         tf_n1  = -1,                                            // First higher time frame
         tf_n2  = -2,                                            // Second higher time frame
         tf_n3  = -3                                             // Third higher time frame
      };
input enTimeFrames       inpTimeFrame = tf_cu;     // Time frame to use 
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,count[];
struct sGlobalStruct
{
   string indiFileName;
   int    indiTimeFrame;
};
sGlobalStruct glo;
#define _mtfCall(_buff,_ind) iCustom(_Symbol,glo.indiTimeFrame,glo.indiFileName,tf_cu,FiltPer,NumberOfBars,Price,Shift,_buff,_ind)

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int OnInit()
{
   IndicatorBuffers(5);
   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);
   SetIndexBuffer(4,count);
         ArrayResize(sourceValues,NumberOfBars);
         ArrayResize(calcValues  ,NumberOfBars);
         ArrayResize(a           ,NumberOfBars);
         ArrayResize(b           ,NumberOfBars);
         ArrayResize(c           ,NumberOfBars);
   Lambda=0.0625/pow(sin(M_PI/FiltPer),4);
   glo.indiFileName   = WindowExpertName();
   glo.indiTimeFrame  = (enTimeFrames)timeFrameValue(inpTimeFrame);
   IndicatorSetString(INDICATOR_SHORTNAME,StringFormat("%s HPF ",timeFrameToString(glo.indiTimeFrame)));                                                                                         
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;
                }
                count[0] = limit;
   if (glo.indiTimeFrame!=_Period)
      {
         limit = (int)fmax(limit,fmin(Bars-1,_mtfCall(4,0)*glo.indiTimeFrame/_Period));
         for(i=limit; i>=0; i--)
         {
            int y = iBarShift(_Symbol,glo.indiTimeFrame,Time[i]);
               histoUp[i] = _mtfCall(0,y);
               histoDn[i] = _mtfCall(1,y);   
                                          
         }     
   return(0);
   }  
                           

   //
   //
   //
   //
   //

   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];
}

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------

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("");
}
int timeFrameValue(int _tf)
{
   int add  = (_tf>=0) ? 0 : fabs(_tf);
   if (add != 0) _tf = _Period;
   int size = ArraySize(iTfTable); 
      int i =0; for (;i<size; i++) if (iTfTable[i]==_tf) break;
                                   if (i==size) return(_Period);
                                                return(iTfTable[(int)fmin(i+add,size-1)]);
}



