Files

58 lines
2.1 KiB
Plaintext

// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Ehlers Moving Average Difference with Hann (MADH)", "MADH", overlay = false)
//@function Ehlers Moving Average Difference with Hann — dual Hann FIR filter
// difference expressed as a percentage. Zero-crossing oscillator.
//@param source Series to analyze (typically Close)
//@param shortLength Short Hann FIR window length (>= 1)
//@param dominantCycle Dominant cycle period (>= 2)
//@returns MADH oscillator value (percentage, zero-centered, unbounded)
//@reference Ehlers, J.F. (2021). "The MAD Indicator, Enhanced."
// Technical Analysis of Stocks & Commodities, Nov 2021.
//@optimized O(LongLength) per bar — FIR scan over two Hann-weighted windows
madh(series float source, simple int shortLength, simple int dominantCycle) =>
if shortLength < 1
runtime.error("ShortLength must be at least 1")
if dominantCycle < 2
runtime.error("DominantCycle must be at least 2")
int longLength = int(shortLength + dominantCycle / 2)
// --- Short Hann FIR filter ---
float filt1 = 0.0
float coef1 = 0.0
for k = 1 to shortLength
float w = 1.0 - math.cos(2.0 * math.pi * k / (shortLength + 1))
filt1 += w * nz(source[k - 1])
coef1 += w
if coef1 != 0.0
filt1 := filt1 / coef1
// --- Long Hann FIR filter ---
float filt2 = 0.0
float coef2 = 0.0
for k = 1 to longLength
float w = 1.0 - math.cos(2.0 * math.pi * k / (longLength + 1))
filt2 += w * nz(source[k - 1])
coef2 += w
if coef2 != 0.0
filt2 := filt2 / coef2
// --- MADH = percentage difference ---
float result = filt2 != 0.0 ? 100.0 * (filt1 / filt2 - 1.0) : 0.0
result
// ── Inputs ──
int p_short = input.int(8, "Short Length", minval = 1)
int p_cycle = input.int(27, "Dominant Cycle", minval = 2)
float p_src = input.source(close, "Source")
// ── Calculation ──
float out = madh(p_src, p_short, p_cycle)
// ── Plot ──
plot(out, "MADH", color.yellow, 2)
hline(0, "Zero", color.gray)