Posted By: DdlV
Some other Ehlers filters - 09/22/13 15:48
Hi all,
I've been going through the papers at this Ehlers site: http://www.mesasoftware.com/technicalpapers.htm and came across a few filters and a couple of indicators which don't seem to be in Zorro yet (if they are, please let me know!). Consequently I've taken a stab at implementing them as a #include, code below. Where Ehlers had fixed values - f.i. cutoffs - I've used those values as the defaults for the parameter. Appreciate your review - both code quality and accuracy of implementation - & comments! Thanks.
The examples Ehlers includes of the use of these are futures or particular stocks, so not directly reproducible on FXCM. His example methodology is 80%/20% crossovers, either after peak/valley as traditionally done, or pre-peak/valley to attempt prediction.
Probably not surprisingly , I haven't been able to get results as good as his, but here's a sample. I stuck with his 80/20 but tightened the Roof to 10 & the script below gave the attached result for SPX500.
The filters:
I've been going through the papers at this Ehlers site: http://www.mesasoftware.com/technicalpapers.htm and came across a few filters and a couple of indicators which don't seem to be in Zorro yet (if they are, please let me know!). Consequently I've taken a stab at implementing them as a #include, code below. Where Ehlers had fixed values - f.i. cutoffs - I've used those values as the defaults for the parameter. Appreciate your review - both code quality and accuracy of implementation - & comments! Thanks.
- HighPass Filter - parameters are Series and CutOff. Per Ehlers a 2-pole filter - Ehlers recommends no less than 2-pole to eliminate spectral dialation. Results are rather different than Zorro's HighPass...
- SuperSmooth Filter - parameters are Series and CutOff. Results seem like Butterworth, but not exactly the same. Ehlers recommends CutOff no less than 10 as below that noise overwhelms the signal.
- Roof Filter - cascade of the 2 above, so essentially a bandpass specifying the range of periods to pass rather than a width around a period (so why "Roof"? Don't know - maybe a signal processing term?) - parameters are the Series, High CutOff, and Low CutOff. Ehlers used 48 for the High CutOff...
- FRAMA (Fractal Adaptive Moving Average) Filter - uses FractalDimension to adapt EMA - parameters are Series and Length.
- Generalized Filter - parameters are Series, filter Coefficients, and Length.
- Laguerre4RSI Indicator - RSI based on 4 period Laguerre time - parameters are Series and Gamma.
- Stochastic Indicator - Roof Price, then Stochastic, finally SuperSmooth - parameters are Series, Length (for Stochastic), High CutOff, and Low CutOff (used for both the Roof and final SuperSmooth).
The examples Ehlers includes of the use of these are futures or particular stocks, so not directly reproducible on FXCM. His example methodology is 80%/20% crossovers, either after peak/valley as traditionally done, or pre-peak/valley to attempt prediction.
Probably not surprisingly , I haven't been able to get results as good as his, but here's a sample. I stuck with his 80/20 but tightened the Roof to 10 & the script below gave the attached result for SPX500.
Code:
#include <EhlersFilters.c> function run() { set(LOGFILE); set(PLOTNOW); BarPeriod = 1440; vars Price = series(price()); vars Stoc = series(EhlersStochastic(Price,0,10,0)); if(crossOver(Stoc,.8)) { exitLong(); if(NumOpenShort==0) enterShort(); } else if(crossUnder(Stoc,.2)) { exitShort(); if(NumOpenLong==0) enterLong(); } plot("EhlersStochastic",Stoc[0],NEW,RED); plot("GoLong",.2,0,BLACK); plot("GoShort",.8,0,BLACK); }
The filters:
Code:
#include <default.c> #define PI 3.14159265 var EhlersHighPass(var* Series,int CutOffPeriod) { // Part of Roofing filter © 2013 John F. Ehlers // alpha1 = (Cosine(.707*360 / 48) + Sine (.707*360 / 48) - 1) / Cosine(.707*360 / 48); // HP = (1 - alpha1 / 2)*(1 - alpha1 / 2)*(Close - 2*Close[1] + Close[2]) + 2*(1 - alpha1)*HP[1] - (1 - alpha1)*(1 - alpha1)*HP[2]; var a,alpha1,b,c; if(!CutOffPeriod) CutOffPeriod = 48; a = (sqrt(2)/2)*2*PI/CutOffPeriod; alpha1 = (cos(a)+sin(a)-1)/cos(a); b = 1-alpha1/2; c = 1-alpha1; var* EHP = series(0,3); return EHP[0] = b*b*(Series[0]-2*Series[1]+Series[2])+2*c*EHP[1]-c*c*EHP[2]; } var EhlersSuperSmooth(var* Series,int CutOffPeriod) { // SuperSmoother filter © 2013 John F. Ehlers // a1 = expvalue(-1.414*3.14159 / 10); // b1 = 2*a1*Cosine(1.414*180 / 10); // c2 = b1; // c3 = -a1*a1; // c1 = 1 - c2 - c3; // Filt = c1*(Close + Close[1]) / 2 + c2*Filt[1] + c3*Filt[2]; var a,a1,b1,c1,c2,c3; if(!CutOffPeriod) CutOffPeriod = 10; a = sqrt(2)*PI/CutOffPeriod; a1 = exp(-a); b1 = 2*a1*cos(a); c2 = b1; c3 = -a1*a1; c1 = 1-c2-c3; var* SS = series(*Series,3); return SS[0] = c1*(Series[0]+Series[1])/2+c2*SS[1]+c3*SS[2]; } var EhlersRoof(var* Series,int CutOffPeriodHigh,int CutOffPeriodLow) { // Roofing filter © 2013 John F. Ehlers var* EHP = series(EhlersHighPass(Series,CutOffPeriodHigh),3); return EhlersSuperSmooth(EHP,CutOffPeriodLow); } var EhlersFRAMA(var* Series, int Length) { if(!Length) Length = 16; var alpha; alpha = exp(-4.6*(FractalDimension(Series,Length)-1)); if(alpha<.01) alpha = .01; else if(alpha>1) alpha = 1; vars F = series(Series[0],2); return F[0] = alpha*Series[0]+(1-alpha)*F[1]; } var EhlersGeneralized(var* Series, var* Coefficients, int Length) { // Generalized Ehlers Filter. // Coefficients need to be computed outside the fucntion. For example, // for 5 bar momentum the calling routine should create a // Coefficients series of the same length as Series consisting of // abs(price(count)-price(count+5)). int count; var Num,Coef,SumCoef; Num = 0; SumCoef = 0; for(count=0;count<Length;count++) { Coef = Coefficients[count]; Num += Coef*Series[count]; SumCoef += Coef; } if(SumCoef==0) return 0; else return Num/SumCoef; } var EhlersLaguerre4RSI(var* Series, var Gamma) { if(Gamma==0) Gamma=.5; var CU,CD; vars L0 = series(0,2); vars L1 = series(0,2); vars L2 = series(0,2); vars L3 = series(0,2); L0[0] = (1-Gamma)*Series[0]+Gamma*L0[1]; L1[0] = -Gamma*L0[0]+L0[1]+Gamma*L1[1]; L2[0] = -Gamma*L1[0]+L1[1]+Gamma*L2[1]; L3[0] = -Gamma*L2[0]+L2[1]+Gamma*L3[1]; CU = 0; CD = 0; if(L0[0]>=L1[0]) CU = L0[0]-L1[0]; else CD = L1[0]-L0[0]; if(L1[0]>=L2[0]) CU += L1[0]-L2[0]; else CD += L2[0]-L1[0]; if(L2[0]>=L3[0]) CU += L2[0]-L3[0]; else CD += L3[0]-L2[0]; if(CU+CD==0) return 0; else return CU/(CU+CD); } var EhlersStochastic(var* Series,int Length, int CutOffPeriodHigh, int CutOffPeriodLow) { // My Stochastic Indicator © 2013 John F. Ehlers // Roof to create Filt, then // HighestC = Filt; // LowestC = Filt; // For count = 0 to Length - 1 Begin // If Filt[count] > HighestC then HighestC = Filt[count]; // If Filt[count] < LowestC then LowestC = Filt[count]; // End; // Stoc = (Filt - LowestC) / (HighestC - LowestC); // MyStochastic = c1*(Stoc + Stoc[1]) / 2 + c2*MyStochastic[1] + c3*MyStochastic[2]; var HighestC,LowestC; if(!Length) Length = 20; var* RS = series(EhlersRoof(Series,CutOffPeriodHigh,CutOffPeriodLow),Length); HighestC = MaxVal(RS,Length); LowestC = MinVal(RS,Length); var* Stoc = series(0,3); if(HighestC==LowestC) Stoc[0] = 0; else Stoc[0] = (RS[0]-LowestC)/(HighestC-LowestC); return EhlersSuperSmooth(Stoc,CutOffPeriodLow); }