A fixed moving average always responds at the same rate. Kaufman's Adaptive Moving Average (KAMA) changes its response from the path that price just took. A clean directional move makes it accelerate. A long zigzag that ends near its starting point makes it slow down.
That idea sounds simple, but implementations can disagree because of four details: the seed, the first valid output, the zero-denominator rule, and the meaning of the fast and slow settings. This tutorial resolves all four. By the end, you can calculate KAMA by hand, implement it in Python or TypeScript, compare vendor output, and inspect every update in a guided lab.
All numerical paths in this article are synthetic teaching data. They test the mechanism; they are not evidence of prediction or investment performance.
The practical question KAMA answers
Suppose two ten-bar paths start at 100 and finish at 110:
- one moves upward almost directly;
- the other rises, falls, and rises again before reaching 110.
Their endpoint change is identical. Their paths are not. KAMA measures how much of the total travel became net displacement.
The numerator is the straight endpoint displacement. The denominator is the sum of every absolute one-bar move. This ratio is near one for a direct path and near zero for a path that expends movement without making net progress.
Perry Kaufman's 1995 Smarter Trading is the original bibliographic anchor for the Adaptive Moving Average and Efficiency Ratio (Google Books). The current official TradingView explanation documents the same displacement, path-length, endpoint-factor, and squared smoothing structure.
First fix the exact KAMA convention
This tutorial uses three configurable integer parameters:
- efficiency period
E=10; - fast period
F=2; - slow period
S=30.
These are tutorial defaults, not universal defaults. TA-Lib fixes the fast/slow endpoints at 2/30 and defaults its exposed efficiency period to 30. QuantConnect exposes all three and defaults only fast/slow to 2/30. Tulip fixes 2/30 and emits one extra leading raw seed value.
Our exact contract is:
- require
E ≥ 2and1 ≤ F < S; - use
x_(E-1)as an internal seed; - publish no seed value;
- publish the first calculated KAMA at index
E; - set efficiency ratio to one when path length is zero;
- reject missing and non-finite values;
- never round intermediate calculations.
This means E=10 requires 11 source observations for the first published
value. Ten movements connect eleven points.
KAMA formula, one layer at a time
Let x_t be the current value and E the efficiency period.
1. Endpoint change
Absolute value makes efficiency directionless. A clean fall can be just as efficient as a clean rise.
2. Cumulative path length
KAMA descriptions often call V_t volatility. It is total absolute movement,
not variance, standard deviation, or a volatility forecast.
3. Efficiency ratio
The triangle inequality keeps ER between zero and one. If price returns to where the window began but moved in between, change is zero and path is positive, so ER is zero.
The V_t=0 branch is an implementation convention. TA-Lib, QuantConnect LEAN,
and Tulip all use ER=1. It can matter after a step: price may have been flat
for a complete window while the recursive KAMA still lags behind the new
level.
4. Fast and slow endpoint factors
Blend them with ER:
Then square the blend:
The square is not decorative. With fast 2 and slow 30:
- maximum
SC = (2/3)² = 0.4444444444; - minimum
SC = (2/31)² = 0.0041623309.
If you translate a fixed EMA alpha back with N=2/alpha−1, these final
constants resemble periods 3.5 and 479.5. So “KAMA moves between EMA(2) and
EMA(30)” is a misleading shortcut. The labels 2 and 30 define the factors
before squaring.
5. Recursive update
Seed internally:
Then update:
Because SC_t stays between zero and one, each update lies between the prior
KAMA and current input. A single KAMA update cannot overshoot that segment.
The complete causal flow
Nothing later than t enters the update at t. KAMA is causal, but causal does
not mean predictive.
Worked KAMA calculation
Use this compact synthetic sequence:
[100, 101, 102, 103, 104, 103, 104, 103, 104, 108, 109]
E=4, F=2, S=30
The hidden seed is KAMA_3=103.
At index 4:
So ER_4=1, SC_4=0.4444444444, and:
The complete trace is:
| t | Value | Change | Path | ER | SC | KAMA |
|---|---|---|---|---|---|---|
| 4 | 104 | 4 | 4 | 1.000000 | 0.444444 | 103.444444 |
| 5 | 103 | 2 | 4 | 0.500000 | 0.133657 | 103.385041 |
| 6 | 104 | 2 | 4 | 0.500000 | 0.133657 | 103.467235 |
| 7 | 103 | 0 | 4 | 0.000000 | 0.004162 | 103.465290 |
| 8 | 104 | 0 | 4 | 0.000000 | 0.004162 | 103.467516 |
| 9 | 108 | 5 | 7 | 0.714286 | 0.244653 | 104.576400 |
| 10 | 109 | 5 | 7 | 0.714286 | 0.244653 | 105.658645 |
Index 7 is the key lesson. Price traveled four units but made no net progress over the window. KAMA nearly freezes.
Python implementation
The readable reference implementation deliberately recomputes each path:
fast_alpha = 2.0 / (fast_period + 1.0)
slow_alpha = 2.0 / (slow_period + 1.0)
previous = values[efficiency_period - 1]
for t in range(efficiency_period, len(values)):
change = abs(values[t] - values[t - efficiency_period])
path = sum(
abs(values[j] - values[j - 1])
for j in range(t - efficiency_period + 1, t + 1)
)
er = 1.0 if path == 0.0 else change / path
alpha = slow_alpha + er * (fast_alpha - slow_alpha)
sc = alpha * alpha
previous = previous + sc * (values[t] - previous)
kama[t] = previous
The complete validated source is implementations/python/kama.py.
TypeScript implementation
The TypeScript version uses the same control flow and nullable alignment:
const fastAlpha = 2 / (fastPeriod + 1);
const slowAlpha = 2 / (slowPeriod + 1);
let previous = values[efficiencyPeriod - 1];
for (let t = efficiencyPeriod; t < values.length; t += 1) {
const change = Math.abs(values[t] - values[t - efficiencyPeriod]);
let path = 0;
for (let j = t - efficiencyPeriod + 1; j <= t; j += 1) {
path += Math.abs(values[j] - values[j - 1]);
}
const er = path === 0 ? 1 : change / path;
const alpha = slowAlpha + er * (fastAlpha - slowAlpha);
const sc = alpha * alpha;
previous += sc * (values[t] - previous);
kama[t] = previous;
}
See implementations/typescript/kama.ts.
Both languages share full-precision JSON fixtures and agree within 1e-12.
Why platform values can differ
Check these questions before calling either implementation wrong:
- Is the efficiency period 10 or 30?
- Are fast and slow periods configurable or fixed?
- Is the previous price or an average used as the seed?
- Is the raw seed emitted at
E-1? - Does the first calculated result appear at
E? - What happens when path length is zero?
- Are pre-ready values hidden, raw, or null?
- Is the source raw, split-adjusted, or total-return adjusted?
- Does the calculation include an unclosed bar?
The official TA-Lib function page and its pinned implementation provide a reproducible vendor comparison point.
Data quality is part of the algorithm
A split-like discontinuity, contract roll, bad tick, unit conversion, or mixed adjustment basis can look like a highly efficient directional move. KAMA cannot know that the move is a data event.
Use one declared source field, calendar, frequency, timezone, and adjustment
basis. Reject missing values by default. If an application deliberately resets
at a gap, clear recursive state and require another E+1 observations.
A correction also requires replay. Changing one past input affects nearby ER windows and changes the recursive KAMA passed into every later update.
Explore 120 observations instead of a tiny demo
The default Regime Tour contains 120 observations:
- quiet alternating warm-up;
- clean directional rise;
- zero-progress chop;
- a sharp step;
- controlled decline;
- noisy range;
- clean recovery.
Use the interactive KAMA playground to change scenarios and parameters, step through the active window, and inspect change, path, ER, alpha, SC, and KAMA together. The additional scenarios cover same endpoints with different paths, a step followed by a flat window, a raw-versus-adjusted discontinuity, and a missing-observation reset.
Tests that matter
The focused suite checks:
- full-precision shared fixtures;
- exactly
Eleading nulls; ER=1for monotone up and down paths;ER=0for a return-to-origin path;- zero path after a level shift;
- output containment between prior KAMA and current value;
- translation and nonzero scale equivariance;
- parameter and finite-number validation;
- input immutability;
- Python and TypeScript parity.
These tests answer “did we implement the definition?” They do not answer “does a trading strategy work?” That requires a separate, bias-aware design with costs and out-of-sample evaluation.
KAMA versus EMA, Hull MA, and MAMA
| Method | Response control | State | First-ready convention | Main contract risk |
|---|---|---|---|---|
| EMA | Fixed alpha | Recursive | period/seed dependent | Seed and warm-up |
| Hull MA | Fixed derived WMA lengths | Finite window | derived-window dependent | Period rounding and signed weights |
| KAMA | ER-driven squared alpha | Recursive plus trailing path | index E here | Seed, zero path, source basis, and parameter convention |
| MAMA | Signed phase-change alpha | Hilbert and recursive state | index 32 for TA-Lib parity | Source price, phase convention, seed, and warm-up |
KAMA is not automatically “better.” It makes a different tradeoff and exposes more path state. MAMA exposes more phase state.
Use KAMA when the important diagnostic is how much recent movement became net travel. Use MAMA when the important diagnostic is how quickly the measured Hilbert phase changed. This is a choice of question, not a ranking of lines.
Common questions
What is KAMA?
KAMA is an adaptive recursive moving average. It changes its smoothing constant from recent endpoint displacement relative to cumulative absolute movement.
How do you calculate KAMA?
Calculate change and path length, divide them to obtain ER, blend the fast and slow EMA factors, square that blend, and apply it to the prior KAMA update.
What do 10, 2, and 30 mean?
Ten is this tutorial's efficiency period. Two and thirty generate the fast and slow endpoint factors before squaring. They are not the final effective EMA period range.
Why is the smoothing constant squared?
Squaring preserves the order of the endpoint factors while strongly compressing low-efficiency updates. It is an essential part of the documented KAMA formula.
When is the first KAMA value ready?
Under this contract, index E: the calculation needs E one-step movements,
E+1 observations, and a hidden seed at E-1.
Why does my KAMA differ from TA-Lib or another chart?
Match efficiency period, fast/slow exposure, seed, first-ready index, zero-path rule, unstable period, source field, adjustment basis, and bar availability.
Is ER a trend-direction signal?
No. Absolute values remove direction. A clean rise and clean fall both have high efficiency.
Can KAMA predict price?
No. KAMA is a causal smoother of observed input. A strategy using it needs separate evidence.
What happens when path length is zero?
This package sets ER to one, matching the maintained TA-Lib, QuantConnect, and Tulip implementations.
What are the best KAMA settings?
There is no universal best setting. Parameter selection depends on the data, timeframe, objective, turnover, costs, and an out-of-sample validation design.
Historical example decision
A named historical security is not useful for this mechanism lesson. Controlled paths isolate the reason ER and SC change, while a market chart adds provider, adjustment, licensing, and hindsight ambiguity. No historical return or profitability claim is made.
Summary
KAMA is an EMA-shaped recursion with a path-sensitive update weight:
- displacement divided by path length produces directionless ER;
- ER blends slow and fast endpoint factors;
- the blend is squared;
- the result updates a recursively seeded average.
The hard part is not typing the formula. It is freezing the seed, warm-up, zero-path, time, adjustment, and reset contracts so every result is reproducible.
The next tutorial is MESA Adaptive Moving Average, which adapts from phase dynamics rather than path efficiency.
Rendered from the canonical Mermaid sources linked by this article.
KAMA calculation flow
Purpose: show how one completed observation becomes a causal KAMA update and where validation, warm-up, and readiness occur.
Interpretation: the output at observation t uses only prices through t. A
zero-length path uses the explicit canonical convention ER = 1; missing or
misordered data is rejected or begins a separately labeled reset segment.
Takeaway: KAMA adapts because the geometry of the recent path changes the size of a normal recursive moving-average update.
References10 primary sources and evidence notesExpand the source trail, evidence role, and limitations behind the engineering choices.
Expand the source trail, evidence role, and limitations behind the engineering choices.
All web sources were accessed on 2026-07-26. The package uses maintained reference implementations to resolve initialization details that short formula summaries leave unspecified.
R01 — Smarter Trading: Improving Performance in Changing Markets
- Organization or authors: Perry J. Kaufman; McGraw-Hill Professional
- Source type: Original book bibliographic record
- Publication or effective date: 1995
- Version: Illustrated edition; ISBN 9780070340022
- URL or DOI: https://books.google.com/books/about/Smarter_Trading.html?id=ndq_21wRJjEC
- Accessed: 2026-07-26
- Jurisdiction: Not jurisdiction-specific
- Evidence role: Sourced fact
- Supports: Kaufman authorship, 1995 publication, and the book's inclusion of Adaptive Moving Average and Efficiency Ratio.
- Limitations: The available preview does not establish exact seed, warm-up, zero-denominator, or software-default behavior.
- Publication decision: Public bibliographic metadata may be cited; no copyrighted book text is reproduced.
R02 — Adaptive Techniques
- Organization or authors: Perry J. Kaufman; Wiley
- Source type: Authoritative book chapter
- Publication or effective date: 2012
- Version: Trading Systems and Methods, fifth edition, chapter 17
- URL or DOI: https://doi.org/10.1002/9781119202561.ch17
- Accessed: 2026-07-26
- Jurisdiction: Not jurisdiction-specific
- Evidence role: Sourced fact
- Supports: An adaptive technique changes with market conditions rather than relying on one fixed response.
- Limitations: The accessible abstract is conceptual; it is not used to resolve implementation initialization.
- Publication decision: Cite metadata and summary only.
R03 — TradingView official KAMA documentation
- Organization or authors: TradingView
- Source type: Official maintained platform documentation
- Publication or effective date: Current documentation viewed 2026-07-26
- Version: Web documentation
- URL or DOI: https://www.tradingview.com/support/solutions/43000773012-kaufman-s-adaptive-moving-average-kama/
- Accessed: 2026-07-26
- Jurisdiction: Platform documentation; not jurisdiction-specific
- Evidence role: Sourced fact
- Supports: 1995 attribution, EMA-style recursion, change and cumulative absolute movement, ER interpretation, fast and slow factors, squaring, and parameter roles.
- Limitations: Does not publish a seed or first-ready-index contract. It must not be used to assert cross-platform numerical parity.
- Publication decision: Formula and terminology are paraphrased with a direct link.
R04 — TA-Lib official KAMA function page
- Organization or authors: TA-Lib project
- Source type: Official technical documentation
- Publication or effective date: Updated July 2026
- Version: Current function documentation
- URL or DOI: https://ta-lib.org/functions/kama.html
- Accessed: 2026-07-26
- Jurisdiction: Open-source software documentation
- Evidence role: Sourced fact
- Supports: Exact
2/3and2/31endpoint constants, efficiency lookback, recursive formula, output meaning, and period-one identity note. - Limitations: The summary does not expose every initialization branch; the pinned C source resolves those details.
- Publication decision: Public documentation is suitable for citation.
R05 — TA-Lib pinned KAMA C implementation
- Organization or authors: TA-Lib project
- Source type: Maintained reference implementation
- Publication or effective date: Repository state retrieved 2026-07-26
- Version: Commit
e203f7c436a9c21fd08246661971cfcb7ee37517 - URL or DOI: https://raw.githubusercontent.com/TA-Lib/ta-lib/e203f7c436a9c21fd08246661971cfcb7ee37517/src/ta_func/ta_KAMA.c
- Accessed: 2026-07-26
- Jurisdiction: BSD-licensed open-source software
- Evidence role: Sourced implementation fact
- Supports: TA-Lib's efficiency-period default of 30, fixed fast/slow constants 2/30, previous-price seed, first output at index
Ewhen unstable period is zero, zero-pathER = 1, and explicit period-one identity. - Limitations: TA-Lib exposes only the efficiency period in this function; it is not evidence that all KAMA implementations fix fast/slow at 2/30.
- Publication decision: Behavior is described; source code is linked rather than copied.
R06 — QuantConnect LEAN pinned KAMA implementation
- Organization or authors: QuantConnect
- Source type: Maintained reference implementation
- Publication or effective date: Repository state retrieved 2026-07-26
- Version: Commit
cd52034ddf55c0c9aa57264d2a148e563924100f - URL or DOI: https://raw.githubusercontent.com/QuantConnect/Lean/cd52034ddf55c0c9aa57264d2a148e563924100f/Indicators/KaufmanAdaptiveMovingAverage.cs
- Accessed: 2026-07-26
- Jurisdiction: Apache-2.0 open-source software
- Evidence role: Sourced implementation fact
- Supports: Configurable fast/slow periods with defaults 2/30, previous-price seed, squared adaptive factor, recursive update, and reset behavior.
- Limitations: Its pre-ready indicator object returns the input value internally; only ready output is comparable with this package's nullable aligned series.
- Publication decision: Behavior is described and linked.
R07 — QuantConnect LEAN pinned Efficiency Ratio implementation
- Organization or authors: QuantConnect
- Source type: Maintained reference implementation
- Publication or effective date: Repository state retrieved 2026-07-26
- Version: Commit
cd52034ddf55c0c9aa57264d2a148e563924100f - URL or DOI: https://raw.githubusercontent.com/QuantConnect/Lean/cd52034ddf55c0c9aa57264d2a148e563924100f/Indicators/KaufmanEfficiencyRatio.cs
- Accessed: 2026-07-26
- Jurisdiction: Apache-2.0 open-source software
- Evidence role: Sourced implementation fact
- Supports: An
E + 1observation window, readiness timing, rolling path calculation, andER = 1for a zero path length. - Limitations: Decimal arithmetic can differ in the last digits from this package's binary floating-point implementation.
- Publication decision: Behavior is described and linked.
R08 — Tulip Indicators pinned KAMA implementation
- Organization or authors: Tulip Charts / Tulip Indicators
- Source type: Maintained reference implementation
- Publication or effective date: Repository state retrieved 2026-07-26
- Version: Commit
be18abb13e075ba866898dcc7cb52399603302a6 - URL or DOI: https://raw.githubusercontent.com/TulipCharts/tulipindicators/be18abb13e075ba866898dcc7cb52399603302a6/indicators/kama.c
- Accessed: 2026-07-26
- Jurisdiction: LGPL-licensed open-source software
- Evidence role: Sourced implementation fact
- Supports: A material alignment variant: Tulip emits the raw previous-price seed at index
E - 1, then calculates atE; it fixes fast/slow at 2/30 and usesER = 1on a zero path. - Limitations: The emitted seed is not a calculated KAMA update, so direct arrays differ by one leading value from this package.
- Publication decision: Behavior is described and linked.
R09 — Canonical package calculations
- Organization or authors: The Fintech Builder
- Source type: Independent author-derived calculation
- Publication or effective date: 2026-07-26
- Version: Canonical fixture revision 1
- URL or DOI:
./examples/worked-example.json - Accessed: 2026-07-26
- Jurisdiction: Not applicable
- Evidence role: Author-derived calculation
- Supports: Worked ER, smoothing constants, KAMA values, effective EMA-length endpoints, and cross-language expected outputs.
- Limitations: Synthetic calculations establish definition fidelity, not trading usefulness or predictive power.
- Publication decision: Publish with visible synthetic and author-derived labels.
R10 — Playground scenario dataset
- Organization or authors: The Fintech Builder
- Source type: Synthetic teaching dataset
- Publication or effective date: 2026-07-26
- Version: Scenario revision 1
- URL or DOI:
./datasets/kama-playground-scenarios.json - Accessed: 2026-07-26
- Jurisdiction: Not applicable
- Evidence role: Synthetic teaching input
- Supports: Controlled trend, chop, step, zero-path, adjustment-basis, gap, and reset demonstrations.
- Limitations: The paths are deliberately constructed and are not observations from a security or evidence of investment performance.
- Publication decision: CC0-1.0; safe to redistribute with the package.
Historical-example evidence gate
Decision: not useful.
A named market period would add realism without isolating path efficiency, zero-path behavior, seed alignment, or parameter response. It would also add provider, timestamp, adjustment, licensing, and hindsight questions. The controlled synthetic scenarios teach the mechanism more precisely. The package makes no empirical return, signal-quality, or profitability claim.
Full dependency-light reference implementations in both supported languages.
/** Canonical Kaufman Adaptive Moving Average for D07-F01-A08. */
export class KAMAValidationError extends Error {
constructor(message: string) {
super(message);
this.name = "KAMAValidationError";
}
}
export interface KAMAResult {
efficiencyRatio: Array<number | null>;
blendedAlpha: Array<number | null>;
smoothingConstant: Array<number | null>;
kama: Array<number | null>;
}
function period(value: number, name: string, minimum: number): number {
if (!Number.isSafeInteger(value) || value < minimum) {
throw new KAMAValidationError(
`${name} must be a safe integer greater than or equal to ${minimum}.`,
);
}
return value;
}
export function calculateKama(
values: readonly number[],
efficiencyPeriod = 10,
fastPeriod = 2,
slowPeriod = 30,
): KAMAResult {
const e = period(efficiencyPeriod, "efficiencyPeriod", 2);
const fast = period(fastPeriod, "fastPeriod", 1);
const slow = period(slowPeriod, "slowPeriod", 2);
if (fast >= slow) {
throw new KAMAValidationError(
"fastPeriod must be less than slowPeriod.",
);
}
if (!Array.isArray(values)) {
throw new KAMAValidationError("values must be an array.");
}
const numbers = values.map((value, index) => {
if (typeof value !== "number" || !Number.isFinite(value)) {
throw new KAMAValidationError(
`values[${index}] must be a finite number.`,
);
}
return value;
});
const efficiencyRatio: Array<number | null> = Array(numbers.length).fill(null);
const blendedAlpha: Array<number | null> = Array(numbers.length).fill(null);
const smoothingConstant: Array<number | null> =
Array(numbers.length).fill(null);
const kama: Array<number | null> = Array(numbers.length).fill(null);
if (numbers.length <= e) {
return { efficiencyRatio, blendedAlpha, smoothingConstant, kama };
}
const fastAlpha = 2 / (fast + 1);
const slowAlpha = 2 / (slow + 1);
let previous = numbers[e - 1];
for (let index = e; index < numbers.length; index += 1) {
const change = Math.abs(numbers[index] - numbers[index - e]);
let pathLength = 0;
for (
let position = index - e + 1;
position <= index;
position += 1
) {
pathLength += Math.abs(numbers[position] - numbers[position - 1]);
}
const rawRatio = pathLength === 0 ? 1 : change / pathLength;
const ratio = Math.min(1, Math.max(0, rawRatio));
const mixed = slowAlpha + ratio * (fastAlpha - slowAlpha);
const constant = mixed * mixed;
previous += constant * (numbers[index] - previous);
efficiencyRatio[index] = ratio;
blendedAlpha[index] = mixed;
smoothingConstant[index] = constant;
kama[index] = previous;
}
return { efficiencyRatio, blendedAlpha, smoothingConstant, kama };
}
The embedded lab now expands to its full document height, keeping the article as the only scroll surface.