7.1 KiB
TRIM: Trimmed Mean Moving Average
Trimmed mean drops the extreme tails before averaging — robust estimation that refuses to let outliers hijack the center.
| Property | Value |
|---|---|
| Category | Statistic |
| Inputs | Source (close) |
| Parameters | period, trimPct (default 10.0) |
| Outputs | Single series (Trim) |
| Output range | Varies (see docs) |
| Warmup | period bars |
| PineScript | trim.pine |
- The Trimmed Mean Moving Average computes a rolling average after discarding a configurable percentage of the most extreme values from each tail of ...
- Similar: Wins, Median | Trading note: Trimmed mean; excludes extreme percentiles. Robust average for volatile data.
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
The Trimmed Mean Moving Average computes a rolling average after discarding a configurable percentage of the most extreme values from each tail of the sorted lookback window. By removing the lowest and highest trimPct% of observations, TRIM eliminates the influence of outliers while retaining more information than a pure median. At trimPct = 0 it degenerates to the SMA; at trimPct = 50 it becomes the median. The default 10% trim provides a robust central tendency estimator that resists spike contamination with minimal loss of responsiveness, requiring O(N \log N) for the sort plus O(N) for the summation per bar.
Historical Context
The trimmed mean was introduced by W.J. Dixon (1960) as part of a systematic study of robust estimators for location. John Tukey (1960, 1977) championed its use as part of his program of exploratory data analysis, arguing that no single estimator dominates all contamination models, and the trimmed mean provides a practical compromise between efficiency under normality (where the SMA is optimal) and resistance to outliers (where the median excels).
In financial applications, the trimmed mean addresses a pervasive problem: price series contain erroneous ticks, flash crashes, and gap events that can corrupt moving average calculations. A single outlier in a 20-bar SMA shifts the average by 1/20 = 5\% of the outlier magnitude. The trimmed mean bounds this influence: with a 10% trim on 20 bars, the 2 lowest and 2 highest values are discarded, and the remaining 16 values contribute equally. If an outlier falls in a discarded tail, it has zero effect.
The trimmed mean also appears in economic statistics: the Federal Reserve Bank of Cleveland publishes a 16% trimmed-mean CPI as an alternative inflation measure that filters out volatile food and energy prices.
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 arranges the values in ascending order using Pine's built-in array.sort(). This is O(N \log N) and dominates the per-bar cost.
Step 3: Trimmed average computes the arithmetic mean of the middle keepCount values:
\text{trimCount} = \left\lfloor \frac{\text{period} \times \text{trimPct}}{100} \right\rfloor
\text{keepCount} = \text{period} - 2 \times \text{trimCount}
\text{TRIM} = \frac{1}{\text{keepCount}} \sum_{i=\text{trimCount}}^{\text{trimCount} + \text{keepCount} - 1} x_{(i)}
where x_{(i)} denotes the $i$-th order statistic.
Edge case: If keepCount would fall below 1 (extreme trim percentage with small period), the implementation clamps it to 1 and adjusts trimCount accordingly, effectively returning the median.
Comparison with WINS: TRIM discards extreme values entirely, reducing the effective sample size. WINS (Winsorized mean) replaces extremes with boundary values, preserving the full sample size. TRIM has a higher breakdown point for the same percentage, but WINS is more efficient when outliers are moderate rather than extreme.
Mathematical Foundation
The $\alpha$-trimmed mean for a sample of size n:
\bar{x}_\alpha = \frac{1}{n - 2k} \sum_{i=k+1}^{n-k} x_{(i)}
where k = \lfloor \alpha \cdot n \rfloor and \alpha = \text{trimPct}/100.
Influence function: The trimmed mean has a bounded influence function that equals zero outside the trimmed range:
\text{IF}(x; \bar{x}_\alpha) = \begin{cases} 0 & \text{if } x < x_{(\alpha)} \text{ or } x > x_{(1-\alpha)} \\ \frac{x - \bar{x}_\alpha}{1 - 2\alpha} & \text{otherwise} \end{cases}
Breakdown point: \alpha (the trim fraction). With 10% trim, up to 10% of the data can be arbitrarily corrupted without affecting the estimator.
Asymptotic efficiency relative to SMA under normality:
| Trim % | Efficiency |
|---|---|
| 0% | 100% (SMA) |
| 5% | ~98% |
| 10% | ~95% |
| 25% | ~85% |
| 50% | ~64% (median) |
Parameter constraints: period \ge 3, trimPct \in [0, 49].
TRIM(source, period, trimPct):
trimCount = floor(period * trimPct / 100)
keepCount = period - 2 * trimCount
if keepCount < 1: keepCount = 1
// Collect and sort
vals = [source[0], source[1], ..., source[period-1]]
sort(vals, ascending)
// Average middle portion
sum = 0
for i = trimCount to trimCount + keepCount - 1:
sum += vals[i]
return sum / keepCount
Performance Profile
Operation Count (Streaming Mode)
Trim collects the window, sorts it, discards the tail values, then averages the inner values.
| Operation | Count | Cost (cycles) | Subtotal |
|---|---|---|---|
| Ring buffer collect | N | 1 cy | ~N cy |
| Array sort (introsort) | N log N | 2 cy | ~2N log N cy |
| Sum inner values (N - 2k) | N - 2k | 2 cy | ~2(N-2k) cy |
| Divide for mean | 1 | 4 cy | ~4 cy |
| NaN guard + state update | 1 | 2 cy | ~2 cy |
| Total (N=20, k=2) | O(N log N) | — | ~220 cy |
O(N log N) per update due to sort. For small periods (N ≤ 64), the sort cost is dominated by cache effects; practical throughput is ~15 ns/bar.
Batch Mode (SIMD Analysis)
| Operation | Vectorizable? | Notes |
|---|---|---|
| Window collection | Yes | Gather from ring buffer with SIMD copy |
| Sort | No | Comparison sort is sequential |
| Inner-range sum | Yes | Contiguous range sum with Vector |
No whole-path SIMD; sort blocks vectorization. Batch is a loop of independent sorts — no cross-bar dependency, so outer loop parallelizable with PLINQ for large datasets.
Resources
- Dixon, W.J. "Simplified Estimation from Censored Normal Samples." Annals of Mathematical Statistics, 1960.
- Tukey, J.W. "Exploratory Data Analysis." Addison-Wesley, 1977.
- Huber, P.J. & Ronchetti, E. "Robust Statistics." 2nd edition, Wiley, 2009.
- Wilcox, R.R. "Fundamentals of Modern Statistical Methods." 2nd edition, Springer, 2010.
- Bryan, M. & Cecchetti, S. "Measuring Core Inflation." In Monetary Policy, NBER, 1994.