// The MIT License (MIT) // © mihakralj //@version=6 indicator("Ehlers Sine Wave (SINE)", "SINE", overlay=false) //@function Calculates Ehlers’ original Sine Wave using a two‑pole High‑Pass, a Super‑Smoother, // and a Hilbert‑transform FIR pair (In‑phase I / Quadrature Q). //@doc https://github.com/mihakralj/pinescript/blob/main/indicators/cycles/sine.md //@param src Series to calculate the Sine Wave from //@param hpLength High‑Pass filter length (detrending period) //@param ssfLength Super‑Smoother filter length (cycle smoothing period) //@returns single normalized sine‑wave value in [‑1 … +1] sine(series float src, simple int hpLength, simple int ssfLength) => if hpLength <= 0 or ssfLength <= 0 runtime.error("Periods must be > 0") float pi = 2 * math.asin(1) float angHP = 2 * pi / hpLength float aHP = (1 - math.sin(angHP)) / math.cos(angHP) var float hp = 0.0 hp := 0.5 * (1 + aHP) * (src - nz(src[1])) + aHP * nz(hp[1]) float angSSF = math.sqrt(2) * pi / ssfLength float aSSF = math.exp(-angSSF) float bSSF = 2 * aSSF * math.cos(angSSF) float c2 = bSSF float c3 = -aSSF * aSSF float c1 = 1 - c2 - c3 var float filt = 0.0 filt := c1 * (hp + nz(hp[1])) / 2 + c2 * nz(filt[1]) + c3 * nz(filt[2]) float Q = 0.0962 * nz(filt[3]) + 0.5769 * nz(filt[1]) - 0.5769 * nz(filt[5]) - 0.0962 * nz(filt[7]) float I = filt float pwr = I*I + Q*Q float sineWave = pwr == 0 ? 0 : I / math.sqrt(pwr) math.min(1, math.max(-1, sineWave)) // ---------- Main loop ---------- // Inputs i_source = input.source(close, "Source") i_hpLength = input.int(40, "High‑Pass Filter Length", minval=1) i_ssfLength = input.int(10, "Super‑Smoother Filter Length", minval=1) // Calculation sine_wave = sine(i_source, i_hpLength, i_ssfLength) // Plot plot(sine_wave, "SINE", color=color.yellow, linewidth=2) hline(0, "Zero Line", color.gray, linestyle=hline.style_dashed)