TASC 2008-02 | Trading Divergences (Vervoot)

Modified on 2010/09/12 11:18 by Eugene — Categorized as: TASC Traders Tips

Traders' Tip text

The article was on “trading divergences”, so we looked back to our Traders’ Tip code for the July 2004 issue of Stocks & Commodities on “VFI Divergence” and modified it for the all-new Wealth-Lab Version 6 (.NET). The Strategy’s PeakDivergence method, which automatically highlights and draws the lines on the chart, can be used to detect any indicator’s divergence from a specified price DataSeries. We’ve included a trading strategy that shorts on “Oscillator lower-top divergence” and exits after a specified number of bars, which can readily be changed using the parameter sliders in the lower-left corner.

WealthLab_Fig1_Feb2008

Figure 1. When using peaks and troughs, keep in mind that price must retrace by some amount before a peak/trough can be seen. Highlighting the detection bars adds realism to what a strategy can achieve.

Strategy Code

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

namespace WealthLab.Strategies { public class DivergenceDetector : WealthScript { private StrategyParameter peakPctPrice; private StrategyParameter peakPctIndicator; private StrategyParameter exitBars; public DivergenceDetector() { peakPctPrice = CreateParameter("Price Peak%", 4, 2, 10, 1); peakPctIndicator = CreateParameter("Indctr Peak%", 20, 5, 30, 1); exitBars = CreateParameter("Exit bars", 5, 1, 30, 1); } // Strategy logic protected override void Execute() { int pkPctPrice = peakPctPrice.ValueInt; int pkPctIndicator = peakPctIndicator.ValueInt; int barsToHold = exitBars.ValueInt; int lastDetectedBar = 0; _barLastChecked = 0; DataSeries rsi = RSI.Series(Close, 14); ChartPane rsiPane = CreatePane(40, true, true); PlotSeries(rsiPane, rsi, Color.Brown, WealthLab.LineStyle.Solid, 2); for(int bar = 20; bar < Bars.Count; bar++) { if (IsLastPositionActive) { Position p = LastPosition; if (bar + 1 - p.EntryBar >= barsToHold) CoverAtMarket(bar + 1, p); } else if (PeakDivergence(bar, Close, pkPctPrice, rsi, pkPctIndicator, rsiPane)) ShortAtMarket(bar + 1); } }

// Returns true if divergence with indicator detected on the specified bar public bool PeakDivergence(int bar, DataSeries price, double pctRev1, DataSeries ind, double pctRev2, ChartPane indPane) { bool divergeDetected = false; PeakTroughMode mode = PeakTroughMode.Percent; int pb1 = (int)PeakBar.Value(bar, price, pctRev1, mode); if (pb1 > _barLastChecked) { _barLastChecked = pb1; int pb2 = (int)PeakBar.Value(pb1, price, pctRev1, mode); if (pb2 > -1) { int testBar = Math.Min(bar, pb1 + proxBars); int ibar1 = (int)PeakBar.Value( testBar, ind, pctRev2, mode); // test peak proximity if (Math.Abs(pb1 - ibar1) > proxBars) ibar1 = pb1; int span = Math.Min(pb1 - pb2 - 1, proxBars); testBar = Math.Min(ibar1 - 1, pb2 + span); int ibar2 = (int)PeakBar.Value( testBar, ind, pctRev2, mode); if (ibar2 < 0) ibar2 = 0; if (Math.Abs(pb2 - ibar2) > proxBars) ibar2 = pb2; divergeDetected = Math.Sign(pricepb1 - pricepb2) != Math.Sign(indibar1 - indibar2); if (divergeDetected) { // Highlight bar detected SetPaneBackgroundColor(PricePane, bar, Color.FromArgb(40, Color.Blue)); DrawLine(PricePane, pb1, pricepb1 * 1.01, pb2, pricepb2 * 1.01, Color.Blue, LineStyle.Solid, 2); DrawLine(indPane, ibar1, indibar1 * 1.01, ibar2, indibar2 * 1.01, Color.Red, LineStyle.Solid, 2); if (Math.Sign(pricepb1 - pricepb2) == 1) for (int b = pb2; b <= pb1; b++) SetPaneBackgroundColor(indPane, b, Color.FromArgb(40, Color.Red)); } } } return divergeDetected; } private const int proxBars = 6; private int _barLastChecked = 0; }

}