KAMA indicator · Pine Script v6
Kaufman Adaptive Moving Average on TradingView
KAMA changes how much weight it gives the latest price by comparing net movement with the total distance price traveled. Directional movement produces a faster response; repeated reversals produce a slower response. The final smoothing coefficient is squared, which matters when comparing KAMA with an EMA.
Use this page to check the formula, reproduce a small example and inspect a working script. The example defines its initialization and flat-window behavior explicitly; these choices can explain differences between implementations.
The KAMA formula, including the square
For source P and lookback N, calculate direction D and total movement V from N adjacent differences. Interpolate between the fast and slow EMA coefficients, square the result, then update the previous KAMA. This follows TradingView's KAMA calculation.
D = abs(P[t] - P[t-N])
V = sum(abs(P[t-i] - P[t-i-1]), i = 0 ... N-1)
ER = D / V
fast = 2 / (fastLength + 1)
slow = 2 / (slowLength + 1)
SC = (ER * (fast - slow) + slow)^2
KAMA[t] = KAMA[t-1] + SC * (P[t] - KAMA[t-1])N changes require N+1 source values. Summing signed changes would cancel reversals and make the denominator equal the net move; that destroys the comparison. ER is between 0 and 1 for a complete finite window with nonzero V. It measures path efficiency, not bullish direction or the probability of a profitable trade.
Fast 2 and slow 30 are inputs before squaring
Direct substitution gives SC=0.444444 at ER=1, SC=0.133657 at ER=0.5, and SC=0.004162 at ER=0. These are about 44.44%, 13.37% and 0.42% weights on the current price. Solving L=2/SC-1 gives fixed-coefficient EMA equivalents of 3.5 and 479.5 at the endpoints. KAMA changes SC each bar, so these equivalents describe local weights, not an identical historical line.
Worked example: the same endpoint, different paths
These invented prices demonstrate arithmetic, not market performance. Set N=3, fast length=2 and slow length=30. Seed KAMA at the source on bar 3, when the first complete window exists. Keep full precision internally; the table rounds to six decimals.
| Bar | Trend price | Reversing price | Trend KAMA | Reversing KAMA |
|---|---|---|---|---|
| 0 | 100 | 100 | Warm-up | Warm-up |
| 1 | 101 | 103 | Warm-up | Warm-up |
| 2 | 102 | 100 | Warm-up | Warm-up |
| 3 | 103 | 103 | 103.000000 (seed) | 103.000000 (seed) |
| 4 | 104 | 100 | 103.444444 | 102.788954 |
| 5 | 105 | 103 | 104.135802 | 102.803801 |
On bar 3, both paths go from 100 to 103. The trend path travels 1+1+1=3, so ER=3/3=1 and SC=0.444444. The reversing path travels 3+3+3=9, so ER=3/9=1/3 and SC=0.070349. Each series keeps that ER through bar 5. ER ignores the direction: the reversing path still has ER=1/3 on bar 4 even though its net movement is negative.
The bar 4 updates are 103+(4/9)×(104-103)=103.444444 and 103+0.070348594×(100-103)=102.788954. Bar 5 uses those updated values as its starting point. Reusing 103 as the seed on every bar would fail to reproduce the table.
A flat window needs a separate rule
For 100, 100, 100, 100, both D and V equal zero. This example assigns ER=0 instead of dividing 0 by 0. A seed of 100 stays at 100. If an earlier KAMA were 102 when a flat 100 window appeared, the next value would be 102+(4/961)×(100-102)=101.991675. A flat price window therefore does not force an existing average to become flat immediately.
Copyable Pine Script v6 with visible diagnostics
Paste the script into TradingView's Pine Editor, save it and add it to the chart. The inputs expose source, ER length and fast/slow lengths. The Data Window includes ER and SC, so a similar-looking line is not your only correctness check.
//@version=6
indicator("KAMA: inspect the adaptive calculation", overlay=true)
source = input.source(close, "Source")
length = input.int(10, "ER length", minval=1)
fastLength = input.int(2, "Fast length", minval=1)
slowLength = input.int(30, "Slow length", minval=2)
if fastLength >= slowLength
runtime.error("Fast length must be smaller than slow length.")
direction = math.abs(source - source[length])
noise = math.sum(math.abs(source - source[1]), length)
validCount = math.sum(na(source) ? 0.0 : 1.0, length + 1)
ready = not na(direction) and not na(noise) and validCount == length + 1
er = ready ? (noise == 0.0 ? 0.0 : direction / noise) : na
fastSC = 2.0 / (fastLength + 1)
slowSC = 2.0 / (slowLength + 1)
sc = math.pow(er * (fastSC - slowSC) + slowSC, 2)
var float kama = na
if not ready
kama := na
else if na(kama[1])
kama := source
else
kama := kama[1] + sc * (source - kama[1])
crossUp = ta.crossover(source, kama)
confirmedCrossUp = barstate.isconfirmed and crossUp
plot(kama, "KAMA", color=color.blue, linewidth=2)
plot(er, "Efficiency ratio", display=display.data_window)
plot(sc, "Squared smoothing constant", display=display.data_window)
plotshape(confirmedCrossUp, title="Confirmed cross above", style=shape.triangleup, location=location.belowbar, color=color.blue, size=size.tiny)
alertcondition(confirmedCrossUp, title="Confirmed cross above KAMA", message="Source crossed above KAMA on a confirmed chart bar.")This script waits for N+1 consecutive valid source values, then seeds at the current source without applying a recursive update on that same bar. A missing value resets the result to na until another complete window exists. It rejects fast length greater than or equal to slow length. These are explicit example policies, not a claim that every KAMA implementation uses them.
The line remains live on an open chart bar. The triangle and alert condition require a confirmed crossover above KAMA. Pine indicators recalculate during realtime updates, and barstate.isconfirmed becomes true on the closing update. A confirmed marker fixes the observation time; it does not establish a profitable entry.
Check disagreements before interpreting the line
- Match the exact symbol/feed, session, chart timeframe and source. The example uses the chart timeframe and makes no higher-timeframe requests.
- Match all four inputs. ER length controls the observation window; the fast and slow lengths set coefficient bounds. A KAMA length of 10 and an EMA length of 10 do not imply matching weights.
- Compare ER and SC on closed bars first. If ER disagrees, inspect the N absolute adjacent changes and missing values. If only SC disagrees, inspect the exact fractions and the square.
- If ER and SC agree but KAMA differs, compare the seed and available history. For identical subsequent inputs, the difference between two seeds shrinks by a factor of 1-SC each update. Small SC can preserve that difference for many bars.
- Keep line calculations separate from crossover confirmation. See Pine's execution model when historical bars agree but the live bar differs.
What the calculation cannot tell you
Scaling every price change by the same factor leaves ER unchanged, so high volatility does not necessarily mean low efficiency. A single directional jump after flat prices can yield ER=1. Neither that ratio nor a crossover tells you whether the next bar will continue. Price can cross a slowly moving KAMA repeatedly in a range.
A shorter ER window reacts to a different sample; it is not automatically a better intraday setting. Any strategy built around the line still needs entry timing, exits, sizing and trading costs. This page provides a calculation example, not investment advice or a performance comparison.
Turn the calculation into a checkable Pineify request
Ask the Pine Script AI Coding Agent to preserve the source, lengths, seed and zero-noise rule while adding your requested plots or confirmed conditions. Compare the generated values with the table before defining strategy exits and costs.
Create a KAMA indicator with source and ER/fast/slow inputs. Square the interpolated coefficient. Use ER=0 for zero total movement and seed from the current source after a complete window. Expose ER and SC in the Data Window, and confirm crossover markers only at chart-bar close.Open Pine Script AI Coding Agent
KAMA questions
Sources and related reading
Documentation checked October 17, 2026. Tables use hypothetical inputs calculated for this page.