Traders' Tip text
The
STMACD indicator by Vitali Apirine from this month's issue presents a way to combine the
stochastic oscillator and
MACD, letting you define oversold/overbought MACD levels. The
STMACD reflects the convergence and divergence of two moving averages relative to the high-low range over a set number of periods.
We illustrate the application of
STMACD with a short-only system that attempts to profit on divergence reversals. When price moves higher but the
STMACD does not reflect that move, creating a lower top, the method looks to fade the move as illustrated on Figure 1 and exits after a specified number of bars.
Granted, it's not the kind of strategy you'd want to employ in the current prolonged bull market without any safety net. Motivated traders should protect it with a stop loss and probably some trade filter.
Figure 1. Sample trades like on the chart of QQQ you can see when the system has a winning streak. Data provided by Yahoo Finance.
After updating our TASCIndicators library to v2019.10 or later, the indicator appears under the TASC Magazine Indicators group. You can plot it on a chart or use it as an entry or exit condition in a Rule-based Strategy without having to program a line of code. As usual you can get the companion Strategy's C# code by downloading it right from Wealth-Lab's "Open Strategy" dialog.
WealthScript Code (C#)
Courtesy Robert Sucher
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;
using TASCIndicators;
namespace WealthLab.Strategies
{
public class TASCNov2019_Divergences : WealthScript
{
private StrategyParameter peakPctPrice;
private StrategyParameter peakPctIndicator;
private StrategyParameter exitBars;
public TASCNov2019_Divergences()
{
peakPctPrice = CreateParameter("Price Peak%", 4, 2, 10, 1);
peakPctIndicator = CreateParameter("Indctr Peak%", 20, 5, 30, 1);
exitBars = CreateParameter("Exit bars", 20, 1, 30, 1);
}
private const int proxBars = 6;
private int _barLastChecked = 0;
protected override void Execute()
{
int pkPctPrice = peakPctPrice.ValueInt;
int pkPctIndicator = peakPctIndicator.ValueInt;
int barsToHold = exitBars.ValueInt;
int lastDetectedBar = 0;
_barLastChecked = 0;
var s = STMACD.Series(Bars,45,12,26);
var es = EMAModern.Series(s,9);
var sp = CreatePane(30,true,true);
PlotSeries(sp, s, Color.Black, WealthLab.LineStyle.Solid, 1);
PlotSeries(sp, es, Color.Red, WealthLab.LineStyle.Solid, 1);
for(int bar = GetTradingLoopStartBar(26); 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, s, pkPctIndicator, sp))
if( ShortAtMarket( bar+1 ) != null )
LastPosition.Priority = Close[bar];
}
}
// 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(price[pb1] - price[pb2]) != Math.Sign(ind[ibar1] - ind[ibar2]);
if (divergeDetected) {
// Highlight bar detected
SetPaneBackgroundColor(PricePane, bar, Color.FromArgb(40, Color.Blue));
DrawLine(PricePane, pb1, price[pb1] * 1.01, pb2, price[pb2] * 1.01, Color.Blue, LineStyle.Solid, 2);
DrawLine(indPane, ibar1, ind[ibar1] * 1.01, ibar2, ind[ibar2] * 1.01, Color.Red, LineStyle.Solid, 2);
if (Math.Sign(price[pb1] - price[pb2]) == 1)
for (int b = pb2; b <= pb1; b++)
SetPaneBackgroundColor(indPane, b, Color.FromArgb(40, Color.Red));
}
}
}
return divergeDetected;
}
}
}
Gene Geren (Eugene)
Wealth-Lab team