Kaufman Adaptive Stop
period = 22 | mult = 2 (0.5–4) | direction = long | ma_type = kama Overview
The Kaufman Adaptive Stop creates intelligent trailing stop levels that expand and contract based on market volatility, protecting profits during calm trends while allowing positions room to breathe during volatile expansions. By calculating a moving average of the high low range and multiplying it by a factor, the indicator positions stops at a distance that adapts to current market conditions rather than using fixed percentages that work poorly across different volatility regimes. During low volatility trends, the stop tightens to protect gains as the averaged range contracts, following price closely to lock in profits from steady advances. When volatility expands during news events or market stress, the stop automatically widens to prevent premature exits from positions that need more room to fluctuate without violating the underlying trend. The direction parameter allows traders to flip between long and short modes, with long stops trailing below price to protect bullish positions and short stops above price for bearish trades. Professional traders value this adaptive approach because it solves the common problem of stops being too tight in volatile markets causing whipsaws, or too wide in calm markets leaving excessive profits at risk, by dynamically adjusting to the market's current personality rather than imposing rigid rules.
Implementation Examples
Compute Kaufman Stop from high/low data:
use vectorta::indicators::kaufmanstop::{kaufmanstop, KaufmanstopInput, KaufmanstopParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using with raw high/low slices
let high = vec![10.0, 11.0, 10.6, 11.5, 11.1];
let low = vec![ 9.5, 10.2, 10.0, 11.0, 10.7];
let params = KaufmanstopParams { period: Some(22), mult: Some(2.0), direction: Some("long".into()), ma_type: Some("sma".into()) };
let input = KaufmanstopInput::from_slices(&high, &low, params);
let output = kaufmanstop(&input)?;
// Using with Candles
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = KaufmanstopInput::with_default_candles(&candles); // period=22, mult=2.0, long, sma
let output = kaufmanstop(&input)?;
// Access values
for v in output.values { println!("stop: {}", v); } API Reference
Input Methods ▼
// From high/low slices
KaufmanstopInput::from_slices(&[f64], &[f64], KaufmanstopParams) -> KaufmanstopInput
// From candles (uses 'high' and 'low')
KaufmanstopInput::from_candles(&Candles, KaufmanstopParams) -> KaufmanstopInput
// With default params (period=22, mult=2.0, direction="long", ma_type="kama" in this UI)
KaufmanstopInput::with_default_candles(&Candles) -> KaufmanstopInput Parameters Structure ▼
pub struct KaufmanstopParams {
pub period: Option<usize>, // Default: 22
pub mult: Option<f64>, // Default: 2.0
pub direction: Option<String>, // Default: "long" ("long" or "short")
pub ma_type: Option<String>, // Default: "sma" ("sma", "ema", ...)
} Output Structure ▼
pub struct KaufmanstopOutput {
pub values: Vec<f64>, // Stop values (below for long, above for short)
} Validation, Warmup & NaNs ▼
period > 0and not greater than the lengths ofhighandlow; otherwiseKaufmanstopError::InvalidPeriod.- Requires at least
periodvalid (finite)(high, low)pairs after the first finite pair; otherwiseKaufmanstopError::NotEnoughValidData. - Indices before
first_valid_idx + period − 1are prefilled withNaN. - MA types
"sma"and"ema"use optimized implementations; other strings are dispatched via the MA selector. - Streaming:
update(high, low)yieldsNoneuntilperiodupdates have been buffered; then returns per-tick stops.
Error Handling ▼
use vectorta::indicators::kaufmanstop::{kaufmanstop, KaufmanstopError};
match kaufmanstop(&input) {
Ok(output) => process(output.values),
Err(KaufmanstopError::EmptyData) =>
eprintln!("Empty high/low input"),
Err(KaufmanstopError::InvalidPeriod { period, data_len }) =>
eprintln!("Invalid period {} for length {}", period, data_len),
Err(KaufmanstopError::NotEnoughValidData { needed, valid }) =>
eprintln!("Need {} valid pairs, have {}", needed, valid),
Err(KaufmanstopError::AllValuesNaN) =>
eprintln!("All input values are NaN"),
} Python Bindings
Basic Usage ▼
Compute Kaufman Stop from NumPy arrays of high and low:
import numpy as np
from vectorta import kaufmanstop, KaufmanstopStream, kaufmanstop_batch
high = np.array([10.0, 11.0, 10.6, 11.5, 11.1], dtype=float)
low = np.array([ 9.5, 10.2, 10.0, 11.0, 10.7], dtype=float)
stops = kaufmanstop(high, low, period=22, mult=2.0, direction="long", ma_type="kama")
# Streaming
stream = KaufmanstopStream(period=22, mult=2.0, direction="long", ma_type="kama")
for h, l in zip(high, low):
value = stream.update(h, l)
if value is not None:
print(value)
# Batch sweep (returns dict with values and metadata)
res = kaufmanstop_batch(high, low, period_range=(10, 30, 5), mult_range=(1.0, 3.0, 0.5), direction="long", ma_type="kama")
print(res['values'].shape, res['rows'], res['cols']) CUDA Acceleration ▼
CUDA support for Kaufman Stop is coming soon.
# Coming soon: CUDA-accelerated Kaufman Stop calculations
# API will mirror other CUDA-enabled indicators in this project. JavaScript/WASM Bindings
Basic Usage ▼
Calculate Kaufman Stop in JavaScript/TypeScript:
import { kaufmanstop_js } from 'vectorta-wasm';
const high = new Float64Array([10.0, 11.0, 10.6, 11.5, 11.1]);
const low = new Float64Array([ 9.5, 10.2, 10.0, 11.0, 10.7]);
// Args: high, low, period, mult, direction, ma_type
const stops = kaufmanstop_js(high, low, 22, 2.0, 'long', 'sma');
console.log('stops:', stops); Memory-Efficient Operations ▼
Use zero-copy operations for large datasets:
import { kaufmanstop_alloc, kaufmanstop_into, kaufmanstop_free, memory } from 'vectorta-wasm';
const high = new Float64Array([/* ... */]);
const low = new Float64Array([/* ... */]);
const n = high.length;
// Allocate WASM buffers
const highPtr = kaufmanstop_alloc(n);
const lowPtr = kaufmanstop_alloc(n);
const outPtr = kaufmanstop_alloc(n);
// Copy inputs into WASM memory
new Float64Array(memory.buffer, highPtr, n).set(high);
new Float64Array(memory.buffer, lowPtr, n).set(low);
// Compute into preallocated output
kaufmanstop_into(highPtr, lowPtr, outPtr, n, 22, 2.0, 'long', 'sma');
// Read back results (copy out)
const stops = new Float64Array(memory.buffer, outPtr, n).slice();
// Free buffers
kaufmanstop_free(highPtr, n);
kaufmanstop_free(lowPtr, n);
kaufmanstop_free(outPtr, n); Batch Processing ▼
Test multiple parameter combinations:
import { kaufmanstop_batch_js } from 'vectorta-wasm';
const high = new Float64Array([/* historical highs */]);
const low = new Float64Array([/* historical lows */]);
// Returns object: { values: Float64Array, combos: Array, rows: number, cols: number }
const result = kaufmanstop_batch_js(
high, low,
10, 30, 10, // period_start, period_end, step
1.0, 3.0, 0.5,// mult_start, mult_end, step
'long', 'sma'
);
// Reshape values into row-major matrix
const rows = result.rows, cols = result.cols;
const matrix: number[][] = [];
for (let r = 0; r < rows; r++) {
const start = r * cols;
matrix.push(Array.from(result.values.slice(start, start + cols)));
}
console.log('combos:', result.combos); Performance Analysis
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05