Files
QuanTAlib/lib/channels/ubands/ubands.pine
T

55 lines
2.3 KiB
Plaintext

// 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")