TASC 2016-09 | Measuring Market Cycles (Ehlers)

Modified on 2016/08/01 21:19 by Eugene — Categorized as: TASC Traders Tips

Traders' Tip text

We’ve coded Ehlers Autocorrelation Periodogram from September 2016 issue of Stocks & Commodities for Wealth-Lab 6 (.NET). To view the picture of spectral activity enhanced by using MESA with the same conditions, drag respective "parameter slider" on the bottom left of the screen.

The dominant cycle periods and periods where there were no useful cycles are represented by differently colored ranges: from yellow at the maximum amplitude to black as ice cold.

Image

Figure 1 shows how the measured cycle periods change over time on the Daily chart of AXP (American Express).

Revision A 08/01/2016

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;

namespace WealthLab.Strategies { public class TASC201609 : WealthScript { private StrategyParameter paramEnhance;

public TASC201609() { paramEnhance = CreateParameter("Enhance Resolution", 0, 0, 1, 1); } protected override void Execute() { bool EnhanceResolution = paramEnhance.ValueInt == 0 ? false : true; DataSeries HP = new DataSeries(Bars, "HP"); DataSeries Filt = new DataSeries(Bars, "Filt"); DataSeries DominantCycle = new DataSeries(Bars, "DominantCycle");

double Deg2Rad = Math.PI / 180.0; double cosInDegrees = Math.Cos((.707 * 360 / 48d) * Deg2Rad); double sinInDegrees = Math.Sin((.707 * 360 / 48d) * Deg2Rad); double alpha1 = (cosInDegrees + sinInDegrees - 1) / cosInDegrees; double a1 = Math.Exp(-1.414 * Math.PI / 8.0); double b1 = 2.0 * a1 * Math.Cos((1.414 * 180d / 8.0) * Deg2Rad); double c2 = b1; double c3 = -a1 * a1; double c1 = 1 - c2 - c3;

for (int bar = 2; bar < Bars.Count; bar++) { HP[bar] = 0.5*(1 + alpha1)*(Close[bar] - Close[bar-1]) + alpha1*HP[bar-1]; //Smooth with a SuperSmoother Filter Filt[bar] = c1*(HP[bar] + HP[bar-1]) / 2 + c2*Filt[bar-1] + c3*Filt[bar-2]; } DataSeries[] ds = new DataSeries[48]; ChartPane tp = CreatePane(50,false,false); for( int n = 0; n < 48; n++ ) { ds[n] = new DataSeries(Bars,n.ToString()); for( int bar = 0; bar < Bars.Count; bar++ ) ds[n][bar] = n; PlotSeries(tp, ds[n], Color.Black, LineStyle.Solid, 16); } HideVolume(); for( int bar = 0; bar < Bars.Count; bar++) { SetPaneBackgroundColor(PricePane,bar,Color.Black); int AvgLength = 3, M = 0; double X = 0, Y = 0, Sx = 0, Sy = 0, Sxx = 0, Syy = 0, Sxy = 0; double[] Corr = new double[70]; double[] CosinePart = new double[70]; double[] SinePart = new double[70]; double[] SqSum = new double[70]; double[,] R = new double[70,2]; double[] Pwr = new double[70]; //Pearson correlation for each value of lag for(int Lag = 0; Lag <= 48; Lag++) { //Set the averaging length as M M = AvgLength; if( AvgLength == 0 ) M = Lag; Sx = 0; Sy = 0; Sxx = 0; Syy = 0; Sxy = 0;

for(int count = 0; count <= M-1; count++) { X = bar-count < 0 ? 0 : Filt[bar-count]; //Y = bar-Lag+count < 0 ? 0 : Filt[bar-Lag+count]; Y = bar-(Lag+count) < 0 ? 0 : Filt[bar-(Lag+count)]; // Rev.A Sx = Sx + X; Sy = Sy + Y; Sxx = Sxx + X*X; Sxy = Sxy + X*Y; Syy = Syy + Y*Y; }

if( (M*Sxx - Sx*Sx)*(M*Syy - Sy*Sy) > 0 ) Corr[Lag] = (M*Sxy-Sx*Sy)/Math.Sqrt((M*Sxx - Sx*Sx)*(M*Syy - Sy*Sy)); }

//Compute the Fourier Transform for each Correlation for(int Period = 0; Period <= 48; Period++) { CosinePart[Period] = 0; SinePart[Period] = 0;

for(int N = 3; N <= 48; N++) { double _cosInDegrees = Math.Cos(((double)N * 360 / (double)Period) * Deg2Rad); double _sinInDegrees = Math.Sin(((double)N * 360 / (double)Period) * Deg2Rad); CosinePart[Period] = CosinePart[Period] + Corr[N]*_cosInDegrees; SinePart[Period] = SinePart[Period] + Corr[N]*_sinInDegrees; }

SqSum[Period] = CosinePart[Period]*CosinePart[Period] + SinePart[Period]*SinePart[Period]; } for(int Period = 8; Period <= 48; Period++) { R[Period, 1] = R[Period, 0]; R[Period, 0] = 0.2*SqSum[Period]*SqSum[Period] + 0.8*R[Period,1]; }

//Find Maximum Power Level for Normalization double MaxPwr = 0; for(int Period = 8; Period <= 48; Period++) { if( R[Period, 0] > MaxPwr ) MaxPwr = R[Period, 0]; } for(int Period = 8; Period <= 48; Period++) { Pwr[Period] = R[Period, 0] / MaxPwr; } //Optionally increase Display Resolution by raising the NormPwr to //a higher mathematically power (since the maximum amplitude is //unity, cubing all amplitudes further reduces the smaller ones) if( EnhanceResolution ) { for(int Period = 8; Period <= 48; Period++) { Pwr[Period] = Math.Pow(Pwr[Period], 3); } }

//Compute the dominant cycle using the CG of the spectrum double PeakPwr = 0, Spx = 0, Sp = 0; for(int Period = 8; Period <= 48; Period++) { if( Pwr[Period] > PeakPwr ) PeakPwr = Pwr[Period]; }

//Plot as a Heatmap double Color1 = 255, Color2 = 0, Color3 = 0; for(int Period = 8; Period < 48; Period++) { if( Pwr[Period] > 0.5 ) { Color1 = 255; Color2 = 255*(2*Pwr[Period] - 1); } else { Color1 = 2*255*Pwr[Period]; Color2 = 0; } Color1 = Math.Min((int)Color1,255); Color1 = Math.Max((int)Color1,0); Color2 = Math.Min((int)Color2,255); Color2 = Math.Max((int)Color2,0); Color3 = Math.Min((int)Color3,255); Color3 = Math.Max((int)Color3,0); SetSeriesBarColor(bar, ds[Period], Color.FromArgb(100,(int)Color1,(int)Color2,(int)Color3) ); } } } } }

Eugene
Wealth-Lab team
www.wealth-lab.com