D07-F01-A08 / Complete engineering topic

Kaufman Adaptive Moving Average (KAMA): Formula, Code, and Interactive Lab

A production-minded guide to Kaufman Adaptive Moving Average (KAMA).

D07 · TECHNICAL INDICATORS
D07-F01-A08Canonical / Tested / Open
D07 / D07-F01

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.

Direct and sawtooth synthetic paths share an endpoint but not an efficiency ratio

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 ≥ 2 and 1 ≤ 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.

The seed is internal; the first calculated result appears one observation later

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

Ct=xtxtEC_t=|x_t-x_{t-E}|

Absolute value makes efficiency directionless. A clean fall can be just as efficient as a clean rise.

2. Cumulative path length

Vt=j=tE+1txjxj1V_t=\sum_{j=t-E+1}^{t}|x_j-x_{j-1}|

KAMA descriptions often call V_t volatility. It is total absolute movement, not variance, standard deviation, or a volatility forecast.

3. Efficiency ratio

ERt={Ct/Vt,Vt>01,Vt=0ER_t= \begin{cases} C_t/V_t,&V_t>0\\ 1,&V_t=0 \end{cases}

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

αf=2F+1,αs=2S+1\alpha_f=\frac{2}{F+1},\qquad \alpha_s=\frac{2}{S+1}

Blend them with ER:

αt=αs+ERt(αfαs)\alpha_t=\alpha_s+ER_t(\alpha_f-\alpha_s)

Then square the blend:

SCt=αt2SC_t=\alpha_t^2

Efficiency is blended first and squared second

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:

KAMAE1=xE1KAMA_{E-1}=x_{E-1}

Then update:

KAMAt=KAMAt1+SCt(xtKAMAt1)KAMA_t=KAMA_{t-1}+SC_t(x_t-KAMA_{t-1})

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.

KAMA turns a trailing path into one bounded recursive update

The complete causal flow

Rendering system map…

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:

Plain text
[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:

C4=104100=4C_4=|104-100|=4 V4=101100+102101+103102+104103=4V_4=|101-100|+|102-101|+|103-102|+|104-103|=4

So ER_4=1, SC_4=0.4444444444, and:

KAMA4=103+0.4444444444(104103)=103.4444444444KAMA_4=103+0.4444444444(104-103)=103.4444444444

The complete trace is:

tValueChangePathERSCKAMA
4104441.0000000.444444103.444444
5103240.5000000.133657103.385041
6104240.5000000.133657103.467235
7103040.0000000.004162103.465290
8104040.0000000.004162103.467516
9108570.7142860.244653104.576400
10109570.7142860.244653105.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:

Python
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:

TypeScript
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:

  1. Is the efficiency period 10 or 30?
  2. Are fast and slow periods configurable or fixed?
  3. Is the previous price or an average used as the seed?
  4. Is the raw seed emitted at E-1?
  5. Does the first calculated result appear at E?
  6. What happens when path length is zero?
  7. Are pre-ready values hidden, raw, or null?
  8. Is the source raw, split-adjusted, or total-return adjusted?
  9. 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.

Raw-like discontinuity and a consistently adjusted synthetic series

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

KAMA, ER, and smoothing constant across controlled synthetic regimes

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 E leading nulls;
  • ER=1 for monotone up and down paths;
  • ER=0 for 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

MethodResponse controlStateFirst-ready conventionMain contract risk
EMAFixed alphaRecursiveperiod/seed dependentSeed and warm-up
Hull MAFixed derived WMA lengthsFinite windowderived-window dependentPeriod rounding and signed weights
KAMAER-driven squared alphaRecursive plus trailing pathindex E hereSeed, zero path, source basis, and parameter convention
MAMASigned phase-change alphaHilbert and recursive stateindex 32 for TA-Lib paritySource 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.

KAMA adapts from path efficiency while MAMA adapts from phase rate

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:

  1. displacement divided by path length produces directionless ER;
  2. ER blends slow and fast endpoint factors;
  3. the blend is squared;
  4. 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.

KAMA calculation flow

Purpose: show how one completed observation becomes a causal KAMA update and where validation, warm-up, and readiness occur.

Rendering system map…

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 notes

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/3 and 2/31 endpoint 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 E when unstable period is zero, zero-path ER = 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 + 1 observation window, readiness timing, rolling path calculation, and ER = 1 for 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 at E; it fixes fast/slow at 2/30 and uses ER = 1 on 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.

kama.ts
/** 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 };
}
Full-height labkama playgroundOpen full screen