Ehlers Voss Predictive Filter with dominant cycle - How to

I need your help here. I tried to make the Voss indicator dynamic with Ehlers' autocorrelation periodogram, but the past values already plotted keep changing, presumably because of the way the array is calculated within the function. Is there a way to fix the issue? Thanks in adv.

`/*
	Autocorrelation Periodogram
	2013 John F. Ehlers
*/

SetBarsRequired(sbrAll);

LPeriod = Param("Low-pass Period", 10, 3, 20);
HPeriod = Param("High-pass Period", 48, 22, 80);
IsPlotHeatMap = ParamToggle("Show HeatMap?", "No|Yes", 1);
IsPlotDominantCycle = ParamToggle("Show Dom. Cycle?", "No|Yes");

pi=3.1415926;

function RoofingFilter(lpPeriod, hpPeriod)
{
	alpha1 = (cos(0.707*2*pi / hpPeriod) + sin(0.707*2*pi / hpPeriod) - 1) / cos(0.707*2*pi / hpPeriod);
	a1 = exp(-1.414*pi / lpPeriod);
	b1 = 2*a1*cos(1.414*pi / lpPeriod);
	c2 = b1;
	c3 = -a1*a1;
	c1 = 1 - c2 - c3;
	
	HP = Close;
	Filt = HP;
	
	for(i = 2; i < BarCount; i++)
	{
		HP[i] = ((1 - alpha1 / 2)^2)*(Close[i] - 2*Close[i-1] + Close[i-2]) + 2*(1 - alpha1)*HP[i-1] - ((1 - alpha1)^2)*HP[i-2];
		Filt[i] = c1*(HP[i] + HP[i-1]) / 2 + c2*Filt[i-1] + c3*Filt[i-2];
	}
	
	return Filt;
}

function AGC(lowerCutoff, higherCutoff, acceptableSlope)
{	
	factor = 0;
	accSlope = -acceptableSlope;	//acceptableSlope = 1.5 dB
	halfLC = lowerCutoff / 2;
	halfHC = higherCutoff / 2;
	ratio = 10^(accSlope/20);
	if(halfHC - halfLC > 0)
		factor = ratio^(1/(halfHC - halfLC));
	return factor;
}

function AutocorrelationPeriodogram(data, isHeatMap, isDomCyc)
{
	avgLength = 3;
	dominantCycle = 0;

	//Pearson correlation for each value of lag
	for(lag = 0; lag <= 48; lag++)
	{
		//Set the average length as M
		M = avgLength;
		if(avgLength == 0)
			M = lag;
		//Initialize correlation sums
		Sx = 0;
		Sy = 0;
		Sxx = 0;
		Syy = 0;
		Sxy = 0;
		//Advance samples of both data streams and sum Pearson components
		for(count = 0; count <= M-1; count++)
		{
			X = Ref(data, -count);
			Y = Ref(data, -(lag + count));
			Sx += X;
			Sy += Y;
			Sxx += X^2;
			Syy += Y^2;
			Sxy += X*Y;
		}
		var1 = (M*Sxx - Sx^2)*(M*Syy - Sy^2);
		VarSet("corr" + lag, IIf(var1 > 0, (M*Sxy - Sx*Sy)/sqrt(var1), 0));	//Compute correlation for each value of lag
		//VarSet("corrScale" + lag, IIf(var1 > 0, 0.5*((M*Sxy - Sx*Sy)/sqrt(var1) + 1), 0));	//Scale each correlation to range between 0 and 1
	}
	
	/*//Plot as a Heatmap (for scale each correlation to range between 0 and 1)
	for(period = 3; period <= 48; period++)
	{
		corr = VarGet("corrScale" + period);
		Red = IIf(corr > 0.5, 255*(2 - 2*corr), 255);
		Green = IIf(corr > 0.5, 255, 2*255*corr);
		PlotOHLC( period-1, period-1, period, period, "", ColorRGB( Red, Green, 0 ), styleCloud | styleNoLabel);
	}*/
	
	/*
		The DFT is accomplished by correlating the autocorrelation at each value of lag with the cosine and sine of each period of interest. 
		The sum of the squares of each of these values represents the relative power at each period.
	*/
	for(period = 10; period <= 48; period++)
	{
		cosinePart = 0;
		sinePart = 0;
		
		for(n = 3; n <= 48; n++)
		{
			cosinePart += VarGet("corr" + n)*cos(2*pi*n / period);
			sinePart += VarGet("corr" + n)*sin(2*pi*n / period);
		}
		VarSet("sqSum" + period, cosinePart^2 + sinePart^2);
	}
	
	//EMA is used to smooth the power measurement at each period
	for(period = 10; period <= 48; period++)
		VarSet("r" + period, AMA((VarGet("sqSum" + period))^2, 0.2));

	//Find Maximum Power Level for Normalization
	K = AGC(10, 48, 1.5);
	for(period = 10; period <= 48; period++)
	{
		if(period == 10)
			VarSet("maxPwr", 0);		
		VarSet("maxPwr", IIf(VarGet("r" + period) > VarGet("maxPwr"), K*VarGet("r" + period), VarGet("maxPwr")));
	}
	
	//Normalization power
	for(period = 10; period <= 48; period++)
		VarSet("pwr" + period, VarGet("r" + period)/VarGet("maxPwr"));
		
	//Compute the dominant cycle using the CG of the spectrum
	Spx = 0;
	Sp = 0;
	for(period = 10; period <= 48; period++)
	{
		Spx += IIf(VarGet("pwr" + period) >= 0.5,  period*VarGet("pwr" + period), 0);
		Sp += IIf(VarGet("pwr" + period) >= 0.5, VarGet("pwr" + period), 0);
	}
	dominantCycle = IIf(Sp != 0, Spx / Sp, 0);
	
	
		//Plot(dominantCycle, "Dominant Cycle", colorBlue, styleThick, Null, Null, 0, 1);

SetBarsRequired( sbrAll, 0 );
pds=LastValue(dominantCycle,1);
Period = pds;

Predict = Param( "Predict", 3, 1, 20, 1 );

Bandwidth = 0.25;
Order = 3 * Predict;
PI = 4 * atan( 1 );

F1 = cos( ( 360 / Period ) * ( PI  / 180 ) );
G1 = cos( ( Bandwidth * 360 / Period ) * ( PI / 180 ) );
S1 = 1 / G1 - sqrt( 1 / ( G1 * G1 ) - 1 );

Filt = IIR( C, 0.5 * ( 1 - S1 ), F1 * ( 1 + S1 ), 0, -S1, -0.5 * ( 1 - S1 ) );

sumC = Voss = 0;

for( n = Order; n < BarCount; n++ )
{
	for( count = 0; count < Order; count++ )
	{
		sumC[n] = sumC[n] + ( ( count + 1 ) / Order ) * Voss[n - Order + count];
	}
	Voss[n] = ((3 + Order) / 2 ) * Filt[n] - sumC[n];
}

Plot( Filt, "Filt", colorWhite, styleLine,Null, Null, 0,0, 10 );
colorvoss=IIf(Voss>Ref(voss,-1) AND voss>Filt,colorAqua,IIf(Voss<Ref(voss,-1) AND voss>Filt,colororange,IIf(Voss<Ref(voss,-1) AND voss<Filt,colorPink,colorPaleBlue)));
Plot( Voss, "Dynamic Cycle Voss ", colorvoss, styleHistogram,Null, Null, 0,0, 10 );


	
	return dominantCycle;
}

filtData = RoofingFilter(LPeriod, HPeriod);
AutocorrelationPeriodogram(filtData, IsPlotHeatMap, IsPlotDominantCycle);`

Why do you reinvent the wheel?

I wrote the formula 10 years ago and it is here

https://traders.com/Documentation/FEEDbk_docs/2016/09/TradersTips.html#item4

1 Like

Dear Tomasz .
How can i use it?

@Huynq99 - from the article (in the TASC Magazine - September 2016) in which John F. Ehlers discussed this autocorrelation periodogram is this:

The measured market cycles for SPY in 2015 are shown in Figure 1, where I used the autocorrelation periodogram for the measurement. The spectral display is shown below the bar chart. The horizontal scale of the spectral display is exactly the same as the scale for the bar chart. The vertical scale is the length of the cyclic components in the spectrum. The color on the display indicates the amplitude of the spectrum components as a continuum at every location of time and cycle period. The color ranges from white hot (yellow) at the maximum amplitude, through red hot, to ice cold (black) over a 20-decibel range. The autocorrelation periodogram uses a 48-bar block of data for each day on the chart because the vertical scale has a maximum of a 48-bar cycle period and it is necessary to use at least one full cycle period of the longest cycle for the measurement. If the scale were limited to 24 bars, for example, the length of the data used could be halved. With reference to Figure 1, the year starts with a dominant cycle period of about 22 bars, decreasing to about 18 bars by the end of January. The cycle period drops to be about 10 bars during February when the prices had the short trend up. In March through May, the cyclic components were all over the place. The smearing, or fuzziness, of the spectral display means there just was no useful cycle during that timeframe. The dominant cycle period early in June was about 24 bars, declining to about 18 bars in mid-August when the price drop occurred. The sharp drop basically destroyed any hope of a rational cycle measurement for a while, and the autocorrela tion periodogram responded by displaying a dominant 10-bar cycle for about two months. Then, starting in mid-October, the measured dominant cycle period ranged between 18 and 22 bars for the remainder of the year.

Note: Below is Amibroker's rendering of what is "Figure 1" in the above excerpt:

2 Likes

I hope this "wheel" is correct now... I think there is still something to be sorted out. If anyone can help me, I would be grateful.

SetBarsRequired( sbrAll, 0 );
Data = Close; 
PI = 3.1415926; 

//Highpass Filter and SuperSmoother Filter together form a Roofing 
HFPeriods = Param("HP filter cutoff", 48, 20, 100 ); 
alpha1 = ( 1-sin( 2 * PI /HFPeriods) ) / cos( 2 * PI / HFPeriods ); 
HP = AMA2( Data - Ref( Data, -1 ), 0.5 * ( 1 + alpha1 ), alpha1 ); 

//Smooth with a SuperSmoother Filter 
a1 = exp( -1.414 * PI / 8); 
b1 = 2 * a1 * cos(1.414 * PI / 8); 
c2 = b1; 
c3 = - a1 * a1; 
c1 = 0.5 * ( 1 - c2 - c3 ); 
Filt = IIR( HP, c1, c2, c1, c3 ); 

AvgLength = 3; 
//Pearson correlation for each value of lag 
x = 0; 
for( lag = 1; lag <= 48; lag++ ) 
{ 
 //Set the averaging length as M 
 M = IIf( AvgLength == 0, lag, AvgLength ); 

 // calculate auto-correlation 
 x = Correlation( Filt, Ref( Filt, -lag ), M ); 

 VarSet("Corr"+ lag, x ); 
} 

MaxPwr = 0; 

for( period = 10; period <= 48; period++ ) 
{ 
 cospart = 0; 
 sinpart = 0; 

 for( N = 3; N <= 48; N++ ) 
 { 
   corr = VarGet("Corr" + N ); 
   cospart += corr * cos( 2 * PI * N / period ); 
   sinpart += corr * sin( 2 * PI * N / period ); 
 } 

 sqsum = cospart * cospart + sinpart * sinpart; 

 R = AMA( sqsum, 0.2 ); // periodogram smoothing 

 MaxPwr = Max( R, MaxPwr ); 

 VarSet( "Pwr" + period, R ); 
} 

// normalization & plot 

for( period = 8; period <= 48; period++ ) 
{ 
 varname = "Pwr" + period; 
 pwr = VarGet( varname ) / MaxPwr; 
     
 // optionally increase display resolution by raising to higher power 
 pwr = pwr ^ 2; // can use ^ 3 too 
     
 VarSet( varname, pwr ); 

 Red = IIf( pwr > 0.5, 255, 255 * 2 * pwr ); 
 Green = IIf( pwr > 0.5, 255 * ( 2 * pwr - 1 ), 0 ); 
    
 N = period; 
    
 //PlotOHLC( N, N, N-1, N-1, "", ColorRGB( Red, Green, 0 ), styleCloud | styleNoLabel); 
} 

//Compute the dominant cycle using the CG of the spectrum
	Spx = 0;
	Sp = 0;
	for(period = 10; period <= 48; period++)
	{
		Spx += IIf(VarGet("pwr" + period) >= 0.5,  period*VarGet("pwr" + period), 0);
		Sp += IIf(VarGet("pwr" + period) >= 0.5, VarGet("pwr" + period), 0);
	}
	dominantCycle = IIf(Sp != 0, Spx / Sp, 0);


Predict = Param( "Predict", 3, 1, 20, 1 );



sumC = Voss = 0;
Order = 3 * Predict;

for( n = Order; n < BarCount; n++ )
{
	for( count = 0; count < Order; count++ )
	{
		sumC[n] = sumC[n] + ( ( count + 1 ) / Order ) * Voss[n - Order + count];
	}
	Voss[n] = ((3 + Order) / 2 ) * Filt[n] - sumC[n];
}
//Plot(dominantCycle, "Dominant Cycle", colorBlue, styleThick, Null, Null, 0, 1);
Plot( Filt, "Filt", colorWhite, styleLine,Null, Null, 0,0, 10 );
colorvoss=IIf(Voss>Ref(voss,-1) AND voss>Filt,colorAqua,IIf(Voss<Ref(voss,-1) AND voss>Filt,colororange,IIf(Voss<Ref(voss,-1) AND voss<Filt,colorPink,colorPaleBlue)));
Plot( Voss, "Dynamic Cycle Voss ", colorvoss, styleHistogram,Null, Null, 0,0, 10 );

Dear @Peppe and @Tomasz.

Wow!!! Great.
Thank you very much.

Wish you have happy weekends.

This topic was automatically closed 100 days after the last reply. New replies are no longer allowed.