Evasive SuperTrend
atr_length = 10 | base_multiplier = 3 | noise_threshold = 1 | expansion_alpha = 0.5 Overview
Evasive SuperTrend starts from the familiar ATR-band trend framework, but it adds explicit logic for bars that look indecisive relative to the existing trail. Internally the study anchors on `hl2`, measures ATR over the chosen window, and maintains a trailing band plus a binary trend state. When price hugs the previous band closely enough to qualify as noise, the algorithm expands the band outward instead of letting the normal trail sit too close to price.
That gives the page four outputs instead of one. `band` is the active trail, `state` is the current direction, `noisy` flags bars where the evasive expansion logic was engaged, and `changed` marks trend flips. There is no configurable candle source parameter here; the study always derives its internal base from `hl2` using the full OHLC bar.
Defaults: Evasive SuperTrend uses `atr_length = 10`, `base_multiplier = 3.0`, `noise_threshold = 1.0`, and `expansion_alpha = 0.5`.
Implementation Examples
Compute the active trail, trend state, noise flags, and change markers from OHLC slices.
use vector_ta::indicators::evasive_supertrend::{
evasive_supertrend,
EvasiveSuperTrendInput,
EvasiveSuperTrendParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let open = vec![100.0, 100.5, 101.0, 100.8, 101.6];
let high = vec![101.0, 101.2, 101.8, 101.7, 102.3];
let low = vec![99.6, 100.0, 100.5, 100.2, 101.0];
let close = vec![100.7, 100.9, 101.5, 101.2, 102.0];
let output = evasive_supertrend(&EvasiveSuperTrendInput::from_slices(
&open,
&high,
&low,
&close,
EvasiveSuperTrendParams {
atr_length: Some(10),
base_multiplier: Some(3.0),
noise_threshold: Some(1.0),
expansion_alpha: Some(0.5),
},
))?;
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = evasive_supertrend(&EvasiveSuperTrendInput::with_default_candles(&candles))?;
println!("band = {:?}", output.band.last());
println!("state = {:?}", candle_output.state.last());
println!("noisy / changed = {:?} / {:?}", candle_output.noisy.last(), candle_output.changed.last()); API Reference
Input Methods ▼
// From candles
EvasiveSuperTrendInput::from_candles(&Candles, EvasiveSuperTrendParams)
-> EvasiveSuperTrendInput
// From OHLC slices
EvasiveSuperTrendInput::from_slices(
&[f64],
&[f64],
&[f64],
&[f64],
EvasiveSuperTrendParams,
) -> EvasiveSuperTrendInput
// From candles with default parameters
EvasiveSuperTrendInput::with_default_candles(&Candles)
-> EvasiveSuperTrendInput Parameters Structure ▼
pub struct EvasiveSuperTrendParams {
pub atr_length: Option<usize>, // default 10
pub base_multiplier: Option<f64>, // default 3.0
pub noise_threshold: Option<f64>, // default 1.0
pub expansion_alpha: Option<f64>, // default 0.5
} Output Structure ▼
pub struct EvasiveSuperTrendOutput {
pub band: Vec<f64>,
pub state: Vec<f64>,
pub noisy: Vec<f64>,
pub changed: Vec<f64>,
} Validation, Warmup & NaNs ▼
- All four OHLC inputs must be non-empty and length-matched.
atr_lengthmust be positive.base_multiplier,noise_threshold, andexpansion_alphamust be valid finite values.- The study requires ATR warmup before the stream starts returning values. Before that, streaming returns
None. - Any non-finite OHLC bar resets the stream and returns
None. stateis encoded as1.0or-1.0,noisyas1.0or0.0, andchangedas1.0only on state flips.- There is no configurable price source parameter; the internal base is always derived from
hl2.
Builder, Streaming & Batch APIs ▼
// Builder
EvasiveSuperTrendBuilder::new()
.atr_length(usize)
.base_multiplier(f64)
.noise_threshold(f64)
.expansion_alpha(f64)
.kernel(Kernel)
.apply(&Candles)
EvasiveSuperTrendBuilder::new()
.apply_slices(&[f64], &[f64], &[f64], &[f64])
EvasiveSuperTrendBuilder::new()
.into_stream()
// Stream
EvasiveSuperTrendStream::try_new(EvasiveSuperTrendParams)
EvasiveSuperTrendStream::update(f64, f64, f64, f64)
-> Option<(f64, f64, f64, f64)>
// Batch
EvasiveSuperTrendBatchBuilder::new()
.atr_length_range(start, end, step)
.atr_length_static(usize)
.base_multiplier_range(start, end, step)
.base_multiplier_static(f64)
.noise_threshold_range(start, end, step)
.noise_threshold_static(f64)
.expansion_alpha_range(start, end, step)
.expansion_alpha_static(f64)
.kernel(Kernel)
.apply_slices(&[f64], &[f64], &[f64], &[f64])
EvasiveSuperTrendBatchBuilder::new()
.apply_candles(&Candles) Error Handling ▼
pub enum EvasiveSuperTrendError {
EmptyInputData,
InputLengthMismatch { open_len: usize, high_len: usize, low_len: usize, close_len: usize },
AllValuesNaN,
InvalidAtrLength { atr_length: usize },
InvalidBaseMultiplier { base_multiplier: f64 },
InvalidNoiseThreshold { noise_threshold: f64 },
InvalidExpansionAlpha { expansion_alpha: f64 },
NotEnoughValidData { needed: usize, valid: usize },
OutputLengthMismatch { expected: usize, got: usize },
InvalidRange { start: String, end: String, step: String },
InvalidKernelForBatch(Kernel),
InvalidInput { msg: String },
} Python Bindings
Python exposes a four-array single-run function, a streaming class, and a batch function. The scalar return order is `band`, `state`, `noisy`, then `changed`, and the batch dict preserves that same output ordering in matrix form.
import numpy as np
from vector_ta import (
evasive_supertrend,
evasive_supertrend_batch,
EvasiveSuperTrendStream,
)
band, state, noisy, changed = evasive_supertrend(
np.asarray(open_values, dtype=np.float64),
np.asarray(high_values, dtype=np.float64),
np.asarray(low_values, dtype=np.float64),
np.asarray(close_values, dtype=np.float64),
atr_length=10,
base_multiplier=3.0,
noise_threshold=1.0,
expansion_alpha=0.5,
kernel="auto",
)
stream = EvasiveSuperTrendStream(10, 3.0, 1.0, 0.5)
print(stream.update(open_values[-1], high_values[-1], low_values[-1], close_values[-1]))
batch = evasive_supertrend_batch(
np.asarray(open_values, dtype=np.float64),
np.asarray(high_values, dtype=np.float64),
np.asarray(low_values, dtype=np.float64),
np.asarray(close_values, dtype=np.float64),
atr_length_range=(10, 14, 2),
base_multiplier_range=(2.5, 3.5, 0.5),
noise_threshold_range=(0.8, 1.2, 0.2),
expansion_alpha_range=(0.3, 0.5, 0.1),
kernel="auto",
)
print(batch["band"].shape, batch["state"].shape)
print(batch["atr_lengths"], batch["base_multipliers"])
print(batch["noise_thresholds"], batch["expansion_alphas"], batch["rows"], batch["cols"]) JavaScript/WASM Bindings
The WASM layer exposes object-returning scalar and batch wrappers plus low-level in-place exports. The standard JavaScript path returns an object with `band`, `state`, `noisy`, and `changed`. Batch adds `rows`, `cols`, and a `combos` array describing each parameter row.
import init, {
evasive_supertrend_js,
evasive_supertrend_batch_js,
} from "/pkg/vector_ta.js";
await init();
const out = evasive_supertrend_js(
openValues,
highValues,
lowValues,
closeValues,
10,
3.0,
1.0,
0.5,
);
console.log(out.band, out.state, out.noisy, out.changed);
const batch = evasive_supertrend_batch_js(openValues, highValues, lowValues, closeValues, {
atr_length_range: [10, 14, 2],
base_multiplier_range: [2.5, 3.5, 0.5],
noise_threshold_range: [0.8, 1.2, 0.2],
expansion_alpha_range: [0.3, 0.5, 0.1],
});
console.log(batch.band, batch.state, batch.noisy, batch.changed, batch.rows, batch.cols, batch.combos); CUDA Bindings (Rust)
Additional details for the CUDA bindings can be found inside the VectorTA repository.
Performance Analysis
Across sizes, Rust CPU runs about 1.14× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)
Related Indicators
Average Directional Index
Technical analysis indicator
Average Directional Movement Index Rating
Technical analysis indicator
Alligator
Technical analysis indicator
Aroon
Technical analysis indicator
Aroon Oscillator
Technical analysis indicator
Chande Momentum Oscillator
Technical analysis indicator