mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-12 23:58:04 +00:00
- Updated BBWN, BBWP, CCV, CV, CVI, EWMA, GKV, HLV, HV, Jvolty, JVOLTYN, MASSI, NATR, RSV, RV, RVI, TR, UI, VOV, VR, YZV indicators with documentation links. - Added documentation links for Aberration, Acceleration Bands, Andrews' Pitchfork, Adaptive Price Zone, ATR Bands, Bollinger Bands, Center of Gravity, Donchian Channels, Decay Min-Max Channel, Detrended Synthetic Price, EACP, EBSW, HOMOD, Jurik Volatility Bands, Keltner Channel, MA Envelope, Min-Max Channel, Price Channel, Regression Channels, Standard Deviation Channel, Stoller Average Range Channel, Super Trend Bands, Ultimate Bands, Ultimate Channel, VWAP Bands, and VWAP with Standard Deviation Bands.
90 lines
4.8 KiB
Plaintext
90 lines
4.8 KiB
Plaintext
// The MIT License (MIT)
|
|
// © mihakralj
|
|
//@version=6
|
|
indicator("Stochastic Momentum Index (SMI)", "SMI", overlay=false)
|
|
|
|
//@function Calculates Stochastic Momentum Index oscillator
|
|
//@param source Source series to calculate SMI for
|
|
//@param k_period Lookback period for high/low range calculation
|
|
//@param k_smooth First smoothing period for raw SMI values
|
|
//@param d_smooth Second smoothing period for signal line
|
|
//@param blau Use Blau method (true) or Chande/Kroll method (false)
|
|
//@returns [%K, %D] values of Stochastic Momentum Index
|
|
smi(series float source, simple int k_period, simple int k_smooth, simple int d_smooth, simple bool blau) =>
|
|
if k_period <= 0 or k_smooth <= 0 or d_smooth <= 0
|
|
runtime.error("All periods must be positive")
|
|
float src_clean = na(source) ? 0 : source
|
|
if na(source)
|
|
[na, na]
|
|
else
|
|
var array<float> high_buffer = array.new_float(0), var array<float> low_buffer = array.new_float(0)
|
|
array.push(high_buffer, nz(high)), array.push(low_buffer, nz(low))
|
|
if array.size(high_buffer) > k_period
|
|
array.shift(high_buffer)
|
|
if array.size(low_buffer) > k_period
|
|
array.shift(low_buffer)
|
|
highest_high = array.max(high_buffer), lowest_low = array.min(low_buffer)
|
|
midpoint = (highest_high + lowest_low) / 2, range_half = (highest_high - lowest_low) / 2
|
|
float a1 = 2.0 / (k_smooth + 1), float a2 = 2.0 / (k_smooth + 1), float a3 = 2.0 / (d_smooth + 1)
|
|
var float e1 = 1.0, var float e2 = 1.0, var float e3 = 1.0, var bool warmup = true
|
|
var float ema1_raw = 0.0, var float ema2_raw = 0.0, var float ema3_raw = 0.0
|
|
var float first_ema = 0.0, var float k_value = 0.0, var float d_value = 0.0
|
|
if blau
|
|
raw_smi = range_half > 0 ? 100 * (src_clean - midpoint) / range_half : 0
|
|
ema1_raw := a1 * (raw_smi - ema1_raw) + ema1_raw
|
|
if warmup
|
|
e1 *= (1 - a1), e2 *= (1 - a2), e3 *= (1 - a3)
|
|
float c1 = 1.0 / (1.0 - e1), float c2 = 1.0 / (1.0 - e2), float c3 = 1.0 / (1.0 - e3)
|
|
first_ema := ema1_raw * c1
|
|
ema2_raw := a2 * (first_ema - ema2_raw) + ema2_raw
|
|
k_value := ema2_raw * c2
|
|
ema3_raw := a3 * (k_value - ema3_raw) + ema3_raw
|
|
d_value := ema3_raw * c3
|
|
warmup := math.max(math.max(e1, e2), e3) > 1e-10
|
|
else
|
|
first_ema := ema1_raw
|
|
ema2_raw := a2 * (first_ema - ema2_raw) + ema2_raw
|
|
k_value := ema2_raw
|
|
ema3_raw := a3 * (k_value - ema3_raw) + ema3_raw
|
|
d_value := ema3_raw
|
|
else
|
|
var float num_ema1 = 0.0, var float num_ema2 = 0.0, var float den_ema1 = 0.0, var float den_ema2 = 0.0
|
|
var float num_first = 0.0, var float den_first = 0.0
|
|
numerator = src_clean - midpoint, denominator = range_half
|
|
ema1_raw := a1 * (numerator - ema1_raw) + ema1_raw
|
|
num_ema1 := a1 * (denominator - num_ema1) + num_ema1
|
|
if warmup
|
|
e1 *= (1 - a1), e2 *= (1 - a2), e3 *= (1 - a3)
|
|
float c1 = 1.0 / (1.0 - e1), float c2 = 1.0 / (1.0 - e2), float c3 = 1.0 / (1.0 - e3)
|
|
num_first := ema1_raw * c1, den_first := num_ema1 * c1
|
|
num_ema2 := a2 * (num_first - num_ema2) + num_ema2
|
|
den_ema2 := a2 * (den_first - den_ema2) + den_ema2
|
|
k_value := den_ema2 > 0 ? 100 * (num_ema2 * c2) / (den_ema2 * c2) : 0
|
|
ema3_raw := a3 * (k_value - ema3_raw) + ema3_raw
|
|
d_value := ema3_raw * c3
|
|
warmup := math.max(math.max(e1, e2), e3) > 1e-10
|
|
else
|
|
num_first := ema1_raw, den_first := num_ema1
|
|
num_ema2 := a2 * (num_first - num_ema2) + num_ema2
|
|
den_ema2 := a2 * (den_first - den_ema2) + den_ema2
|
|
k_value := den_ema2 > 0 ? 100 * num_ema2 / den_ema2 : 0
|
|
ema3_raw := a3 * (k_value - ema3_raw) + ema3_raw
|
|
d_value := ema3_raw
|
|
[k_value, d_value]
|
|
|
|
// ---------- Main loop ----------
|
|
|
|
// Inputs
|
|
i_k_period = input.int(10, "%K Period", minval=1, maxval=100, tooltip="Lookback period for high/low range calculation")
|
|
i_k_smooth = input.int(3, "%K Smooth", minval=1, maxval=20, tooltip="First smoothing period for raw SMI values")
|
|
i_d_smooth = input.int(3, "%D Smooth", minval=1, maxval=20, tooltip="Second smoothing period for signal line")
|
|
i_source = input.source(close, "Source", tooltip="Price series to analyze")
|
|
i_blau = input.bool(true, "Blau Method", tooltip="True: Blau (smooth raw SMI ratio), False: Chande/Kroll (smooth numerator & denominator first)")
|
|
|
|
// Calculation
|
|
[k_value, d_value] = smi(i_source, i_k_period, i_k_smooth, i_d_smooth, i_blau)
|
|
|
|
// Plots
|
|
plot(k_value, "SMI %K", color=color.yellow, linewidth=2)
|
|
plot(d_value, "SMI %D", color=color.blue, linewidth=2)
|