Kaufman Adaptive Moving Average (KAMA)
period = 30 Overview
The Kaufman Adaptive Moving Average intelligently adjusts its responsiveness based on market efficiency, becoming a fast moving average during clean trends and a slow moving average during choppy consolidations, solving the eternal trader's dilemma of choosing between responsiveness and stability. KAMA calculates an efficiency ratio by comparing net price change to the sum of all individual price movements, then maps this ratio to a smoothing constant that varies between fast and slow exponential moving average speeds. When markets trend efficiently with minimal retracements, the efficiency ratio approaches 1 and KAMA tracks price closely like a 2 period EMA, capturing profits from the earliest stages of breakouts. During sideways chop where prices oscillate without direction, efficiency drops toward 0 and KAMA behaves like a 30 period EMA, filtering out whipsaws that would trigger false signals with fixed period averages. Traders leverage KAMA as a universal trend filter that automatically adapts to market conditions without requiring manual parameter adjustments for different volatility regimes. The indicator particularly excels at staying with strong trends longer than traditional moving averages while quickly exiting when efficiency deteriorates, providing superior risk adjusted returns across diverse market environments from trending to ranging conditions.
Implementation Examples
Get started with KAMA in just a few lines:
use vectorta::indicators::kama::{kama, KamaInput, KamaParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using with price data slice
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let params = KamaParams { period: Some(30) }; // Default period = 30
let input = KamaInput::from_slice(&prices, params);
let result = kama(&input)?;
// Using with Candles data structure (defaults: source="close", period=30)
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = KamaInput::with_default_candles(&candles);
let result = kama(&input)?;
// Access the KAMA values
for value in result.values {
println!("KAMA: {}", value);
} API Reference
Input Methods ▼
// From price slice
KamaInput::from_slice(&[f64], KamaParams) -> KamaInput
// From candles with custom source
KamaInput::from_candles(&Candles, &str, KamaParams) -> KamaInput
// From candles with default params (close, period=30)
KamaInput::with_default_candles(&Candles) -> KamaInput Parameters Structure ▼
pub struct KamaParams {
pub period: Option<usize>, // Default: 30
} Output Structure ▼
pub struct KamaOutput {
pub values: Vec<f64>, // KAMA values
} Validation, Warmup & NaNs ▼
- Input must be non-empty; else
KamaError::EmptyInputData. - All-NaN input is invalid;
KamaError::AllValuesNaN. period > 0andperiod ≤ len; otherwiseKamaError::InvalidPeriod.- There must be at least
period+1valid points after the first finite value; elseKamaError::NotEnoughValidData. - Warmup: indices before
first_valid + periodareNaN; the first finite output equals the price at that index. kama_into_slicerequires output buffer length to match input; elseKamaError::BufferLengthMismatch.
Error Handling ▼
use vectorta::indicators::kama::{kama, KamaError};
match kama(&input) {
Ok(output) => process(output.values),
Err(KamaError::EmptyInputData) => eprintln!("input slice is empty"),
Err(KamaError::AllValuesNaN) => eprintln!("all input values are NaN"),
Err(KamaError::InvalidPeriod { period, data_len }) => {
eprintln!("invalid period: {} (len={})", period, data_len)
}
Err(KamaError::NotEnoughValidData { needed, valid }) => {
eprintln!("not enough valid data: needed={}, valid={}", needed, valid)
}
Err(KamaError::BufferLengthMismatch { expected, got }) => {
eprintln!("buffer mismatch: expected={}, got={}", expected, got)
}
Err(KamaError::InvalidKernel) => eprintln!("invalid kernel for batch context"),
} Python Bindings
Basic Usage ▼
Calculate KAMA using NumPy arrays (default period=30):
import numpy as np
from vectorta import kama
# Prepare price data as NumPy array
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5])
# Calculate with defaults (period=30)
result = kama(prices, period=30)
# Or specify kernel for performance optimization ("auto", "avx2", "avx512", "scalar")
result = kama(prices, period=30, kernel="auto")
print(f"KAMA values: {result}") Streaming Real-time Updates ▼
Process real-time price updates efficiently:
from vectorta import KamaStream
# Initialize streaming KAMA calculator
stream = KamaStream(period=30)
# Process real-time price updates
for price in price_feed:
kama_value = stream.update(price)
if kama_value is not None:
print(f"Current KAMA: {kama_value}") Batch Parameter Sweep ▼
Test multiple KAMA periods efficiently:
import numpy as np
from vectorta import kama_batch
prices = np.array([...])
# Define period sweep as (start, end, step)
period_range = (10, 60, 5)
results = kama_batch(prices, period_range=period_range, kernel="auto")
print(results.keys()) # dict with 'values', 'periods'
print(results['values'].shape) # (num_combinations, len(prices))
print(results['periods']) # array of periods tested CUDA Acceleration ▼
CUDA support is available for KAMA in Python (device APIs).
import numpy as np
from vectorta import (
kama_cuda_batch_dev,
kama_cuda_many_series_one_param_dev,
)
# Option 1: One series, many parameters (parameter sweep on GPU)
prices_f32 = np.asarray(prices, dtype=np.float32)
res = kama_cuda_batch_dev(prices_f32, period_range=(10, 60, 5), device_id=0)
# res is a device-backed array wrapper; convert or use downstream APIs as provided
# Option 2: Many series, one parameter (time-major input: [T, N])
tm = np.random.rand(1000, 64).astype(np.float32)
res2 = kama_cuda_many_series_one_param_dev(tm, period=30, device_id=0) JavaScript/WASM Bindings
Basic Usage ▼
Calculate KAMA in JavaScript/TypeScript:
import { kama_js } from 'vectorta-wasm';
// Price data as Float64Array or regular array
const prices = new Float64Array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5]);
// Calculate KAMA with specified period
const result = kama_js(prices, 30);
// Result is a Float64Array
console.log('KAMA values:', result); Memory-Efficient Operations ▼
Use zero-copy operations for better performance with large datasets:
import { kama_alloc, kama_free, kama_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* your data */]);
const length = prices.length;
// Allocate WASM memory for input and output
const inPtr = kama_alloc(length);
const outPtr = kama_alloc(length);
// Copy input data into WASM memory
new Float64Array(memory.buffer, inPtr, length).set(prices);
// Calculate KAMA directly into allocated memory
// Args: in_ptr, out_ptr, len, period
kama_into(inPtr, outPtr, length, 30);
// Read results from WASM memory (slice() to copy out)
const kamaValues = new Float64Array(memory.buffer, outPtr, length).slice();
// Free allocated memory when done
kama_free(inPtr, length);
kama_free(outPtr, length);
console.log('KAMA values:', kamaValues); Batch Processing ▼
Test multiple period values efficiently:
import { kama_batch_js, kama_batch_metadata_js } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
// Define period sweep
const start = 10, end = 60, step = 5; // 10, 15, 20, ... 60
// Get metadata (periods tested)
const metadata = kama_batch_metadata_js(start, end, step); // [period1, period2, ...]
const numCombos = metadata.length;
// Calculate all combinations
const results = kama_batch_js(prices, start, end, step);
// Results is a flat array of length numCombos * prices.length
const matrix = [] as number[][];
for (let i = 0; i < numCombos; i++) {
const s = i * prices.length;
const e = s + prices.length;
matrix.push(results.slice(s, e));
}
// Access specific period results
const period = metadata[0];
const values = matrix[0]; Performance Analysis
Across sizes, Rust CPU runs about 8.76× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05
CUDA note
In our benchmark workload, the Rust CPU implementation is faster than CUDA for this indicator. Prefer the Rust/CPU path unless your workload differs.
Related Indicators
Arnaud Legoux Moving Average
Moving average indicator
Compound Ratio Moving Average (CoRa Wave)
Moving average indicator
Centered Weighted Moving Average
Moving average indicator
Double Exponential Moving Average
Moving average indicator
Ehlers Distance Coefficient Filter
Moving average indicator
Ehlers Error-Correcting EMA (ECEMA)
Moving average indicator