// Licensed under the Apache License, Version 2.0 // © mihakralj //@version=6 // Ultimate Bands logic based on work by John F. Ehlers (c) 2024 indicator("Ehlers Ultimate Bands (UBANDS)", "UBANDS", overlay=true) //@function Calculates Ultimate Bands //@param src Source series for the bands //@param length Lookback period for the Ehlers Ultrasmooth Filter and RMS //@param mult RMS multiplier for band width //@returns tuple [upperBand, middleBand, lowerBand] ubands(series float src, simple int length, simple float mult) => var float usf_state = na, var float c1=0.0, var float c2=0.0, var float c3=0.0, var int prev_len = 0 if prev_len != length or na(c1) float arg = (math.sqrt(2)*math.pi)/math.max(1,float(length)) float exp_arg = math.exp(-arg) c2 := 2*exp_arg*math.cos(arg) c3 := -exp_arg*exp_arg c1 := (1+c2-c3)/4.0 prev_len := length usf_state := na float s = nz(src,src[1]), s1 = nz(src[1],s), s2 = nz(src[2],s1) float current_usf = na(usf_state) or na(usf_state[1]) or na(usf_state[2]) ? s : (1-c1)*s + (2*c1-c2)*s1 - (c1+c3)*s2 + c2*nz(usf_state[1],s1) + c3*nz(usf_state[2],s2) usf_state := current_usf float smooth = usf_state series float residuals = src - smooth float rms = 0.0 if length > 0 float sumSq_r = 0.0, int count_r = 0 for i = 0 to length - 1 float val_r = residuals[i] if not na(val_r) sumSq_r += val_r*val_r count_r += 1 if count_r > 0 rms := math.sqrt(sumSq_r/count_r) [smooth + mult*rms, smooth, smooth - mult*rms] // ---------- Main loop ---------- // Inputs i_source = input.source(close, "Source") i_length = input.int(20, "Length", minval=1, tooltip="Lookback period for smoothing and RMS calculation.") i_mult = input.float(1.0, "RMS Multiplier", minval=0.01, tooltip="Band width as multiple of RMS value.") // Calculation [upperBand, middleBand, lowerBand] = ubands(i_source, i_length, i_mult) // Plot plot(middleBand, "Middle Band", color=color.yellow, linewidth=2) p1 = plot(upperBand, "Upper Band", color=color.yellow, linewidth=2) p2 = plot(lowerBand, "Lower Band", color=color.yellow, linewidth=2) fill(p1, p2, color=color.new(color.blue, 90), title="Band Fill")