Files
Miha Kralj 35a6702b06 fix(docs): correct .md documentation across errors, dynamics, filters, forecasts, momentum, numerics, oscillators, reversals, statistics, trends, volatility, volume
Deep review of all indicator categories verified .md headers against .cs WarmupPeriod, parameters, inputs, and outputs. Fixes include warmup corrections, parameter documentation, output type accuracy, and Pine Script alignment.
2026-03-10 18:38:23 -07:00

88 lines
3.7 KiB
Plaintext

// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Volatility Adjusted Moving Average (VAMA)", "VAMA", overlay=true)
//@function Calculates VAMA by adjusting MA length based on volatility ratio using ATR
//@param source Series to calculate VAMA from
//@param base_length Base lookback period for the moving average
//@param short_atr_period Short-term ATR period for current volatility measurement
//@param long_atr_period Long-term ATR period for reference volatility measurement
//@param min_length Minimum allowed adjusted length
//@param max_length Maximum allowed adjusted length
//@returns VAMA value
//@optimized Uses RMA compensator for ATR and circular buffer for O(1) sum updates
vama(series float source, simple int base_length, simple int short_atr_period=10, simple int long_atr_period=50, simple int min_length=5, simple int max_length=100) =>
var float prevClose = na
float tr1 = high - low
float tr2 = math.abs(high - prevClose)
float tr3 = math.abs(low - prevClose)
float trueRange = math.max(tr1, tr2, tr3)
prevClose := close
float EPSILON = 1e-10
var float raw_rma_short = 0.0
var float e_short = 1.0
var float raw_rma_long = 0.0
var float e_long = 1.0
float short_atr = na
float long_atr = na
if not na(trueRange)
float alpha_short = 1.0 / float(short_atr_period)
float beta_short = 1.0 - alpha_short
raw_rma_short := (raw_rma_short * (short_atr_period - 1) + trueRange) / short_atr_period
e_short := beta_short * e_short
short_atr := e_short > EPSILON ? raw_rma_short / (1.0 - e_short) : raw_rma_short
float alpha_long = 1.0 / float(long_atr_period)
float beta_long = 1.0 - alpha_long
raw_rma_long := (raw_rma_long * (long_atr_period - 1) + trueRange) / long_atr_period
e_long := beta_long * e_long
long_atr := e_long > EPSILON ? raw_rma_long / (1.0 - e_long) : raw_rma_long
float volatility_ratio = not na(short_atr) and not na(long_atr) and short_atr != 0.0 ? long_atr / short_atr : 1.0
float calc_length = base_length * volatility_ratio
int adjusted_length = int(math.max(min_length, math.min(max_length, calc_length)))
var array<float> buffer = array.new_float(max_length, na)
var int head = 0
var float sum = 0.0
var int valid_count = 0
if array.size(buffer) != max_length
buffer := array.new_float(max_length, na)
head := 0
sum := 0.0
valid_count := 0
float oldest = array.get(buffer, head)
if not na(oldest)
sum -= oldest
valid_count -= 1
if not na(source)
sum += source
valid_count += 1
array.set(buffer, head, source)
head := (head + 1) % max_length
float avg = valid_count > 0 ? sum / valid_count : source
int actual_count = math.min(valid_count, adjusted_length)
float partial_sum = 0.0
int partial_count = 0
for i = 0 to actual_count - 1
int idx = (head - 1 - i + max_length) % max_length
float val = array.get(buffer, idx)
if not na(val)
partial_sum += val
partial_count += 1
partial_count > 0 ? partial_sum / partial_count : nz(avg, source)
// ---------- Main loop ----------
// Inputs
i_base_length = input.int(20, "Base Length", minval=1)
i_source = input.source(close, "Source")
i_short_atr = input.int(10, "Short ATR Period", minval=1)
i_long_atr = input.int(50, "Long ATR Period", minval=1)
i_min_length = input.int(5, "Minimum Length", minval=1)
i_max_length = input.int(100, "Maximum Length", minval=1)
// Calculation
vama_value = vama(i_source, i_base_length, i_short_atr, i_long_atr, i_min_length, i_max_length)
// Plot
plot(vama_value, "VAMA", color=color.yellow, linewidth=2)