Stochastic Distance
lookback_length = 200 | length1 = 12 | length2 = 3 | ob_level = 40 | os_level = -40 Overview
Stochastic Distance evaluates where the current price sits inside a broad rolling range, then turns that distance into an oscillator with a companion signal line. Instead of outputting the classic stochastic percentage directly, it focuses on the distance relationship and gives you configurable overbought and oversold guide rails so the same study can be interpreted as either a mean-reversion or momentum-following oscillator.
In VectorTA the indicator works on a single price slice or on candle closes, supports a streaming update path for live bars, and exposes batch sweeps across the long lookback, the two smoothing lengths, and both threshold levels. That makes it practical for regime studies where you want to compare how the same distance oscillator behaves under different range horizons and threshold settings.
Defaults: `lookback_length = 200`, `length1 = 12`, `length2 = 3`, `ob_level = 40`, and `os_level = -40`.
Implementation Examples
Run the indicator on a direct price slice or on candle closes using the default thresholds.
use vector_ta::indicators::stochastic_distance::{
stochastic_distance,
StochasticDistanceInput,
StochasticDistanceParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let direct = stochastic_distance(&StochasticDistanceInput::from_slice(
&close,
StochasticDistanceParams {
lookback_length: Some(200),
length1: Some(12),
length2: Some(3),
ob_level: Some(40),
os_level: Some(-40),
},
))?;
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let from_candles = stochastic_distance(
&StochasticDistanceInput::with_default_candles(&candles),
)?;
println!("latest oscillator = {:?}", direct.oscillator.last());
println!("latest signal = {:?}", direct.signal.last());
println!("candle signal = {:?}", from_candles.signal.last()); API Reference
Input Methods ▼
StochasticDistanceInput::from_candles(&Candles, StochasticDistanceParams)
-> StochasticDistanceInput
StochasticDistanceInput::from_slice(&[f64], StochasticDistanceParams)
-> StochasticDistanceInput
StochasticDistanceInput::with_default_candles(&Candles)
-> StochasticDistanceInput Parameters Structure ▼
pub struct StochasticDistanceParams {
pub lookback_length: Option<usize>, // default 200
pub length1: Option<usize>, // default 12
pub length2: Option<usize>, // default 3
pub ob_level: Option<i32>, // default 40
pub os_level: Option<i32>, // default -40
} Output Structure ▼
pub struct StochasticDistanceOutput {
pub oscillator: Vec<f64>,
pub signal: Vec<f64>,
} Validation, Thresholds & NaNs ▼
- The source slice must not be empty or entirely NaN, and the resolved lookback and smoothing lengths must fit the available data.
lookback_length,length1, andlength2are validated independently and return the documented length errors when they do not fit.os_levelmust be strictly less thanob_levelor the indicator returns the threshold validation error.- The stream path returns
Noneuntil enough valid values arrive to fill the rolling range and both smoothing stages. - Output buffers must match the source length or the indicator returns the documented output-length mismatch error.
- Batch mode validates every axis and rejects non-batch kernels.
Builder, Streaming & Batch APIs ▼
StochasticDistanceBuilder::new()
.lookback_length(usize)
.length1(usize)
.length2(usize)
.ob_level(i32)
.os_level(i32)
.kernel(Kernel)
.apply(&Candles)
.apply_slice(&[f64])
.into_stream()
StochasticDistanceStream::try_new(params)
stream.update(value) -> Option<(f64, f64)>
StochasticDistanceBatchBuilder::new()
.lookback_length(start, end, step)
.length1(start, end, step)
.length2(start, end, step)
.ob_level(start, end, step)
.os_level(start, end, step)
.kernel(Kernel)
.apply_slice(&[f64]) Python Bindings
Python exposes a direct function, a streaming class, and a batch helper that returns oscillator and signal matrices alongside the resolved sweep axes for the lookback, smoothing, and threshold settings.
from vector_ta import (
stochastic_distance,
stochastic_distance_batch,
StochasticDistanceStream,
)
oscillator, signal = stochastic_distance(
close,
lookback_length=200,
length1=12,
length2=3,
ob_level=40,
os_level=-40,
)
stream = StochasticDistanceStream(
lookback_length=200,
length1=12,
length2=3,
ob_level=40,
os_level=-40,
)
point = stream.update(close[-1])
batch = stochastic_distance_batch(
close,
lookback_length_range=(150, 200, 25),
length1_range=(10, 14, 2),
length2_range=(3, 5, 1),
ob_level_range=(35, 45, 5),
os_level_range=(-45, -35, 5),
)
print(batch["oscillator"].shape)
print(batch["lookback_lengths"]) JavaScript/WASM Bindings
The WASM layer exposes a high-level single-call API, an object-returning batch helper, and low-level allocation and into-buffer entry points for caller-managed memory.
import init, {
stochastic_distance_js,
stochastic_distance_batch_js,
stochastic_distance_alloc,
stochastic_distance_free,
stochastic_distance_into,
stochastic_distance_batch_into,
} from "vector-ta-wasm";
await init();
const single = stochastic_distance_js(close, 200, 12, 3, 40, -40);
console.log(single.oscillator, single.signal);
const batch = stochastic_distance_batch_js(close, {
lookback_length_range: [150, 200, 25],
length1_range: [10, 14, 2],
length2_range: [3, 5, 1],
ob_level_range: [35, 45, 5],
os_level_range: [-45, -35, 5],
});
const ptrIn = stochastic_distance_alloc(close.length);
const ptrOsc = stochastic_distance_alloc(close.length);
const ptrSig = stochastic_distance_alloc(close.length);
stochastic_distance_into(ptrIn, ptrOsc, ptrSig, close.length, 200, 12, 3, 40, -40);
stochastic_distance_free(ptrIn, close.length);
stochastic_distance_free(ptrOsc, close.length);
stochastic_distance_free(ptrSig, close.length); 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)