mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-09 14:30:56 +00:00
86fe32a682
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: aider (openrouter/anthropic/claude-sonnet-4) <aider@aider.chat> Co-authored-by: Warp <agent@warp.dev>
87 lines
3.3 KiB
Plaintext
87 lines
3.3 KiB
Plaintext
// The MIT License (MIT)
|
|
// © mihakralj
|
|
//@version=6
|
|
indicator("Percentage Price Oscillator (PPO)", "PPO", overlay=false)
|
|
|
|
//@function Calculates Percentage Price Oscillator using compensated EMAs
|
|
//@doc https://github.com/mihakralj/pinescript/blob/main/indicators/momentum/ppo.md
|
|
//@param src Source series to calculate PPO for
|
|
//@param fast_len Fast EMA period
|
|
//@param slow_len Slow EMA period
|
|
//@param signal_len Signal line period
|
|
//@returns Tuple containing PPO line and signal line values
|
|
ppo(series float src, simple int fast_len, simple int slow_len, simple int signal_len)=>
|
|
if fast_len<=0 or slow_len<=0 or signal_len<=0
|
|
runtime.error("Lengths must be greater than 0")
|
|
if fast_len>=slow_len
|
|
runtime.error("Fast length must be less than slow length")
|
|
float alpha_fast = 2.0/math.max(fast_len,1)
|
|
var float fast_ema = na, var float fast_result = na
|
|
var float fast_e = 1.0, var bool fast_warmup = true
|
|
float alpha_slow = 2.0/math.max(slow_len,1)
|
|
var float slow_ema = na, var float slow_result = na
|
|
var float slow_e = 1.0, var bool slow_warmup = true
|
|
float alpha_signal = 2.0/math.max(signal_len,1)
|
|
var float signal_ema = na, var float signal_result = na
|
|
var float signal_e = 1.0, var bool signal_warmup = true
|
|
if not na(src)
|
|
if na(fast_ema)
|
|
fast_ema := 0.0
|
|
fast_result := src
|
|
else
|
|
fast_ema := alpha_fast*(src-fast_ema)+fast_ema
|
|
if fast_warmup
|
|
fast_e *= (1-alpha_fast)
|
|
float fast_c = 1.0/(1.0-fast_e)
|
|
fast_result := fast_c*fast_ema
|
|
if fast_e<=1e-10
|
|
fast_warmup := false
|
|
else
|
|
fast_result := fast_ema
|
|
if na(slow_ema)
|
|
slow_ema := 0.0
|
|
slow_result := src
|
|
else
|
|
slow_ema := alpha_slow*(src-slow_ema)+slow_ema
|
|
if slow_warmup
|
|
slow_e *= (1-alpha_slow)
|
|
float slow_c = 1.0/(1.0-slow_e)
|
|
slow_result := slow_c*slow_ema
|
|
if slow_e<=1e-10
|
|
slow_warmup := false
|
|
else
|
|
slow_result := slow_ema
|
|
float ppo_line = 100 * (fast_result - slow_result) / slow_result
|
|
if not na(ppo_line)
|
|
if na(signal_ema)
|
|
signal_ema := 0.0
|
|
signal_result := ppo_line
|
|
else
|
|
signal_ema := alpha_signal*(ppo_line-signal_ema)+signal_ema
|
|
if signal_warmup
|
|
signal_e *= (1-alpha_signal)
|
|
float signal_c = 1.0/(1.0-signal_e)
|
|
signal_result := signal_c*signal_ema
|
|
if signal_e<=1e-10
|
|
signal_warmup := false
|
|
else
|
|
signal_result := signal_ema
|
|
float hist = ppo_line - signal_result
|
|
[ppo_line, signal_result, hist]
|
|
|
|
// ---------- Main loop ----------
|
|
|
|
// Inputs
|
|
i_source = input.source(close, "Source")
|
|
i_fast_len = input.int(12, "Fast Length", minval=1)
|
|
i_slow_len = input.int(26, "Slow Length", minval=1)
|
|
i_signal_len = input.int(9, "Signal Length", minval=1)
|
|
|
|
// Calculation
|
|
[ppo_line, signal_line, hist] = ppo(i_source, i_fast_len, i_slow_len, i_signal_len)
|
|
|
|
// Plot
|
|
plot(ppo_line, "PPO", color=color.blue, linewidth=2)
|
|
plot(signal_line, "Signal", color=color.red, linewidth=2)
|
|
plot(hist, "Histogram", color.gray, style=plot.style_histogram)
|