12 KiB
VAMA: Volatility Adjusted Moving Average
The market doesn't care about your moving average period. VAMA returns the favor by not caring about a fixed period either.
| Property | Value |
|---|---|
| Category | Trend (IIR MA) |
| Inputs | OHLCV bar (TBar) |
| Parameters | baseLength (default 20), shortAtrPeriod (default 10), longAtrPeriod (default 50), minLength (default 5), maxLength (default 100) |
| Outputs | Single series (Vama) |
| Output range | Tracks input |
| Warmup | 1 bar |
| PineScript | vama.pine |
- Most moving averages use a fixed lookback period.
- Similar: VIDYA, KAMA | Complementary: Volatility analysis | Trading note: Volatility-Adjusted MA; scales smoothing by relative volatility.
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
The Core Insight
Most moving averages use a fixed lookback period. VAMA takes a different approach: it dynamically adjusts its effective period based on current market volatility relative to historical norms. When short-term volatility exceeds long-term volatility (high activity), VAMA shortens its period for faster response. When volatility contracts (quiet markets), it lengthens the period for smoother output.
The mechanism uses two ATRs (Average True Range) measured over different timeframes. Their ratio determines how the base period scales. Think of it as an automatic gear shift: volatile markets get responsive tracking, while calm markets get noise reduction.
Historical Context
VAMA emerged from the observation that fixed-period averages create a fundamental mismatch: periods optimal for trending markets over-smooth during volatility spikes, while periods optimized for choppy conditions whipsaw during trends. The volatility ratio approach provides a principled way to adapt rather than choosing a compromise period that works poorly in both regimes.
The ATR-based volatility measurement (using True Range rather than close-to-close changes) captures gap activity and intrabar range that simpler volatility proxies miss. This matters for instruments that gap frequently or have significant intrabar movement.
Architecture
VAMA consists of three interconnected subsystems:
-
Dual ATR Engine: Two RMA (Wilder's smoothed average) calculations track True Range over short and long periods. Both use bias compensation during warmup to avoid the typical EMA startup distortion.
-
Period Adjustment Logic: The ratio
long_ATR / short_ATRscales the base period. When short-term volatility exceeds long-term (ratio < 1), the period shrinks. When short-term is subdued (ratio > 1), the period extends. Clamping prevents extreme values. -
Dynamic SMA Calculator: A circular buffer holds recent values, and SMA is computed over the adjusted period by iterating backwards from the most recent entry.
The Volatility Ratio
volatility_ratio = long_ATR / short_ATR
adjusted_length = base_length × volatility_ratio
adjusted_length = clamp(adjusted_length, min_length, max_length)
When short ATR rises relative to long ATR (current volatility spike):
- Ratio drops below 1
- Adjusted length shortens
- VAMA becomes more responsive
When short ATR falls relative to long ATR (volatility contraction):
- Ratio exceeds 1
- Adjusted length extends
- VAMA becomes smoother
True Range Calculation
True Range captures the full bar's movement including gaps:
TR = \max(H - L, |H - C_{prev}|, |L - C_{prev}|)
This matters because:
- Gap-up followed by selloff:
|L - C_{prev}|captures the true range - Gap-down followed by rally:
|H - C_{prev}|captures the true range - No gap:
H - Lapplies as expected
RMA with Bias Compensation
The ATR smoothing uses RMA (Relative Moving Average, also called Wilder's smoothing):
\alpha = \frac{1}{\text{period}}
RMA_t = \alpha \cdot TR_t + (1 - \alpha) \cdot RMA_{t-1}
Bias compensation addresses startup:
e_t = (1 - \alpha)^t
RMA_{compensated} = \frac{RMA_{raw}}{1 - e_t}
Mathematical Foundation
Parameter Relationships
| Parameter | Default | Purpose |
|---|---|---|
baseLength |
20 | Center point for period adjustment |
shortAtrPeriod |
10 | Current volatility measurement window |
longAtrPeriod |
50 | Historical volatility reference |
minLength |
5 | Floor for adjusted period |
maxLength |
100 | Ceiling for adjusted period |
The ratio of ATR periods determines sensitivity to volatility changes. A 10/50 ratio (5:1) means the short ATR reacts five times faster to volatility changes than the long ATR, creating meaningful but not excessive period swings.
Effective Period Dynamics
With default parameters and typical market behavior:
| Market Condition | Typical Ratio | Adjusted Length |
|---|---|---|
| Volatility spike | 0.5 - 0.8 | 10 - 16 bars |
| Normal conditions | 0.9 - 1.1 | 18 - 22 bars |
| Volatility compression | 1.2 - 2.0 | 24 - 40 bars |
The clamping to [minLength, maxLength] prevents extreme values that could cause either excessive noise (too short) or excessive lag (too long).
Implementation Notes
Complexity Analysis
| Operation | Complexity | Notes |
|---|---|---|
| True Range | O(1) | Three comparisons |
| ATR updates | O(1) | RMA is recursive |
| Buffer insertion | O(1) | Circular buffer |
| SMA calculation | O(adjusted_length) | Sum over dynamic window |
The SMA calculation is the dominant cost. With maxLength = 100, worst case iterates 100 values. For typical adjusted lengths of 15-30, this remains efficient.
Memory Layout
- Two
RmaStatestructs (24 bytes each): ATR state - Circular buffer (
double[maxLength]): Source values - State copy for bar correction: Additional buffer array
Total footprint scales with maxLength parameter.
Bar Correction (isNew=false)
VAMA supports bar correction by maintaining previous state (_p_state, _p_buffer). When isNew=false, state rolls back before recalculation. This handles real-time bar updates where the current bar's OHLC changes before bar close.
Performance Profile
Operation Count (Streaming Mode)
VAMA has three computational phases: True Range, dual ATR updates, and dynamic SMA:
Phase 1: True Range Calculation
| Operation | Count | Cost (cycles) | Subtotal |
|---|---|---|---|
| SUB (H - L) | 1 | 1 | 1 |
| SUB (H - Cprev) | 1 | 1 | 1 |
| SUB (L - Cprev) | 1 | 1 | 1 |
| ABS (×2) | 2 | 1 | 2 |
| CMP (max of 3) | 2 | 1 | 2 |
| Phase 1 subtotal | 7 | — | ~7 cycles |
Phase 2: Dual ATR (RMA) Updates
| Operation | Count | Cost (cycles) | Subtotal |
|---|---|---|---|
| FMA (short ATR) | 1 | 4 | 4 |
| FMA (long ATR) | 1 | 4 | 4 |
| MUL (compensator ×2) | 2 | 3 | 6 |
| DIV (bias correction ×2) | 2 | 15 | 30 |
| Phase 2 subtotal | 6 | — | ~44 cycles |
Phase 3: Dynamic SMA (O(L) where L = adjusted_length)
| Operation | Count | Cost (cycles) | Subtotal |
|---|---|---|---|
| DIV (ratio: long/short) | 1 | 15 | 15 |
| MUL (base × ratio) | 1 | 3 | 3 |
| CLAMP (2 CMP) | 2 | 1 | 2 |
| ADD (sum L values) | L | 1 | L |
| DIV (sum / L) | 1 | 15 | 15 |
| Phase 3 subtotal | 5 + L | — | ~35 + L cycles |
Total per bar: ~86 + L cycles where L = adjusted_length (typically 15-30).
| Typical Scenario | Adjusted Length | Total Cycles |
|---|---|---|
| High volatility | 10 | ~96 cycles |
| Normal | 20 | ~106 cycles |
| Low volatility | 40 | ~126 cycles |
Post-warmup (no bias correction): subtract ~30 cycles → ~56 + L cycles/bar.
Batch Mode (SIMD Analysis)
VAMA is partially vectorizable:
| Component | SIMD Potential | Notes |
|---|---|---|
| True Range | Limited | Min/max chains not ideal for SIMD |
| ATR (RMA) | None | Recursive IIR filter |
| SMA summation | Yes | Horizontal sum of buffer segment |
For SMA with L ≥ 8, AVX2 can reduce ADD operations by ~4×:
| Optimization | Operations | Cycles Saved |
|---|---|---|
| SIMD sum (L=32) | 32 → 8 ops | ~24 cycles |
| FMA for ATR | Already optimal | — |
Benchmark Results
| Metric | Value | Notes |
|---|---|---|
| Throughput | ~15M bars/sec | TBar input, single-threaded |
| Allocations | 0 bytes | Hot path allocation-free |
| Complexity | O(adjusted_length) | Per-bar, varies with volatility |
| Warmup | max(longAtrPeriod, maxLength) | Both ATRs and buffer must fill |
| State Size | ~900 bytes | Two RMA states + circular buffer |
Quality Metrics
| Metric | Score | Notes |
|---|---|---|
| Accuracy | 8/10 | Tracks price within adaptive window |
| Timeliness | 8/10 | Shortens period during volatility spikes |
| Overshoot | 8/10 | SMA-based, minimal overshoot |
| Smoothness | 7/10 | Smooth in low-vol, responsive in high-vol |
Usage Patterns
Basic Usage
var vama = new Vama(baseLength: 20, shortAtrPeriod: 10, longAtrPeriod: 50);
foreach (var bar in bars)
{
var result = vama.Update(bar, isNew: true);
// result.Value contains the volatility-adjusted average
}
With OHLC Data (Recommended)
// TBar provides proper True Range calculation
var bar = new TBar(time, open, high, low, close, volume);
var result = vama.Update(bar, isNew: true);
With Single Values (Limited)
// Single values create synthetic bar with O=H=L=C
// This results in TR=0, so period stays at baseLength
var value = new TValue(time, close);
var result = vama.Update(value, isNew: true);
Note: For proper volatility adaptation, VAMA requires OHLC data. Single-value input forces TR=0 and disables the adaptive behavior.
Event-Driven Chaining
var source = new TBarSeries();
var vama = new Vama(source, baseLength: 20);
// VAMA subscribes to source.Pub events
source.Add(new TBar(...)); // Triggers VAMA update
Common Pitfalls
-
Using TValue input: VAMA needs OHLC for True Range. Single values produce zero TR and no adaptation.
-
Mismatched ATR periods: Short period should be significantly less than long period (typically 5:1 ratio). Similar periods produce ratio ≈ 1 and minimal adaptation.
-
Narrow min/max range: If
minLengthandmaxLengthare too close, the adaptive behavior is constrained. Allow meaningful range. -
Forgetting warmup: Both ATR calculations need warmup (especially the longer one). Early values before
IsHotare approximations. -
Over-optimizing parameters: The default 10/50 ATR ratio works across most instruments. Excessive parameter tuning often means overfitting to historical data.
Comparison with Alternatives
| Indicator | Adaptation Mechanism | OHLC Required |
|---|---|---|
| VAMA | ATR volatility ratio | Yes (for proper operation) |
| KAMA | Efficiency ratio (direction vs noise) | No |
| VIDYA | Standard deviation ratio | No |
| JMA | Proprietary adaptive filter | No |
VAMA's ATR-based approach specifically responds to range expansion/contraction, making it well-suited for instruments with significant intrabar movement or gaps. KAMA responds to directional efficiency, VIDYA to statistical volatility.
References
- Wilder, J.W. (1978). "New Concepts in Technical Trading Systems" - ATR and RMA foundations
- PineScript reference implementation:
vama.pine