9.9 KiB
DSMA: Deviation-Scaled Moving Average
When the market screams, DSMA sprints. When it whispers, DSMA crawls. An adaptive moving average that lets volatility dictate the pace.
| Property | Value |
|---|---|
| Category | Trend (IIR MA) |
| Inputs | Source (close) |
| Parameters | period, scaleFactor (default 0.5) |
| Outputs | Single series (Dsma) |
| Output range | Tracks input |
| Warmup | period bars |
| PineScript | dsma.pine |
| Signature | dsma_signature |
- DSMA (Deviation-Scaled Moving Average) is a volatility-adaptive trend filter that combines a Super Smoother (2-pole Butterworth IIR filter) with RM...
- Similar: DEMA, KAMA | Complementary: ADX for trend confirmation | Trading note: Deviation-Scaled MA; adapts smoothing based on price deviation.
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
DSMA (Deviation-Scaled Moving Average) is a volatility-adaptive trend filter that combines a Super Smoother (2-pole Butterworth IIR filter) with RMS-based deviation scaling. Unlike fixed-period moving averages that treat all market conditions identically, DSMA adjusts its responsiveness based on measured volatility—accelerating when trends are strong and decelerating when prices consolidate.
Historical Context
DSMA appears to be a proprietary or boutique indicator without mainstream adoption in commercial platforms. The algorithm surfaced in custom PineScript implementations, drawing from established signal processing concepts: Butterworth filtering for trend extraction (popularized by John Ehlers) and RMS deviation measurement for volatility assessment. This QuanTAlib implementation follows the PineScript reference, translating its recursive logic into high-performance C# with zero-allocation streaming updates.
Architecture & Physics
DSMA operates in three stages, each addressing a specific signal processing challenge:
Stage 1: Trend Extraction via Super Smoother
The Super Smoother is a 2-pole Butterworth low-pass filter—the same topology used in analog audio circuits to eliminate high-frequency noise without phase distortion. Ehlers adapted it for financial time series by discretizing the transfer function:
H(z) = \frac{c_0 + c_1 z^{-1} + c_2 z^{-2}}{1 - a_1 z^{-1} - a_2 z^{-2}}
Coefficients are precomputed from the period parameter:
\omega = \frac{\sqrt{2} \cdot \pi}{\text{period}}
a = e^{-\omega}
c_0 = \frac{(1 - a)^2}{1 + 2a \cos(\omega) + a^2}
The filter maintains two delay states (z^{-1}, z^{-2}) and produces a smooth baseline trend (\text{filt}_t) with minimal lag for its degree of smoothing.
Stage 2: Volatility Measurement via RMS
Root Mean Square (RMS) quantifies the magnitude of oscillations around the filtered trend:
\text{RMS}_t = \sqrt{\frac{1}{N} \sum_{i=0}^{N-1} (\text{price}_{t-i} - \text{filt}_{t-i})^2}
RMS is computed incrementally over a rolling window using a circular RingBuffer for O(1) updates. Unlike standard deviation (which measures dispersion around a mean), RMS measures absolute deviation from the trend line—a more direct proxy for volatility in trend-following contexts.
Stage 3: Adaptive Alpha Scaling
The final EMA-style smoothing coefficient adapts based on the ratio of trend strength to volatility:
\alpha_t = \min\left(\text{scaleFactor} \cdot \frac{5}{\text{period}} \cdot \frac{|\text{filt}_t|}{\text{RMS}_t}, 1\right)
- Numerator (
|\text{filt}_t|): Captures the magnitude of the filtered deviation. - Denominator (
\text{RMS}_t): Normalizes by recent volatility, preventing over-reaction to noise. - Scale Factor: User-adjustable multiplier (default 0.5) to control overall responsiveness.
- Clamping: Alpha is bounded at 1.0 to prevent numerical instability.
When trends are strong relative to volatility (high signal-to-noise ratio), alpha approaches its maximum, and DSMA tracks price aggressively. During consolidation (low signal-to-noise), alpha shrinks, and DSMA smooths heavily.
The final output is an exponential moving average using this dynamic alpha:
\text{DSMA}_t = \alpha_t \cdot \text{price}_t + (1 - \alpha_t) \cdot \text{DSMA}_{t-1}
Implemented with fused multiply-add for single-rounding precision:
_state.Dsma = Math.FusedMultiplyAdd(_state.Dsma, 1.0 - alpha, alpha * input.Value);
Performance Profile
DSMA combines the computational cost of a 2-pole IIR filter, a rolling RMS calculation, and an EMA update—still achieving constant-time complexity through incremental ring buffer updates.
Operation Count (Streaming Mode, Scalar)
| Operation | Count | Cost (cycles) | Subtotal |
|---|---|---|---|
| Stage 1: Deviation Calculation | |||
| SUB (zeros = value - result) | 1 | 1 | 1 |
| Stage 2: Super Smoother (2-pole Butterworth) | |||
| ADD (zeros + zeros1) | 1 | 1 | 1 |
| MUL (c1Half × sum) | 1 | 3 | 3 |
| FMA (filt1 × b1 - a1Sq × filt2) | 1 | 4 | 4 |
| MUL (a1Sq × filt2) | 1 | 3 | 3 |
| ADD (filtPart1 + filtPart2) | 1 | 1 | 1 |
| Stage 3: RMS Buffer Update | |||
| MUL (filt × filt) | 1 | 3 | 3 |
| ADD/SUB (sumSquared update) | 2 | 1 | 2 |
| FMA (running sum) | 1 | 4 | 4 |
| Stage 4: RMS Calculation | |||
| MUL (sumSquared × periodRecip) | 1 | 3 | 3 |
| CMP/MAX (MinRms guard) | 1 | 1 | 1 |
| SQRT | 1 | 15 | 15 |
| Stage 5: Alpha Calculation | |||
| ABS | 1 | 1 | 1 |
| DIV (filt / rms) | 1 | 15 | 15 |
| MUL (scaleAdjustment × ratio) | 1 | 3 | 3 |
| CMP/MIN (clamp to 1.0) | 1 | 1 | 1 |
| Stage 6: Adaptive EMA | |||
| SUB (1 - alpha) | 1 | 1 | 1 |
| FMA (result × decay + alpha × value) | 1 | 4 | 4 |
| MUL (alpha × value) | 1 | 3 | 3 |
| Total | ~69 cycles |
Dominant costs:
- SQRT (15 cycles, 22%) — RMS calculation
- DIV (15 cycles, 22%) — alpha normalization by RMS
- Super Smoother filter (~12 cycles, 17%) — 2-pole IIR recursion
Batch Mode (SIMD Analysis)
DSMA is not SIMD-parallelizable across bars due to:
- Super Smoother is a 2-pole IIR filter with recursive state (filt[t-1], filt[t-2])
- Adaptive alpha depends on current RMS which depends on running sum
- Final EMA output feeds back as input to next iteration
FMA optimization (already applied):
- RMS running sum update uses FMA
- Final adaptive EMA uses FMA pattern
Quality Metrics
| Metric | Score | Notes |
|---|---|---|
| Accuracy | 7/10 | Volatile in choppy markets; shines in trends |
| Timeliness | 8/10 | Adaptive lag—minimal during strong trends |
| Overshoot | 6/10 | Can overshoot when volatility spikes suddenly |
| Smoothness | 8/10 | Super Smoother baseline ensures good filtering |
Benchmarked on Intel i7-12700K @ 3.6 GHz (Turbo off), AVX2, .NET 10.0, 10K iterations.
Validation
DSMA is not implemented in mainstream libraries (TA-Lib, Skender, Tulip, Ooples). Validation relies on behavioral testing against known algorithm properties.
| Library | Status | Notes |
|---|---|---|
| TA-Lib | N/A | Not implemented |
| Skender | N/A | Not implemented |
| Tulip | N/A | Not implemented |
| Ooples | N/A | Not implemented |
| Behavioral | ✅ | Validated: trend following, volatility response, bounds |
Behavioral Test Summary
- Trend Following: DSMA converges to price during sustained trends (10 consecutive bars ±1%, final deviation <2%)
- Volatility Response: Higher scale factor (0.9 vs 0.1) produces 3-5x larger deviation during volatile periods
- Smoothness: Output exhibits <50% of input variance when volatility is low (validated over 1000 GBM bars)
- Bounds: Output remains within [min, max] price range ±1% tolerance
- Mathematical Consistency: Streaming updates match batch calculations (ε < 1e-10)
Common Pitfalls
-
Warmup Period: DSMA requires
Periodbars to fill the Super Smoother delay line and RMS buffer. The firstPeriodoutputs will be unstable. UseIsHotto detect when the indicator has sufficient history. -
Scale Factor Sensitivity: The default
scaleFactor = 0.5balances responsiveness and stability. Values >0.7 can cause whipsaws in choppy markets; values <0.3 introduce excessive lag. Tune this parameter based on your asset's typical volatility regime. -
Volatility Normalization: The RMS denominator in the alpha formula can approach zero during extended flat periods, causing alpha to spike. The implementation clamps alpha at 1.0, but extremely low volatility can still produce jittery behavior. Consider a minimum RMS threshold (not implemented in this version).
-
Not a Momentum Oscillator: DSMA is a trend filter, not a momentum indicator. Do not confuse high alpha values with strong momentum—alpha reflects signal-to-noise ratio, not directional strength. Use a separate momentum indicator (RSI, MACD) for confirmation.
-
Comparison with JMA: DSMA uses a simpler adaptive mechanism than JMA (which employs fractal efficiency and phase adjustment). JMA typically offers smoother output and better overshoot control but at higher computational cost. DSMA is faster and more transparent algorithmically.
-
Bar Correction: Like all QuanTAlib indicators, DSMA supports bar correction via the
isNewparameter. WhenisNew = false, it rolls back to the previous state before recalculating. Ensure your data feed correctly signals bar updates versus corrections. -
SIMD Limitation: The recursive nature of the Super Smoother filter and adaptive alpha calculation precludes efficient SIMD vectorization. The
Calculate(Span)method uses a scalar loop. For bulk backtesting, consider parallelizing across multiple series rather than within a single series.