# KAMA — Kaufman Adaptive Moving Average
**EMA that adapts its smoothing factor to market conditions.** Fast
response when trending, heavy smoothing when noisy. Used by quant shops.
| Update cost | ~16 cycles |
| Memory | ~N×8 bytes (lookback buffer) |
| Types | `KamaF64` |
| Requires | `alloc` feature (runtime window size) |
| Priming | After N samples |
| Output | `Option<T>` — smoothed value once primed |
## What It Does
```
Trending signal: Noisy signal:
efficiency ratio ≈ 1.0 efficiency ratio ≈ 0.0
Value Value
120 ┤ · 120 ┤ · · ·
115 ┤ · 115 ┤ · ·
110 ┤ · 110 ┤ · ·
105 ┤ · 105 ┤ · · ·
100 ┤──·───────── KAMA tracks 100 ┤──·──·──·──────── KAMA barely moves
└────────────── t └────────────── t
α → fast (responsive) α → slow (smooths heavily)
```
The **efficiency ratio** measures how efficiently the signal is moving:
```
ER = direction / volatility (0 to 1)
```
- **ER ≈ 1.0** — signal is trending (straight line). KAMA responds fast.
- **ER ≈ 0.0** — signal is noisy (random walk). KAMA smooths heavily.
## When to Use It
**Use KAMA when:**
- Signal alternates between trending and mean-reverting
- Fixed alpha EMA is either too slow (misses trends) or too noisy (amplifies noise)
- You want one primitive that adapts to regime changes
**Don't use KAMA when:**
- Signal has consistent noise characteristics → [EMA](ema.md) is simpler
- You need direction detection → use [TrendAlert](trend-alert.md) or [Holt](holt.md)
- You need the absolute cheapest smoother → EMA at ~5 cycles vs KAMA at ~16
## Configuration
```rust
let mut kama = KamaF64::builder()
.window_size(10) // ER lookback window
.fast_span(2) // alpha when ER=1 (very reactive)
.slow_span(30) // alpha when ER=0 (very smooth)
.min_samples(10)
.build().unwrap();
```
### Parameters
| `window_size` | ER lookback window | Required | 10-20 typical |
| `fast_span` | EMA span when trending | 2 | Lower = more reactive at ER=1 |
| `slow_span` | EMA span when noisy | 30 | Higher = smoother at ER=0 |
## Examples
### Trading — Adaptive Price Smoothing
```rust
let mut price_kama = KamaF64::builder()
.window_size(10)
.fast_span(2)
.slow_span(30)
.build().unwrap();
if let Some(smoothed) = price_kama.update(mid_price) {
// Tracks trends closely, filters noise
}
// Check current regime:
if let Some(er) = price_kama.efficiency_ratio() {
if er > 0.7 { /* trending */ }
else { /* noisy / mean-reverting */ }
}
```
## Performance
| `KamaF64::update` (window=10) | 16 cycles | 25 cycles |
O(N) volatility recompute per update. For N=10, that's 9 subtractions
+ absolute values. Negligible for typical window sizes.
## Academic Reference
Kaufman, P.J. *Trading Systems and Methods.* Chapter on adaptive techniques.
Originally published in *Smarter Trading* (1995).