TRADERS’ TIPS

November 2021

Tips Article Thumbnail

For this month’s Traders’ Tips, the focus is John Ehlers’ article in this issue, “The MAD Indicator, Enhanced.” Here, we present the November 2021 Traders’ Tips code with possible implementations in various software.

You can right-click on any chart to open it in a new tab or window and view it at it’s originally supplied size, often much larger than the version printed in the magazine.

The Traders’ Tips section is provided to help the reader implement a selected technique from an article in this issue or another recent issue. The entries here are contributed by software developers or programmers for software that is capable of customization.


logo

TradeStation: November 2021

Last month in his October 2021 article in S&C, “Cycle/Trend Analytics And The MAD Indicator,” John Ehlers presented the MAD (moving average difference) indicator, an oscillator developed out of his research into understanding cycles data better. The MAD indicator effectively took the difference between two simple moving averages. While the MAD is said to offer an improvement over the classic, well-known MACD, the MADH (moving average difference with Hann) that Ehlers presents in his article in this issue, “The MADH: The MAD Indicator, Enhanced,” is said to offer an improvement over the MAD indicator. The enhancement comes from the utilization of the Hann windowing technique and takes the difference of two finite impulse response filters. Ehlers explains that excellent buy and sell indications can be seen in the indicator’s valleys and peaks, respectively.

Indicator:  TASC NOV 2021 MADH
// TASC NOV 2021
// MADH (Moving Average Difference - Hann) Indicator
// (C) 2021 John F. Ehlers

inputs:
	ShortLength(8),
	DominantCycle(27);

variables:
	LongLength(20),
	Filt1(0),
	Filt2(0), 
	coef(0),
	count(0),
	MADH(0);

LongLength = IntPortion(ShortLength + DominantCycle / 2);
Filt1 = 0;
coef = 0;

for count = 1 to ShortLength 
begin
	Filt1 = Filt1 + (1 - Cosine(360*count / (ShortLength + 
	 1)))*Close[count - 1];
	coef = coef + (1 - Cosine(360*count / (ShortLength + 1)));
end;

If coef <> 0 then Filt1 = Filt1 / coef;

Filt2 = 0;
coef = 0;

for count = 1 to LongLength 
begin
	Filt2 = Filt2 + (1 - Cosine(360*count / (LongLength + 
	 1)))*Close[count - 1];
	coef = coef + (1 - Cosine(360*count / (LongLength + 1)));
end;

If coef <> 0 Then Filt2 = Filt2 / coef;

// Computed as percentage of price
If Filt2 <> 0 then MADH = 100*(Filt1 - Filt2) / Filt2;

Plot1(MADH, "MADH");
Plot2(0, "Zero");

A sample chart is shown in Figure 1.

Sample Chart

FIGURE 1: TRADESTATION. This TradeStation daily chart of the continuous emini S&P 500 shows the MADH indicator applied.

This article is for informational purposes. No type of trading or investment recommendation, advice, or strategy is being made, given, or in any manner provided by TradeStation Securities or its affiliates.

—John Robinson
TradeStation Securities, Inc.
www.TradeStation.com

BACK TO LIST

logo

thinkorswim: November 2021

We put together a study based on the article by John Ehlers in this issue titled “The MADH: The MAD Indicator, Enhanced.” We built the strategy referenced by using our proprietary scripting language, thinkscript. To ease the loading process, simply click on http://tos.mx/zq1AI6I or enter it into the address into setupopen shared item from within thinkorswim then choose view thinkScript study and name it “MADH” or whatever you like and can identify. You can then add the strategy to your charts from the edit studies menu from within the charts tab and then select studies.

The chart in Figure 2 shows the study added to a one-year daily chart of SPY. Please see John Ehlers’ article for more information on how to utilize the study.

Sample Chart

FIGURE 2: THINKORSWIM. This sample chart shows the MADH study added to a one-year daily chart of SPY.

—thinkorswim
A division of TD Ameritrade, Inc.
www.thinkorswim.com

BACK TO LIST

logo

eSIGNAL: November 2021

For this month’s Traders’ Tip, we’ve provided the study Moving Average Difference - Hann Indicator.efs based on the article in this issue by John Ehlers titled “The MADH: The MAD Indicator, Enhanced.” This study offers an improvement over the classic MACD study by Gerald Appel by optimizing the lengths of the moving averages.

The study contains formula parameters that may be configured through the edit chart window (right-click on the chart and select “edit chart”). A sample chart is shown in Figure 3.

Sample Chart

FIGURE 3: eSIGNAL. Here is an example of the study plotted on a daily chart of SPY.

To discuss this study or download a complete copy of the formula code, please visit the EFS library discussion board forum under the forums link from the support menu at www.esignal.com or visit our EFS KnowledgeBase at http://www.esignal.com/support/kb/efs. The eSignal formula script (EFS) is also available for copying & pasting below.

/**********************************
Provided By:  
Copyright 2019 Intercontinental Exchange, Inc. All Rights Reserved. 
eSignal is a service mark and/or a registered service mark of Intercontinental Exchange, Inc. 
in the United States and/or other countries. This sample eSignal Formula Script (EFS) 
is for educational purposes only. 
Intercontinental Exchange, Inc. reserves the right to modify and overwrite this EFS file with each new release. 

Description:      
    The MAD Indicator, Enhanced
    by John F. Ehlers
    

Version:            1.00  09/13/2021

Formula Parameters:                    Default:
ShortLength                            8
DominantCycle                          27
 

Notes:
The related article is copyrighted material. If you are not a subscriber
of Stocks & Commodities, please visit www.traders.com.

**********************************/
var fpArray = new Array();
var bInit = false;

function preMain() {
    setStudyTitle("Moving Average Difference - Hann Indicator");
    setCursorLabelName("MADH", 0);
    setPriceStudy(false);
    setDefaultBarFgColor(Color.RGB(0x00,0x94,0xFF), 0);
    setPlotType( PLOTTYPE_LINE , 0 );
    
    
    var x=0;
    fpArray[x] = new FunctionParameter("ShortLength", FunctionParameter.NUMBER);
	with(fpArray[x++]){
        setLowerLimit(1);  
        setDefault(8);
    }    
    fpArray[x] = new FunctionParameter("DominantCycle", FunctionParameter.NUMBER);
	with(fpArray[x++]){
        setLowerLimit(1); 
        setDefault(27);
    }   
}

var bVersion = null;
var xClose = null;
var xMADH = null;
var LongLength = null;
var Filt1 = null;
var coef = null;
var Filt2 = null;


function main(ShortLength, DominantCycle) {
    if (bVersion == null) bVersion = verify();
    if (bVersion == false) return; 
    
    if ( bInit == false ) { 
        xClose = close(); 
        LongLength = Math.trunc(ShortLength + DominantCycle / 2);
        addBand(0, PS_DASH, 1, Color.grey, 1);
        xMADH = efsInternal('Calc_MAD', xClose, ShortLength, LongLength);
                        
        bInit = true; 
    }      
    
    if (getCurrentBarCount() < LongLength || getCurrentBarCount() < ShortLength) return;


    return xMADH.getValue(0);        
}

function Calc_MAD(xClose, ShortLength, LongLength){
    Filt1 = 0;
    coef = 0;
    for (var i = 1; i <= ShortLength; i++){
        Filt1 = Filt1 + (1 - Math.cos(2 * Math.PI * i / (ShortLength + 1))) * xClose.getValue(-i + 1);
        coef = coef + (1 - Math.cos(2 * Math.PI * i / (ShortLength + 1)));
    }
    if (coef != 0) Filt1 = Filt1 / coef;
        
    Filt2 = 0;
    coef = 0;
    for (var i = 1; i <= LongLength; i++){
        Filt2 = Filt2 + (1 - Math.cos(2 * Math.PI * i / (LongLength + 1))) * xClose.getValue(-i + 1);
        coef = coef + (1 - Math.cos(2 * Math.PI * i / (LongLength + 1)));
    }
    if (coef != 0) Filt2 = Filt2 / coef;
    if (Filt2 != 0) ret = 100 * (Filt1 - Filt2) / Filt2;
    
    return ret;
}

function verify(){
    var b = false;
    if (getBuildNumber() < 779){
        
        drawTextAbsolute(5, 35, "This study requires version 10.6 or later.", 
            Color.white, Color.blue, Text.RELATIVETOBOTTOM|Text.RELATIVETOLEFT|Text.BOLD|Text.LEFT,
            null, 13, "error");
        drawTextAbsolute(5, 20, "Click HERE to upgrade.@URL=http://www.esignal.com/download/default.asp", 
            Color.white, Color.blue, Text.RELATIVETOBOTTOM|Text.RELATIVETOLEFT|Text.BOLD|Text.LEFT,
            null, 13, "upgrade");
        return b;
    } 
    else
        b = true;
    
    return b;
}

—Eric Lippert
eSignal, an Interactive Data company
800 779-6555, www.eSignal.com

BACK TO LIST

logo

Wealth-Lab.com: November 2021

We have added John Ehlers’ MADH indicator to Wealth-Lab 7 for the convenience of our users. In his article in this issue, Ehlers suggests that the valleys and peaks of the indicator can signal buy and sell opportunities. To test this trading idea, Wealth-Lab users can simply add the “indicator turns” building block or use the sample code provided below.

System rules

using WealthLab.Backtest;
using System;
using WealthLab.Core;
using WealthLab.Indicators;
using WealthLab.TASC;
using System.Drawing;
using System.Collections.Generic;

namespace WealthScript1 
{
	public class MyStrategy1 : UserStrategyBase
	{
		/* create indicators and other objects here, this is executed prior to the main trading loop */
		public override void Initialize(BarHistory bars)
		{
			mad = MAD.Series(bars.Close, 8, 20);
			madh = MADH.Series(bars.Close, 8, 20);

			PlotIndicator(mad, Color.Red, PlotStyles.Line, false, "MAD");
			PlotIndicator(madh, Color.Yellow, PlotStyles.Line, false, "MADH");

			ChartDisplaySettings cds = new ChartDisplaySettings();
			cds.ColorGridLines = Color.Transparent;
			cds.ColorWatermark = Color.White;
			cds.ColorUpBar = Color.Green;
			cds.ColorDownBar = Color.Red;
			cds.ColorBackground = Color.Black;
			SetChartDrawingOptions(cds);

			SetPaneDrawingOptions("MAD", 20, 50);
			SetPaneDrawingOptions("MADH", 20, 51);
		}

		/* execute the strategy rules here, this is executed once for each bar in the backtest history */
		public override void Execute(BarHistory bars, int idx)
		{
			if(madh.TurnsUp(idx))
				PlaceTrade(bars, TransactionType.Buy, OrderType.Market);
			if (madh.TurnsDown(idx))
				ClosePosition(LastPosition, OrderType.Market);
		}

		/* declare private variables below */
		MAD mad; MADH madh;
	}
}

Figure 4 illustrates application of the MADH to a chart of SPY.

Sample Chart

FIGURE 4: WEALTH-LAB. This chart shows an example of trade signals produced by the system if applied to a daily chart of SPY.

—Gene Geren (Eugene)
Wealth-Lab team
www.wealth-lab.com

BACK TO LIST

logo

Neuroshell Trader: November 2021

John Ehlers’ MADH indicator, presented in his article in this issue, can be easily implemented in NeuroShell Trader using NeuroShell Trader’s ability to call external dynamic linked libraries. Dynamic linked libraries can be written in C, C++ and Power Basic.

After moving the code given in the article to your preferred compiler and creating a DLL, you can insert the resulting indicator as follows:

  1. Select “new indicator” from the insert menu.
  2. Choose the external program & library calls category.
  3. Select the appropriate external DLL call indicator.
  4. Set up the parameters to match your DLL.
  5. Select the finished button.
Sample Chart

FIGURE 5: NEUROSHELL TRADER. This NeuroShell Trader chart shows the MAD and MADH indicators.

NeuroShell Trader users can go to the Stocks & Commodities section of the NeuroShell Trader free technical support website to download a copy of this or any previous Traders’ Tips.

—Ward Systems Group, Inc.
sales@wardsystems.com
www.neuroshell.com

BACK TO LIST

logo

Optuma: November 2021

In his article in this issue, “The MADH: The MAD Indicator, Enhanced,” John Ehlers introduces his MADH indicator. To calculate the MADH indicator in Optuma, you can wrap the MAD formula in the prebuilt FIR() function available to all clients with our Ehlers module (www.optuma.com/ehlers).

//Calculate MAD Oscillator;
//MA Inputs;
#$Short = 8;
#$Long = 23;
//Calc MAD;
S1 = MA(BARS=$Short, CALC=Close);
L1 = MA(BARS=$Long, CALC=Close);
MAD1 =100 * ((S1 - L1)/L1);
//Wrap MAD in the FIR Hann function to calculate MADH;
FIR(MAD1, SMOOTHSTYLE=Hann, BARS=20)
Sample Chart

FIGURE 6: OPTUMA. This sample chart displays the MADH oscillator.

—support@optuma.com

BACK TO LIST

logo

TradersStudio: November 2021

The importable TradersStudio files based on John Ehlers’ article in this issue, “The MADH: The MAD Indicator, Enhanced,” can be obtained on request via email to info@TradersEdgeSystems.com. The code is also available below.

Code for the author’s indicator is provided in following files:

'The MAD Indicator, Enhanced
'Author: John F. Ehlers, TASC Nov 2021
'Coded by: Richard Denning, 9/14/2021

Function EHLERS_MADH(ShortLength, DominantCycle)
'ShortLength=8, DominantCycle=27
    Dim LongLength
    Dim Filt1
    Dim Filt2
    Dim coef
    Dim count
    Dim MADH As BarArray

    If BarNumber=FirstBar Then
        LongLength = 20
        Filt1 = 0
        Filt2 = 0
        coef = 0
        count = 0
        MADH = 0
    End If

    LongLength = CInt(ShortLength + DominantCycle / 2)
    Filt1 = 0
    coef = 0
    For count = 1 To ShortLength
        Filt1 = Filt1 + (1 - TStation_Cosine(360*count / (ShortLength + 1)))*Close[count - 1]
        coef = coef + (1 - TStation_Cosine(360*count / (ShortLength + 1)))
    Next
    If coef <> 0 Then
        Filt1 = Filt1 / coef
    End If
    Filt2 = 0
    coef = 0
    For count = 1 To LongLength
        Filt2 = Filt2 + (1 - TStation_Cosine(360*count / (LongLength + 1)))*Close[count - 1]
        coef = coef + (1 - TStation_Cosine(360*count / (LongLength + 1)))
    Next
    If coef <> 0 Then
        Filt2 = Filt2 / coef
    End If
    If Filt2 <> 0 Then
        MADH = 100*(Filt1 - Filt2)/Filt2
    End If
    EHLERS_MADH = MADH
End Function
'-------------------------------------------------------------------------------------------
'INDICATOR PLOT
Sub EHLERS_MADH_IND(ShortLength,DominantCycle)
Dim MADH As BarArray
MADH = EHLERS_MADH(ShortLength,DominantCycle)
plot1(MADH)
plot2(0)
End Sub

A sample chart displaying the oscillator is shown in Figure 7.

Sample Chart

FIGURE 7: TRADERSSTUDIO. The MADH indicator is shown on a chart of Cisco Systems Inc. (CSCO) during 2012.

—Richard Denning
info@TradersEdgeSystems.com
for TradersStudio

BACK TO LIST

logo

TradingView: November 2021

Here is TradingView Pine code for implementing the MADH indicator (moving average difference with Hann windowing) as presented by John Ehlers in his article in this issue.

// TASC Issue: November 2021
// Article: "Moving Average Difference with Hann Windowing (MADH)" by John Ehlers
// Language: TradingView's Pine Script
// Provided by: PineCoders, for tradingview.com

//@version=4
study("TASC 2021.11 - Moving Average Diff. with Hann Windowing (MADH)", "MADH")

float sourceInput        = input(close, "Source:")
int   shortLengthInput   = input(8,     "Short Length:",   minval = 2)
int   dominantCycleInput = input(27,    "Dominant Cycle:", minval = 4)

madh(source, shortLength, dominantCycle) =>
	var float PIx2 = math.pi * 2.0
	float filt1 = 0.0
	float coeffs = 0.0
	for count = 1 to shortLength
		float hannCoeff = 1.0 - cos(PIx2 * count / (shortLength + 1))
		filt1 += hannCoeff * source[count - 1]
		coeffs += hannCoeff
	filt1 := nz(filt1 / coeffs)
	int longLength = int(shortLength + dominantCycle * 0.5)
	float filt2 = 0.0
	coeffs := 0.0
	for count = 1 to longLength
		float hannCoeff = 1.0 - cos(PIx2 * count / (longLength + 1))
		filt2 += hannCoeff * source[count - 1]
		coeffs += hannCoeff
	filt2 := nz(filt2 / coeffs)
	nz(100.0 * (filt1 - filt2) / filt2)

madhSignal = madh(sourceInput, shortLengthInput, dominantCycleInput)

plot(madhSignal, "MADH", color.orange, 3)
hline(0, "Zero", color.gray)

The indicator is available on TradingView from the PineCodersTASC account at: tradingview.com/u/PineCodersTASC/#published-scripts

Sample Chart

FIGURE 8: TRADINGVIEW. The MADH indicator is shown on a chart of the S&P 500 Index.

—TradingView
https://www.tradingview.com

BACK TO LIST

logo

The Zorro Project: November 2021

Last month in his October 2021 article in S&C, John Ehlers described his MAD indicator. In his article this month, he presents the MADH oscillator, which is the MAD enhanced with a Hann window applied. Here again is the code in C for Zorro for the MAD and Hann from previus issues.

var MAD(vars Data, int ShortPeriod, int LongPeriod) 
{ 
   return 100*(SMA(Data,ShortPeriod)
    /SMA(Data,LongPeriod)-1.);
}

vars hann(vars Data,int Length)
{
   vars Out = series(0,Length);
   int i;
  for(i=0; i<Length; i++)
  Out[i] = Data[i] * (1-cos(2*PI*(i+1)/(Length+1)));
  return Out;
}

For creating the MADH, we just glue both functions together:

var MADH(vars Data, int ShortPeriod, int LongPeriod) 
{ 
   return 100*(SMA(hann(Data,ShortPeriod),ShortPeriod)
      /SMA(hann(Data,LongPeriod),LongPeriod)-1.);
}

Here is a script for replicating Ehlers’ chart in this issue of the MADH using SPY data from the STOOQ website:

void run()
{
  StartDate = 20191201;
  EndDate = 20210701;
  BarPeriod = 1440;

  assetAdd("SPY","STOOQ:*");
  asset("SPY");
  plot("MAD",MAD(seriesC(),8,23),NEW,RED);
  plot("MADH",MADH(seriesC(),8,23),NEW,BLUE);
}

The resulting chart is shown in Figure 9.

Sample Chart

FIGURE 9: ZORRO PROJECT. Here is the MADH indicator applied to SPY data from the STOOQ website.

The MADH oscillator and scripts can be downloaded from the 2021 script repository on https://financial-hacker.com. The Zorro platform can be downloaded from https://zorro-project.com.

—Petra Volkova
The Zorro Project by oP group Germany
https://zorro-project.com

BACK TO LIST

logo

NinjaTrader: November 2021

The MADH (moving average distance—Hann) indicator, as discussed in the article in this issue by John Ehlers, “The MAD Indicator, Enhanced,” is available for download at the following links for NinjaTrader 8 and for NinjaTrader 7:

Once the file is downloaded, you can import the indicator into NinjaTrader 8 from within the control center by selecting Tools → Import → NinjaScript Add-On and then selecting the downloaded file for NinjaTrader 8. To import into NinjaTrader 7, from within the control center window, select the menu File → Utilities → Import NinjaScript and select the downloaded file.

You can review the source code for this indicator in NinjaTrader 8 by selecting the menu New → NinjaScript Editor → Indicators from within the control center window and selecting the MADH file. You can review the indicator’s source code in NinjaTrader 7 by selecting the menu Tools → Edit NinjaScript → Indicator from within the control center window and selecting the MADH file.

A sample chart displaying the indicator is shown in Figure 10.

Sample Chart

FIGURE 10: NINJATRADER. The chart displays the MADH indicator on the emini S&P 500.

NinjaScript uses compiled DLLs that run native, not interpreted, which provides you with the highest performance possible.

—Kate Windheuser
NinjaTrader, LLC
www.ninjatrader.com

BACK TO LIST

Microsoft Excel: November 2021

In his article in this issue, “The MADH: The MAD Indicator, Enhanced,” John Ehlers combines two concepts presented in his previous articles in this series.

By replacing the two moving averages used in the basic MAD indicator with two Hann windowing averages, we get an indicator that is smoother as determined by looking at the rate of change (ROC) of the original MAD and the enhanced MADH (see Figure 11).

Sample Chart

FIGURE 11: EXCEL. This shows a chart comparing MAD and MADH oscillators along with their respective ROC (rate of change) plots.

Ehlers suggests that “excellent buy and sell indications are at the valleys and peaks” of the MADH indicator. These valleys and peaks occur at the points where the MADH ROC crosses zero.

ROC crossovers are a bit easier to see in Figure 12 with the focus narrowed to approximately six months centered on the March 2020 market downturn.

Sample Chart

FIGURE 12: EXCEL. Here is a closer look at three months on either side of the March 2020 market downturn.

To explore the ROC crossover buy and sell indications, scroll slightly to the right of the charts (shown in Figure 13) to see a one-share trading simulation.

Sample Chart

FIGURE 13: EXCEL. This shows a trading simulation using zero crossings of the MADH ROC.

The transaction summary tab (Figure 14) provides transaction details for the trading simulation along with a few more statistics for this trading simulation.

Sample Chart

FIGURE 14: EXCEL. Here you can see the transaction summary tab for the trading simulation.

To download this spreadsheet:
The spreadsheet file for this Traders’ Tip can be downloaded here. To successfully download it, follow these steps:

—Ron McAllister
Excel and VBA programmer
rpmac_xltt@sprynet.com

BACK TO LIST

Originally published in the November 2021 issue of
Technical Analysis of STOCKS & COMMODITIES magazine.
All rights reserved. © Copyright 2021, Technical Analysis, Inc.