> *Jim Sloman looked at how volatility distributes across a window and asked: if the most volatile bars are recent, should the filter not respond faster? NMA derives its smoothing constant from the volatility profile itself, weighted by a square-root kernel that emphasizes recent action.*
- NMA is an adaptive IIR filter whose smoothing ratio is derived from a volatility-weighted square-root kernel analysis of log-price movements over a...
NMA is an adaptive IIR filter whose smoothing ratio is derived from a volatility-weighted square-root kernel analysis of log-price movements over a lookback window. When volatility concentrates in recent bars, the ratio approaches 1.0 (fast tracking). When volatility is spread uniformly, the ratio approaches $1/\sqrt{N}$ (heavy smoothing). The square-root kernel $(\sqrt{i+1} - \sqrt{i})$ gives a concave-down weighting that gently emphasizes recency, while the log-price transformation normalizes for price level, making the adaptation scale-invariant.
## Historical Context
Jim Sloman introduced the Natural Moving Average in *Ocean Theory* (pages 63-70), a book that applied chaos and complexity theory metaphors to financial markets. The NMA was designed as a "natural" filter that lets the market's own volatility structure determine the smoothing rate, rather than imposing an arbitrary period.
The core innovation is the square-root differencing kernel $\sqrt{i+1} - \sqrt{i}$ as the weighting function for volatility. This kernel has the property that its cumulative sum $\sqrt{N}$ grows sublinearly, meaning each additional bar in the lookback contributes less weight than the previous one. This creates a "diminishing returns" effect: extending the lookback adds context without drowning out recent information.
The log-price transformation ($\ln(\text{price}) \times 1000$) serves two purposes: (1) it makes the volatility measure proportional to percentage moves rather than absolute dollar moves, and (2) the scaling factor of 1000 brings typical values into a numerically convenient range for the ratio computation.
NMA belongs to the family of adaptive moving averages alongside KAMA, VIDYA, and ADXVMA, but uses a unique adaptation mechanism based on the spatial distribution of volatility rather than a single efficiency or strength metric.
## Architecture & Physics
### 1. Log-Price Buffer
A circular buffer of size $N+1$ stores $\ln(\text{price}) \times 1000$ for each bar, providing the lookback data for volatility computation.
For `period = 40`: approximately 164 FLOPs per streaming update.
### Batch Mode (SIMD Analysis)
The inner `ComputeRatio()` loop walks backward through the ring buffer with data-dependent indexing, which resists SIMD vectorization. The batch `Calculate(Span)` method uses the same scalar loop per bar.
SIMD opportunity exists for the sqrt-weight precomputation (done once in the constructor), but not for the per-bar ratio computation due to the sequential buffer access pattern.
| Metric | Score |
|--------|-------|
| Streaming latency | 8/10 (O(N) per bar, but small constant) |
| Batch throughput | 5/10 (O(N*M) total, no SIMD in hot loop) |
| `_state` | State | 32B | Current NMA, last NMA, bar count, flags |
| `_p_state` | State | 32B | Previous state for rollback |
| **Total** | | ~144B + 3Nx8B | |
For `period = 40`: approximately 144 + 984 = **1128 bytes** per instance.
### Bar Correction Pattern
NMA requires full buffer copy (`CopyFrom`) for bar correction rather than the lighter `Snapshot`/`Restore` used by simpler indicators. The reason: `ComputeRatio()` reads all buffer positions during backward traversal, so a single-value restore is insufficient.
- Mathematical verification: ratio bounds $[1/\sqrt{N}, 1]$ confirmed
- Edge cases: NaN/Infinity handling, bar correction precision
## Common Pitfalls
1.**Log of non-positive prices**: If `price <= 0`, `Math.Log` returns `-Infinity` or `NaN`. The implementation guards with `price > 0 ? Math.Log(price) * 1000 : 0.0`.
2.**Bar correction drift with Snapshot/Restore**: RingBuffer's `Snapshot()`/`Restore()` only saves one buffer position. NMA's `ComputeRatio()` reads ALL positions, so `CopyFrom()` is mandatory. Using Snapshot/Restore produces ~1% drift after corrections.
3.**Zero denominator in ratio**: When all adjacent log-prices are identical ($o_i = 0$ for all $i$), the denominator is zero. The implementation returns `ratio = 0`, causing NMA to hold its previous value.
4.**Period = 1 degeneracy**: With a single-bar lookback, `ComputeRatio()` has zero iterations and returns 0. NMA becomes a constant after initialization. Use `period >= 2` for meaningful adaptation.
5.**Log-scale amplification**: The $\times 1000$ scaling factor amplifies differences between log-prices. While this improves numerical resolution for the ratio computation, it also amplifies floating-point errors during buffer operations.
6.**Memory cost of CopyFrom**: Each bar correction copies the entire buffer array ($N+1$ doubles = 328 bytes for period 40). This is ~8x more expensive than Snapshot/Restore but necessary for correctness.
7.**No external validation available**: Unlike SMA, EMA, or KAMA, there are no reference implementations to validate against. All correctness assurance comes from internal consistency tests and mathematical bound verification.