// The MIT License (MIT) // © mihakralj //@version=6 indicator("HT_PHASOR: Hilbert Transform Phasor Components", "HT_PHASOR", overlay=false) //@function Numerically stable atan2 implementation for quadrant-aware angle calculation //@param y Y-coordinate (imaginary/quadrature component) //@param x X-coordinate (real/in-phase component) //@returns Angle in radians from -π to π atan2(series float y, series float x) => if y == 0.0 and x == 0.0 runtime.error("atan2: Both y and x cannot be zero") ay = math.abs(y) ax = math.abs(x) angle = 0.0 if ax > ay angle := math.atan(ay / ax) else angle := (math.pi / 2.0) - math.atan(ax / ay) if x < 0.0 angle := math.pi - angle if y < 0.0 angle := -angle angle //@function Calculates Hilbert Transform Phasor Components (InPhase and Quadrature) //@doc https://github.com/mihakralj/pinescript/blob/main/indicators/cycles/ht_phasor.md //@param source Series to analyze for phasor components //@returns Tuple [inphase, quadrature] components ht_phasor(series float source) => var float smooth_price = 0.0 var float detrender = 0.0 var float i1 = 0.0 var float q1 = 0.0 var float ji = 0.0 var float jq = 0.0 var float i2 = 0.0 var float q2 = 0.0 var float re = 0.0 var float im = 0.0 var float period = 15.0 var float smooth_period = 15.0 float price = nz(source) float bandwidth = 0.075 * smooth_period + 0.54 smooth_price := (4.0 * price + 3.0 * nz(price[1]) + 2.0 * nz(price[2]) + nz(price[3])) / 10.0 detrender := (0.0962 * smooth_price + 0.5769 * nz(smooth_price[2]) - 0.5769 * nz(smooth_price[4]) - 0.0962 * nz(smooth_price[6])) * bandwidth q1 := (0.0962 * detrender + 0.5769 * nz(detrender[2]) - 0.5769 * nz(detrender[4]) - 0.0962 * nz(detrender[6])) * bandwidth i1 := nz(detrender[3]) ji := (0.0962 * i1 + 0.5769 * nz(i1[2]) - 0.5769 * nz(i1[4]) - 0.0962 * nz(i1[6])) * bandwidth jq := (0.0962 * q1 + 0.5769 * nz(q1[2]) - 0.5769 * nz(q1[4]) - 0.0962 * nz(q1[6])) * bandwidth i2 := i1 - jq q2 := q1 + ji i2 := 0.2 * i2 + 0.8 * nz(i2[1]) q2 := 0.2 * q2 + 0.8 * nz(q2[1]) re := i2 * nz(i2[1]) + q2 * nz(q2[1]) im := i2 * nz(q2[1]) - q2 * nz(i2[1]) re := 0.2 * re + 0.8 * nz(re[1]) im := 0.2 * im + 0.8 * nz(im[1]) if im != 0.0 or re != 0.0 float angle = atan2(im, re) if angle != 0.0 period := 2.0 * math.pi / angle period := math.max(6.0, math.min(50.0, period)) smooth_period := 0.33 * period + 0.67 * smooth_period [i2, q2] // ---------- Main loop ---------- // Inputs i_source = input.source(hlc3, "Source") // Calculation [inphase, quadrature] = ht_phasor(i_source) // Plot plot(inphase, "InPhase", color=color.yellow, linewidth=2) plot(quadrature, "Quadrature", color=color.blue, linewidth=2) hline(0, "Zero", color=color.gray, linestyle=hline.style_solid)