Skip to content

Median Absolute Deviation (MAD)

Robust dispersion estimator — the median of absolute deviations from the window's median. The median analogue of standard deviation: ignores extreme outliers (a single huge spike barely moves the result) and is widely used as a sturdier alternative to StdDev for risk reporting on heavy-tailed return distributions.

Quick reference

ItemValue
FamilyPrice Statistics
Input typef64
Output typef64
Output range[0, ∞)
Default parametersperiod required
Warmup periodperiod
InterpretationOutlier-resistant volatility measure

Formula

med = median(window)
MAD = median( |x_i - med|  for x_i in window )

Multiplying MAD by 1.4826 gives a consistent estimator of the underlying Gaussian standard deviation ("robust σ"). Wickra returns raw MAD; multiply downstream if you want the σ equivalent. See crates/wickra-core/src/indicators/median_absolute_deviation.rs.

Parameters

NameTypeDefaultConstraintDescription
periodusizenone> 0Rolling window.

Inputs / Outputs

Indicator<Input = f64, Output = f64>. Standard binding shapes.

Warmup

warmup_period() == period.

Edge cases

  • All-identical input. MAD = 0.
  • Outlier robustness. Single spike that would inflate StdDev by 5x barely changes MAD (~1x).
  • Cost. Each update is O(period · log period) for the sort; acceptable for period ≤ 252.
  • Reset. Clears the rolling window.

Examples

Rust

rust
use wickra::{BatchExt, Indicator, MedianAbsoluteDeviation};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut series: Vec<f64> = (0..50).map(|i| 100.0 + f64::from(i % 5)).collect();
    series[25] = 200.0;  // outlier
    let mut mad = MedianAbsoluteDeviation::new(20)?;
    println!("row 30 MAD = {:?}", mad.batch(&series)[30]);
    Ok(())
}

Python

python
import numpy as np
import wickra as ta

series = (100 + np.arange(50) % 5).astype(float)
series[25] = 200.0
mad = ta.MedianAbsoluteDeviation(20)
print(mad.batch(series)[30])

Node

javascript
const wickra = require('wickra');
const mad = new wickra.MedianAbsoluteDeviation(20);
const series = Array.from({ length: 50 }, (_, i) => 100 + i % 5);
series[25] = 200;
console.log(mad.batch(series)[30]);

Streaming

rust
use wickra::{Indicator, MedianAbsoluteDeviation};

let mut mad = MedianAbsoluteDeviation::new(50).unwrap();
let price_stream: Vec<f64> = Vec::new(); // your live price feed
for px in price_stream {
    if let Some(v) = mad.update(px) {
        let robust_sigma = v * 1.4826;
        // Use robust_sigma in place of StdDev for outlier-robust risk
    }
}

Interpretation

  • Robust to outliers. MAD's breakdown point is 50% (you can corrupt half the data and MAD still works). StdDev's breakdown point is 0%.
  • Use for heavy-tailed series. Financial returns are notoriously heavy-tailed; MAD-based risk gives more stable readings than StdDev-based.
  • Robust σ. 1.4826 · MAD ≈ Gaussian σ for a normal population; useful when you want the σ-units interpretation but with outlier protection.

Common pitfalls

  • MAD ≠ StdDev. Don't substitute MAD where σ is expected without applying the 1.4826 correction (or document the alternative units).
  • Cost on large windows. O(period · log period). Long windows on minute bars can be slow.

References

  • Frederick Hampel, The Influence Curve and Its Role in Robust Estimation, Journal of the American Statistical Association, 1974.

See also