What it does
The KAMA Trend Filter plots Perry Kaufman's Adaptive Moving Average and shades the chart in three states: trending up, trending down, or no trend. KAMA speeds up when price moves efficiently in one direction and slows almost to a halt when price chops sideways, so it naturally hugs trends and flattens in ranges.
The extra filter uses the same efficiency ratio that drives KAMA to decide whether there is a trend worth following at all. That makes it useful as a "should I be using a trend strategy right now?" switch on top of other tools.
How it works
- Efficiency ratio (ER) = |price − price n bars ago| ÷ sum of the absolute bar-to-bar changes over n bars. ER is 1 when price moved in a straight line and near 0 when it went nowhere.
- Fast constant = 2 ÷ (fast period + 1), slow constant = 2 ÷ (slow period + 1).
- Smoothing constant = (ER × (fast − slow) + slow)², which keeps KAMA between very slow and fairly fast.
- KAMA = previous KAMA + smoothing constant × (price − previous KAMA).
- For the filter, ER is smoothed with a short SMA. If it is at or above the threshold, the market is "trending"; direction comes from KAMA's change over the slope lookback. Otherwise the state is "no trend".
State changes are confirmed on bar close. The smoothed ER is visible in the Data Window.
How to use it
- Green background with a rising KAMA: trend-following ideas in the long direction have context. Red: the same for shorts. Grey: the market is inefficient, and breakout or trend entries tend to struggle.
- Many traders use the no-trend state to stand aside, or to switch to range tactics such as fading resistance and support.
- KAMA itself can act as a dynamic trailing reference in a clean trend.
- It suits H1–D1 on majors, gold, oil and indices. Raise the threshold for noisy instruments and lower it for smooth ones. The volatility lesson explains why the same settings behave differently across markets.
Settings
| Input | Default | What it changes |
|---|---|---|
| Source | close | Price used for ER and KAMA. |
| Efficiency ratio length | 10 | Window for the efficiency ratio. |
| Fast EMA period | 2 | Fastest KAMA speed. |
| Slow EMA period | 30 | Slowest KAMA speed. |
| Trend threshold (ER) | 0.30 | Higher = fewer bars classed as trending. |
| ER smoothing | 3 | Steadies the filter; 1 = raw ER. |
| Slope lookback (bars) | 3 | Bars used to judge KAMA direction. |
| Shade background by state | On | Background color by state. |
| Show trend-start labels | On | Up/Down labels and a cross for no-trend. |
Limitations
- The efficiency ratio is backward-looking. By the time it crosses the threshold, part of the move has already happened.
- A single fixed threshold does not fit every market or timeframe; you will need to tune it.
- Sharp news spikes can produce a high ER for a few bars and briefly label the market as trending.
- The filter describes the past only and does not forecast direction or the size of the next move.
Pine Script source
In TradingView open Pine Editor, paste the code, click Save and then Add to chart.
FXP_KamaTrendFilter.pine
67 lines
// © FXPIPS ONLINE — https://fxpips.online/tradingview-indicators/kama-trend-filter/
// License: MIT. Educational tool — not financial advice. Trading involves substantial risk.
//@version=6
// Kaufman Adaptive Moving Average plus an efficiency-ratio filter that shades the chart as
// trending up, trending down or no trend. State changes are confirmed on bar close.
indicator("FXP KAMA Trend Filter", shorttitle = "FXP KAMA", overlay = true)
// ── Inputs ─────────────────────────────────────────────────────────────
grpK = "KAMA"
src = input.source(close, "Source", group = grpK)
erLen = input.int(10, "Efficiency ratio length", minval = 2, group = grpK)
fastLen = input.int(2, "Fast EMA period", minval = 1, group = grpK)
slowLen = input.int(30, "Slow EMA period", minval = 2, group = grpK)
grpF = "Trend filter"
erThreshold = input.float(0.30, "Trend threshold (ER)", minval = 0.0, maxval = 1.0, step = 0.01, group = grpF, tooltip = "Smoothed efficiency ratio at or above this value counts as trending.")
erSmooth = input.int(3, "ER smoothing", minval = 1, group = grpF)
slopeBars = input.int(3, "Slope lookback (bars)", minval = 1, group = grpF)
grpV = "Display"
showBg = input.bool(true, "Shade background by state", group = grpV)
showSignals = input.bool(true, "Show trend-start labels", group = grpV)
colBull = input.color(#26a69a, "Uptrend color", group = grpV)
colBear = input.color(#ef5350, "Downtrend color", group = grpV)
colFlat = input.color(#9e9e9e, "No-trend color", group = grpV)
bgTransp = input.int(88, "Background transparency", minval = 0, maxval = 100, group = grpV)
// ── Efficiency ratio ───────────────────────────────────────────────────
direction = math.abs(src - src[erLen])
noise = math.sum(math.abs(src - src[1]), erLen)
erRaw = nz(noise > 0 ? direction / noise : 0.0)
erSmoothed = ta.sma(erRaw, erSmooth)
// ── KAMA ───────────────────────────────────────────────────────────────
fastSc = 2.0 / (fastLen + 1)
slowSc = 2.0 / (slowLen + 1)
sc = math.pow(erRaw * (fastSc - slowSc) + slowSc, 2)
var float kama = na
kama := na(kama) ? src : kama + sc * (src - kama)
// ── Trend state: 1 up, -1 down, 0 no trend ─────────────────────────────
kamaSlope = kama - kama[slopeBars]
trending = erSmoothed >= erThreshold
int state = trending and kamaSlope > 0 ? 1 : trending and kamaSlope < 0 ? -1 : 0
prevState = nz(state[1])
bullStart = state == 1 and prevState != 1 and barstate.isconfirmed
bearStart = state == -1 and prevState != -1 and barstate.isconfirmed
flatStart = state == 0 and prevState != 0 and barstate.isconfirmed
stateColor = state == 1 ? colBull : state == -1 ? colBear : colFlat
// ── Plots ──────────────────────────────────────────────────────────────
plot(kama, "KAMA", color = stateColor, linewidth = 2)
plot(erSmoothed, "Efficiency ratio", display = display.data_window)
bgcolor(showBg ? color.new(stateColor, bgTransp) : na, title = "Trend state background")
plotshape(showSignals and bullStart, "Uptrend start", style = shape.labelup, location = location.belowbar, color = colBull, text = "Up", textcolor = color.white, size = size.small)
plotshape(showSignals and bearStart, "Downtrend start", style = shape.labeldown, location = location.abovebar, color = colBear, text = "Down", textcolor = color.white, size = size.small)
plotshape(showSignals and flatStart, "No-trend start", style = shape.xcross, location = location.abovebar, color = colFlat, size = size.tiny)
// ── Alerts ─────────────────────────────────────────────────────────────
alertcondition(bullStart, "KAMA uptrend start", "KAMA filter switched to uptrend on {{ticker}} ({{interval}})")
alertcondition(bearStart, "KAMA downtrend start", "KAMA filter switched to downtrend on {{ticker}} ({{interval}})")
alertcondition(flatStart, "KAMA no-trend start", "KAMA filter switched to no-trend on {{ticker}} ({{interval}})")

