Log in to see Cloud of Tags

Wealth-Lab Wiki

TASC 2008-03 | Measuring Cycle Periods (Ehlers)

RSS

Traders' Tip text

We’ve coded Ehler’s filter bank to measure the dominant cycle (DC) and the sine and cosine filter components in WealthScript for Wealth-Lab Version 6 (.NET). The CycleFilterDC function plots and returns the DC series and its components, so it’s a trivial matter to make use of them in a trading strategy.

WealthLab_Fig1_March2008

Figure 1. In this daily chart of cyclical price action, you can just about verify the dominant cycle measurement (plotted in lime on the heat map) by visual inspection.

Strategy Code

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

namespace WealthLab.Strategies { public class MyStrategy : WealthScript { public class ArrayHolder { // current, old, older internal double I, I2, I3; internal double Q, Q2, Q3; internal double R, R2, R3; internal double Im, Im2, Im3; internal double A; internal double dB; } public DataSeries CycleFilterDC(DataSeries ds, out DataSeries sine, out DataSeries cosine) { double twoPi = 2 * Math.PI; // Initialize arrays ArrayHolder[] ah = new ArrayHolder[51]; for( int n = 8; n < 51; n++ ) ah[n] = new ArrayHolder(); Color[] color = new Color[21]; DataSeries[] DB = new DataSeries[51]; double domCycle = 0d; string name = ds.Description; DataSeries result = Close - Close; result.Description = "Dominant Cycle(" + name + ")"; // Create and plot the decibel series - change the colors later ChartPane dbPane = CreatePane(40, false, false ); for( int n = 8; n < 51; n++ ) { DB[n] = result + n; DB[n].Description = "Cycle." + n.ToString(); PlotSeries(dbPane, DB[n], Color.Black, LineStyle.Solid, 6); } // Convert decibels to RGB color for display for( int n = 0; n <= 10; n++ ) // yellow to red: 0 to 10 dB color[n] = Color.FromArgb(255, (int)(255 - (255 * n / 10)), 0); for( int n = 11; n <= 20; n++ ) // red to black: 11 to 20 db color[n] = Color.FromArgb( (int)(255 * (20 - n)/10 ), 0, 0); // Detrend data by High Pass Filtering with a 40 Period cutoff DataSeries HP = result; double alpha = (1 - Math.Sin(twoPi/40)) / Math.Cos(twoPi/40); for(int bar = 1; bar < Bars.Count; bar++) HP[bar] = 0.5 * (1 + alpha)* Momentum.Series(ds, 1)[bar] + alpha * HP[bar-1]; DataSeries smoothHP = FIR.Series(HP, "1,2,3,3,2,1"); for( int bar = 6; bar < Bars.Count; bar++ ) { double maxAmpl = 0; double delta = -0.015 * bar + 0.5; delta = delta < 0.15 ? 0.15 : delta; for( int n = 8; n < 51; n++ ) { double beta = Math.Cos(twoPi / n); double g = 1 / Math.Cos(2 * twoPi * delta / n); double a = g - Math.Sqrt(g * g - 1); ah[n].Q = Momentum.Series(smoothHP, 1)[bar] * n / twoPi; ah[n].I = smoothHP[bar]; ah[n].R = 0.5 * (1 - a) * (ah[n].I - ah[n].I3) + beta * (1 + a) * ah[n].R2 - a * ah[n].R3; ah[n].Im = 0.5 * (1 - a) * (ah[n].Q - ah[n].Q3) + beta * (1 + a) * ah[n].Im2 - a * ah[n].Im3; ah[n].A = ah[n].R * ah[n].R + ah[n].Im * ah[n].Im; maxAmpl = ah[n].A > maxAmpl ? ah[n].A : maxAmpl; } double num = 0; double den = 0; for( int n = 8; n < 51; n++ ) { if( maxAmpl != 0 && ah[n].A / maxAmpl > 0 ) ah[n].dB = 10 * Math.Log10( (1 - 0.99 * ah[n].A / maxAmpl) / 0.01 ); ah[n].dB = ah[n].dB > 20 ? 20 : ah[n].dB; SetSeriesBarColor(bar, DB[n], color[(int)Math.Round(ah[n].dB)]); if( ah[n].dB <= 3 ) { num = num + n * (20 - ah[n].dB); den = den + (20 - ah[n].dB); } if( den > 0 ) domCycle = num/den; result[bar] = domCycle; ah[n].I3 = ah[n].I2; ah[n].I2 = ah[n].I; ah[n].Q3 = ah[n].Q2; ah[n].Q2 = ah[n].Q; ah[n].R3 = ah[n].R2; ah[n].R2 = ah[n].R; ah[n].Im3 = ah[n].Im2; ah[n].Im2 = ah[n].Im; } } result = Median.Series(result, 10); PlotSeries(dbPane, result, Color.Lime, WealthLab.LineStyle.Solid, 2); // sine and cosine components sine = Low - Low; sine.Description = "sine(DC)"; double a2 = 0d; for(int bar = 10; bar < Bars.Count; bar++) { double delta = -0.015 * bar + 0.5; delta = delta < 0.15 ? 0.15 : delta; double beta = Math.Cos(2 * Math.PI / result[bar] ); double g = 1 / Math.Cos(4 * Math.PI * delta / result[bar]); if( g < 1 ) a2 = 0; else a2 = g - Math.Sqrt(g * g - 1); sine[bar] = 0.5 * (1 - a2) * Momentum.Value(bar, smoothHP, 1) + beta * (1 + a2) * sine[bar-1] - a2 * sine[bar-2]; } cosine = ( result / 6.28 ) * ( sine - (sine >> 1) ); cosine.Description = "cosine(DC)"; ChartPane sinePane = CreatePane( 40, false, false ); for(int bar = 0; bar < Bars.Count; bar++) SetPaneBackgroundColor(sinePane, bar, Color.Black); PlotSeries(sinePane, sine, Color.Red, LineStyle.Solid, 1); PlotSeries(sinePane, cosine, Color.Cyan, LineStyle.Solid, 1); return result; } protected override void Execute() { HideVolume(); HidePaneLines(); DataSeries avgPrice = (High + Low) / 2; avgPrice.Description = "Avg Price"; // Get the dominant cycle, sine and cosine, and plot the heat map DataSeries sine, cosine; DataSeries DC = CycleFilterDC(avgPrice, out sine, out cosine); /* Use the DC, sine, and cosine DataSeries in a Trading Strategy here */ } } }

Important Disclaimer: The information provided by Wealth-Lab is strictly for informational purposes and is not to be construed as advice or solicitation to buy or sell any security.  The owner of Wealth-Lab.com assumes no liability resulting from the use of the material contained herein for investment purposes. By using this web site, you agree to the terms of this disclaimer and our Terms of Use.


ScrewTurn Wiki. Some of the icons created by FamFamFam.