mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-05 04:27:43 +00:00
125 lines
6.1 KiB
Markdown
125 lines
6.1 KiB
Markdown
# CMA: Cumulative Moving Average
|
|
|
|
> *The running average that never forgets. Every single tick you've ever fed it? Still in there, affecting the result. It's like the elephant of technical indicators.*
|
|
|
|
| Property | Value |
|
|
| ---------------- | -------------------------------- |
|
|
| **Category** | Statistic |
|
|
| **Inputs** | Source (close) |
|
|
| **Parameters** | `source` |
|
|
| **Outputs** | Single series (CMA) |
|
|
| **Output range** | Varies (see docs) |
|
|
| **Warmup** | `1` bars |
|
|
| **PineScript** | [cma.pine](cma.pine) |
|
|
|
|
- The Cumulative Moving Average (CMA) calculates the arithmetic mean of ALL data points seen so far, not just a fixed window.
|
|
- **Similar:** [SMA](../../trends_FIR/sma/Sma.md), [EMA](../../trends_IIR/ema/ema.md) | **Trading note:** Cumulative Moving Average; running mean of all data points. Anchored VWAP without volume weighting.
|
|
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
|
|
|
|
The Cumulative Moving Average (CMA) calculates the arithmetic mean of ALL data points seen so far, not just a fixed window. Unlike SMA or EMA which use a sliding window, CMA treats every historical value with equal weight. As the sample size grows, each new value has diminishing impact on the average.
|
|
|
|
## Historical Context
|
|
|
|
The concept of a running mean is fundamental to statistics and was formalized by B. P. Welford in 1962 for numerically stable computation. Donald Knuth popularized it in *The Art of Computer Programming*. While not a traditional trading indicator, CMA is essential for scenarios requiring the true average of all observed data: calculating session VWAP from scratch, averaging tick counts, or computing lifetime average fill prices.
|
|
|
|
## Architecture & Physics
|
|
|
|
The naive approach (sum all values, divide by count) works for small datasets but fails at scale. After millions of ticks, the running sum can overflow or lose precision.
|
|
|
|
### Welford's Algorithm with FMA
|
|
|
|
QuanTAlib uses Welford's numerically stable update, enhanced with Fused Multiply-Add (FMA) for maximum precision:
|
|
|
|
$$ M_n = M_{n-1} + \alpha \cdot (x_n - M_{n-1}) \quad \text{where } \alpha = \frac{1}{n} $$
|
|
|
|
Implemented as:
|
|
|
|
```csharp
|
|
double alpha = 1.0 / n;
|
|
double delta = x - mean;
|
|
mean = Math.FusedMultiplyAdd(alpha, delta, mean);
|
|
```
|
|
|
|
This formulation:
|
|
|
|
1. Keeps intermediate values near the scale of the actual mean (no overflow)
|
|
2. Requires only O(1) memory (just count and mean)
|
|
3. Achieves O(1) time complexity per update
|
|
4. Uses FMA for single-rounding precision (avoids rounding `alpha * delta` before adding to `mean`)
|
|
5. Is mathematically equivalent to $M_n = \frac{(n-1) \cdot M_{n-1} + x_n}{n}$
|
|
|
|
### Why Not Just Sum?
|
|
|
|
Consider averaging 10 million tick prices around 50,000 (a futures contract). The naive sum exceeds $5 \times 10^{11}$, approaching the precision limits of `double`. Welford's algorithm keeps the working value around 50,000 throughout, maintaining full precision.
|
|
|
|
### The Diminishing Return Problem
|
|
|
|
As $n$ grows large, each new value contributes only $\frac{1}{n}$ to the mean. After 1 million samples, a new tick moves the average by roughly 0.0001% of the difference from the current mean. This is mathematically correct but may not be what traders want for responsiveness (use EMA or SMA for that).
|
|
|
|
## Mathematical Foundation
|
|
|
|
### 1. Incremental Update (Welford)
|
|
|
|
$$ M_n = M_{n-1} + \frac{x_n - M_{n-1}}{n} $$
|
|
|
|
Where:
|
|
|
|
* $M_n$ = cumulative mean after $n$ values
|
|
* $M_{n-1}$ = previous cumulative mean
|
|
* $x_n$ = new value
|
|
* $n$ = total count of values
|
|
|
|
### 2. Algebraic Equivalence
|
|
|
|
$$ M_n = \frac{1}{n} \sum_{i=1}^{n} x_i = \frac{(n-1) \cdot M_{n-1} + x_n}{n} $$
|
|
|
|
## Performance Profile
|
|
|
|
### Operation Count (Streaming Mode)
|
|
|
|
Cumulative Mean Arithmetic uses a simple running sum divided by count — no window, no buffer.
|
|
|
|
| Operation | Count | Cost (cycles) | Subtotal |
|
|
| :--- | :---: | :---: | :---: |
|
|
| Add value to running sum | 1 | 1 cy | ~1 cy |
|
|
| Increment count | 1 | 1 cy | ~1 cy |
|
|
| Divide sum by count | 1 | 4 cy | ~4 cy |
|
|
| NaN guard + state update | 1 | 2 cy | ~2 cy |
|
|
| **Total** | **O(1)** | — | **~8 cy** |
|
|
|
|
Cheapest mean variant — no buffer, no window management. Throughput limited by division latency (~4 cy on modern x86).
|
|
|
|
| Metric | Score | Notes |
|
|
| :--- | :--- | :--- |
|
|
| **Throughput** | ~5 ns/bar | Single division per update. |
|
|
| **Allocations** | 0 | Zero-allocation in hot paths. |
|
|
| **Complexity** | O(1) | Constant time regardless of history length. |
|
|
| **Accuracy** | 10 | Welford's algorithm ensures numerical stability. |
|
|
| **Timeliness** | 1 | Maximum lag; every historical value affects output. |
|
|
| **Overshoot** | 0 | Never overshoots the input data range. |
|
|
| **Smoothness** | 10 | Extremely smooth as $n$ grows (almost constant). |
|
|
|
|
## Validation
|
|
|
|
| Library | Status | Notes |
|
|
| :--- | :--- | :--- |
|
|
| **TA-Lib** | N/A | No CMA function. |
|
|
| **Skender** | N/A | No CMA function. |
|
|
| **Tulip** | N/A | No CMA function. |
|
|
| **Mathematical** | ✅ | Validated against known formulas. |
|
|
|
|
CMA is a fundamental statistical operation rather than a standard TA library indicator. QuanTAlib validates against mathematical proofs: arithmetic progressions, geometric series, and direct sum/count calculations.
|
|
|
|
## Use Cases
|
|
|
|
1. **Session VWAP**: Calculate volume-weighted average price from session start
|
|
2. **Lifetime Averages**: Average fill price across all trades
|
|
3. **Quality Metrics**: Average latency, slippage, or fill rate over time
|
|
4. **Baseline Comparison**: Compare current price to "all-time average"
|
|
|
|
## Common Pitfalls
|
|
|
|
1. **Responsiveness**: CMA becomes nearly unresponsive after many values. For a reactive average, use SMA or EMA instead.
|
|
2. **Memory of Bad Data**: A single extreme outlier early in the stream permanently affects the average. Consider filtering before feeding CMA.
|
|
3. **No Period Parameter**: Unlike SMA/EMA, CMA has no period. It always includes all data. This is by design.
|
|
4. **Session Resets**: If you need per-session averages, call `Reset()` at session boundaries. |