mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-27 17:27:43 +00:00
70 lines
2.6 KiB
Plaintext
70 lines
2.6 KiB
Plaintext
// Licensed under the Apache License, Version 2.0
|
|
// © mihakralj
|
|
//@version=6
|
|
indicator("Ehlers Decycler Oscillator (DECO)", "DECO", overlay=false)
|
|
|
|
//@function Calculates Decycler Oscillator using dual 2-pole Butterworth high-pass filters
|
|
//@param source Source series to calculate DECO from
|
|
//@param short_period Short cycle cutoff period for high-pass filter
|
|
//@param long_period Long cycle cutoff period for high-pass filter
|
|
//@returns DECO value (HP(longPeriod) - HP(shortPeriod))
|
|
deco(series float source, simple int short_period, simple int long_period) =>
|
|
if short_period <= 0 or long_period <= 0
|
|
runtime.error("All periods must be positive")
|
|
if short_period >= long_period
|
|
runtime.error("Short period must be less than long period")
|
|
|
|
float src = na(source) ? 0.0 : source
|
|
|
|
// Butterworth 2-pole HP coefficient: alpha = (cos(x) + sin(x) - 1) / cos(x)
|
|
// where x = 0.707 * 2pi / period
|
|
float rad = 0.707 * 2.0 * math.pi
|
|
|
|
float arg_short = rad / short_period
|
|
float alpha_s = (math.cos(arg_short) + math.sin(arg_short) - 1.0) / math.cos(arg_short)
|
|
float omah_s = 1.0 - alpha_s * 0.5
|
|
float oma_s = 1.0 - alpha_s
|
|
float a1_s = omah_s * omah_s
|
|
float b1_s = 2.0 * oma_s
|
|
float c1_s = -(oma_s * oma_s)
|
|
|
|
float arg_long = rad / long_period
|
|
float alpha_l = (math.cos(arg_long) + math.sin(arg_long) - 1.0) / math.cos(arg_long)
|
|
float omah_l = 1.0 - alpha_l * 0.5
|
|
float oma_l = 1.0 - alpha_l
|
|
float a1_l = omah_l * omah_l
|
|
float b1_l = 2.0 * oma_l
|
|
float c1_l = -(oma_l * oma_l)
|
|
|
|
// 2-pole HP: HP[n] = a1*(x - 2*x[1] + x[2]) + b1*HP[1] + c1*HP[2]
|
|
float diff_src = nz(src) - 2.0 * nz(src[1]) + nz(src[2])
|
|
|
|
var float hp_s = 0.0
|
|
var float hp_s1 = 0.0
|
|
var float hp_l = 0.0
|
|
var float hp_l1 = 0.0
|
|
|
|
float new_hp_s = bar_index < 2 ? 0.0 : a1_s * diff_src + b1_s * hp_s + c1_s * hp_s1
|
|
float new_hp_l = bar_index < 2 ? 0.0 : a1_l * diff_src + b1_l * hp_l + c1_l * hp_l1
|
|
|
|
hp_s1 := hp_s
|
|
hp_s := new_hp_s
|
|
hp_l1 := hp_l
|
|
hp_l := new_hp_l
|
|
|
|
na(source) ? na : new_hp_l - new_hp_s
|
|
|
|
// ---------- Main loop ----------
|
|
|
|
// Inputs
|
|
i_short_period = input.int(30, "Short Period", minval=1, maxval=500, tooltip="Short cycle cutoff period for high-pass filter")
|
|
i_long_period = input.int(60, "Long Period", minval=2, maxval=1000, tooltip="Long cycle cutoff period for high-pass filter")
|
|
i_source = input.source(close, "Source", tooltip="Price series to analyze")
|
|
|
|
// Calculation
|
|
result = deco(i_source, i_short_period, i_long_period)
|
|
|
|
// Plot
|
|
plot(result, "DECO", color=color.yellow, linewidth=2)
|
|
hline(0, "Zero Line", color=color.gray, linestyle=hline.style_dotted)
|