// The MIT License (MIT) // © mihakralj //@version=6 indicator("Detrended Synthetic Price (DSP)", "DSP", overlay=false) //@function Calculates Detrended Synthetic Price using Ehlers dual-EMA algorithm //@param source Series to detrend //@param period Dominant cycle period for quarter/half-cycle EMA calculation //@returns Detrended synthetic price (difference between quarter-cycle and half-cycle EMAs) dsp(series float source, simple int period) => if period <= 0 runtime.error("Period must be greater than 0") int fast_period = math.max(2, int(math.round(period / 4.0))) int slow_period = math.max(3, int(math.round(period / 2.0))) float alpha_fast = 2.0 / (fast_period + 1) float alpha_slow = 2.0 / (slow_period + 1) var float ema_fast_raw = 0.0 var float ema_slow_raw = 0.0 float current = nz(source) ema_fast_raw += alpha_fast * (current - ema_fast_raw) ema_slow_raw += alpha_slow * (current - ema_slow_raw) var bool warmup = true var float e_fast = 1.0 var float e_slow = 1.0 float ema_fast = ema_fast_raw float ema_slow = ema_slow_raw if warmup e_fast *= (1.0 - alpha_fast) e_slow *= (1.0 - alpha_slow) float c_fast = 1.0 / (1.0 - e_fast) float c_slow = 1.0 / (1.0 - e_slow) ema_fast := c_fast * ema_fast_raw ema_slow := c_slow * ema_slow_raw warmup := e_fast > 1e-10 or e_slow > 1e-10 // Return difference (detrended synthetic price) ema_fast - ema_slow // ---------- Main loop ---------- // Inputs i_source = input.source(hlc3, "Source") i_period = input.int(40, "Dominant Cycle Period", minval=4, maxval=200, tooltip="Dominant cycle period. Quarter-cycle and half-cycle EMAs calculated from this value.") // Calculation dsp_val = dsp(i_source, i_period) // Plot plot(dsp_val, "DSP", color=color.yellow, linewidth=2) hline(0, "Zero Line", color=color.gray, linestyle=hline.style_solid)