Files

8.6 KiB
Raw Permalink Blame History

WRMSE: Weighted Root Mean Squared Error

Not all errors are created equal—WRMSE lets you decide which ones matter most.

Property Value
Category Error Metric
Inputs Actual vs Predicted (dual input)
Parameters period
Outputs Single series (Wrmse)
Output range \geq 0
Warmup period bars
PineScript wrmse.pine
  • WRMSE extends the classic RMSE by incorporating weights for each observation, enabling analysts to emphasize critical data points such as recent ob...
  • Similar: RMSE, WMAPE | Trading note: Weighted RMSE; emphasizes accuracy at specific points. Useful for time-decay weighting.
  • Validated against TA-Lib, Skender, and Tulip reference implementations where available.

WRMSE extends the classic RMSE by incorporating weights for each observation, enabling analysts to emphasize critical data points such as recent observations, high-volume periods, or specific market regimes. When all weights are equal, WRMSE reduces exactly to RMSE, making it a strict generalization. This implementation uses dual RingBuffers for O(1) streaming updates with periodic resync to manage floating-point drift.

Historical Context

Root Mean Squared Error has been a foundational metric in statistics and signal processing since Gauss's work on least squares in the early 19th century. The weighted variant emerged naturally from generalized least squares theory, where heteroscedasticity (non-constant variance) necessitates giving different importance to different observations.

In financial contexts, weighting becomes essential because market conditions vary significantly: a 1% error during a flash crash carries different implications than the same error during low-volatility consolidation. Volume-weighted errors, recency-weighted errors, and regime-adaptive weighting schemes all build on this foundation.

The implementation here maintains exact mathematical equivalence to RMSE when weights are uniform, verified through comparison tests against our standard RMSE indicator.

Architecture & Physics

The indicator maintains two parallel RingBuffers tracking weighted squared errors and weights separately, enabling proper normalization as the window slides.

1. Dual Buffer State Management

The state tracks running sums for both numerator and denominator:


\text{State} = \begin{cases}
\text{WeightedErrorSum} & \sum_{i \in W} w_i \cdot (a_i - p_i)^2 \\
\text{WeightSum} & \sum_{i \in W} w_i
\end{cases}

where W is the current window of observations.

2. O(1) Streaming Updates

Each new observation triggers constant-time updates via the sliding window pattern:


\text{WeightedErrorSum}_{t} = \text{WeightedErrorSum}_{t-1} - \text{oldest}_e + w_t \cdot (a_t - p_t)^2

\text{WeightSum}_{t} = \text{WeightSum}_{t-1} - \text{oldest}_w + w_t

3. Bar Correction Support

The isNew=false pattern enables bar correction for live trading scenarios where the current bar's values may update multiple times before close. State rollback uses _p_state (previous valid state) to restore buffers to the pre-correction position.

4. Floating-Point Drift Mitigation

Running sums accumulate floating-point errors over time. Periodic resync (every 1000 ticks by default) recalculates sums from buffer contents to bound drift.

Mathematical Foundation

Core Formula


\text{WRMSE} = \sqrt{\frac{\sum_{i=1}^{n} w_i \cdot (a_i - p_i)^2}{\sum_{i=1}^{n} w_i}}

where:

  • a_i = actual value at position i
  • p_i = predicted value at position i
  • w_i = weight at position i (must be non-negative)
  • n = window size (period)

Reduction to RMSE

When all weights are equal (w_i = c for constant c):


\text{WRMSE} = \sqrt{\frac{c \cdot \sum_{i=1}^{n} (a_i - p_i)^2}{n \cdot c}} = \sqrt{\frac{\sum_{i=1}^{n} (a_i - p_i)^2}{n}} = \text{RMSE}

Weight Normalization

The denominator \sum w_i ensures the metric remains scale-invariant with respect to weight magnitude. Doubling all weights produces identical results.

NaN/Invalid Value Handling

Invalid inputs (NaN, Infinity, negative weights) substitute the last valid value:


v_t = \begin{cases}
v_t & \text{if } v_t \text{ is finite and valid} \\
v_{\text{last valid}} & \text{otherwise}
\end{cases}

Performance Profile

Operation Count (Streaming Mode, Scalar)

Operation Count Cost (cycles) Subtotal
Validation/NaN checks 3 1 3
SUB (diff) 1 1 1
MUL (diff², weight×diff²) 2 3 6
ADD/SUB (running sums) 4 1 4
DIV 1 15 15
SQRT 1 15 15
CMP (weight threshold) 1 1 1
Total ~13 ~45 cycles

The dominant costs are DIV and SQRT (67% combined), consistent with other RMSE-family indicators.

Batch Mode (SIMD/FMA)

For uniform weights, the batch path delegates to the same SIMD infrastructure as RMSE:

Operation Scalar Ops SIMD Ops (AVX2) Speedup
Squared error computation N N/4 4×
Rolling mean N N (sequential) 1×

For weighted batch computation, an additional weight multiplication occurs in the SIMD loop, but the rolling aggregation remains sequential due to the cumulative nature of the window.

Per-bar efficiency:

Mode Cycles/bar Notes
Streaming (uniform weights) ~45 Uses default weight 1.0
Streaming (custom weights) ~48 Additional weight validation
Batch SIMD (uniform) ~30 Amortized over 4-wide vectors
Batch SIMD (weighted) ~35 Weight multiplication in SIMD

Quality Metrics

Metric Score Notes
Accuracy 10/10 Exact formula implementation
Flexibility 9/10 Custom weights enable regime adaptation
Interpretability 8/10 Same units as input, but weights add complexity
Robustness 9/10 NaN handling, negative weight rejection
Performance 8/10 O(1) streaming, SIMD batch support

Validation

Library Status Notes
Internal RMSE Uniform weights match RMSE within 1e-10
Manual Calculation Step-by-step verification in tests
TA-Lib N/A No WRMSE implementation
Skender N/A No WRMSE implementation
Tulip N/A No WRMSE implementation

WRMSE is validated by:

  1. Mathematical equivalence to RMSE with uniform weights (BatchSpan_UniformWeights_MatchesStreaming, UniformWeightsBatch_MatchesRmseBatch)
  2. Manual calculation verification (Wrmse_CalculatesCorrectlyWithWeights)
  3. Weight influence tests (Wrmse_HigherWeightsHaveMoreInfluence)
  4. Streaming/batch parity tests for both uniform and custom weights

Common Pitfalls

  1. Weight Interpretation: Weights are multiplied by squared errors, not linear errors. A weight of 2.0 gives that observation twice the influence in the squared error sum, which may not align with intuitive expectations.

  2. Zero Weight Sum: If all weights in the window sum to effectively zero (< 1e-10), the result is 0.0 to avoid division by zero. This edge case should be rare in practice.

  3. Negative Weights: Negative weights are rejected and replaced with the last valid weight. Consider using absolute values or clamping in upstream processing if your weight source may produce negatives.

  4. Memory Footprint: Each instance allocates two RingBuffers of size period, doubling memory compared to unweighted RMSE. For a period of 100:

    • 2 buffers × 100 doubles × 8 bytes = 1,600 bytes per instance
    • 10,000 concurrent instances ≈ 15.3 MB
  5. Warmup Period: The indicator requires period observations before IsHot becomes true. During warmup, results use the available data but may not represent the full window statistics.

  6. Bar Correction: When using isNew=false, ensure you're correcting the most recent observation. Multiple corrections without intervening new bars work correctly, but the pattern assumes temporal locality.

References

  • Aitken, A.C. (1936). "On Least Squares and Linear Combinations of Observations." Proceedings of the Royal Society of Edinburgh.
  • Gauss, C.F. (1809). Theoria Motus Corporum Coelestium. (Foundation of least squares theory)
  • Greene, W.H. (2012). Econometric Analysis. 7th ed. Chapter 9: Generalized Least Squares.