- The Winsorized Mean Moving Average computes a rolling average after replacing (not discarding) the most extreme values in each tail with the bounda...
The Winsorized Mean Moving Average computes a rolling average after replacing (not discarding) the most extreme values in each tail with the boundary values at the trim point. Unlike the trimmed mean (TRIM) which removes outliers entirely, Winsorization preserves the full sample size by clamping extreme values to the nearest non-extreme observation. At `winPct = 0` it degenerates to the SMA; at `winPct = 50` all values equal the median pair. The default 10% Winsorization provides a robust central tendency estimator that dampens outlier impact while maintaining the statistical efficiency advantages of the full sample size.
## Historical Context
Winsorization is named after Charles P. Winsor, a biostatistician at Harvard, though the technique was popularized by John Tukey (1962) who credited Winsor with the idea. The concept arises naturally from the question: "what if instead of throwing away extreme values, we replace them with the most extreme non-discarded value?" This produces an estimator that is more efficient than the trimmed mean under light contamination models while retaining comparable robustness.
The distinction between trimming and Winsorizing is subtle but consequential. Consider a 20-bar window with 10% processing: TRIM discards the 2 lowest and 2 highest values, averaging the remaining 16. WINS replaces the 2 lowest with the 3rd-lowest value and the 2 highest with the 3rd-highest, averaging all 20. Both have the same breakdown point (10%), but WINS has higher asymptotic efficiency because it uses all $n$ observations in the average.
In financial applications, Winsorization is standard practice in factor modeling: Fama-French factor returns are typically Winsorized at 1% or 5% to prevent a handful of extreme observations from dominating cross-sectional regressions. The Winsorized mean is also used in the construction of robust risk measures like the Winsorized variance and the Winsorized covariance matrix.
## Architecture and Physics
The computation has three steps per bar:
**Step 1: Collection** gathers the most recent `period` values into an array, substituting 0 for NaN via `nz()`.
**Step 2: Sort and clamp** arranges values in ascending order, then replaces the lowest `winCount` values with the value at index `winCount` (the lower boundary) and the highest `winCount` values with the value at index `period - 1 - winCount` (the upper boundary):
The clamping preserves the boundary values themselves; only values beyond them are replaced.
**Step 3: Average** computes the arithmetic mean of all `period` values (including the replaced ones). Since replaced values equal the boundary values, this is equivalent to:
where $k = \text{winCount}$ and $x_{(i)}$ is the $i$-th order statistic.
**Edge case**: If `winCount` would reach or exceed `period / 2`, it is clamped to `(period - 1) / 2`, producing the median pair (two middle values) replicated across all positions.
## Mathematical Foundation
The **Winsorized mean** for a sample of size $n$ with $k$ replacements per tail:
O(N log N) per update due to sort. Slightly higher total cost than TRIM because the sum includes all N values (not N-2k), but both are dominated by the sort.
### Batch Mode (SIMD Analysis)
| Operation | Vectorizable? | Notes |
| :--- | :---: | :--- |
| Window collection | Yes | Gather from ring buffer with SIMD copy |
| Full-window sum | Yes | Vector<double> sum over N values |
Sort blocks SIMD on the main path. The sum phase can use Vector<double> for modest gains. Outer loop (across M bars) has no cross-bar dependency — suitable for parallel batch.