Stochastic Oscillator (Stoch)
fastk_period = 14 | slowk_period = 3 | slowk_ma_type = sma | slowd_period = 3 | slowd_ma_type = sma Overview
The Stochastic Oscillator evaluates momentum by positioning the current close within the recent high-low range. The raw %K calculation finds the highest high and lowest low over the fast period, then determines where the current close sits within that range on a 0-100 scale. This raw %K value undergoes smoothing to produce the slow %K line, which then receives additional smoothing to generate the %D signal line. The resulting dual-line oscillator identifies overbought conditions above 80 and oversold conditions below 20. Traders watch for %K and %D line crossovers to signal momentum shifts, with bullish crosses above 20 suggesting buying opportunities and bearish crosses below 80 indicating selling pressure. VectorTA provides flexible moving average type selection for both smoothing stages, defaulting to SMA(3) for both. The configurable smoothing allows adaptation from highly sensitive fast stochastics to smoother slow stochastics depending on trading timeframe and volatility environment.
Implementation Examples
Compute %K and %D from slices or candles:
use vectorta::indicators::stoch::{stoch, StochInput, StochParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// From high/low/close slices
let high = vec![/* ... */];
let low = vec![/* ... */];
let close = vec![/* ... */];
let params = StochParams { fastk_period: Some(14), slowk_period: Some(3), slowk_ma_type: Some("sma".into()), slowd_period: Some(3), slowd_ma_type: Some("sma".into()) };
let input = StochInput::from_slices(&high, &low, &close, params);
let out = stoch(&input)?; // out.k, out.d
// From Candles with defaults (fastk=14, slowk=3 SMA, slowd=3 SMA)
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = StochInput::with_default_candles(&candles);
let out = stoch(&input)?; API Reference
Input Methods ▼
// From candles (uses high/low/close fields)
StochInput::from_candles(&Candles, StochParams) -> StochInput
// From high/low/close slices
StochInput::from_slices(&[f64], &[f64], &[f64], StochParams) -> StochInput
// Defaults: fastk=14, slowk=3 (SMA), slowd=3 (SMA)
StochInput::with_default_candles(&Candles) -> StochInput Parameters Structure ▼
pub struct StochParams {
pub fastk_period: Option<usize>, // Default: 14
pub slowk_period: Option<usize>, // Default: 3
pub slowk_ma_type: Option<String>, // Default: "sma"
pub slowd_period: Option<usize>, // Default: 3
pub slowd_ma_type: Option<String>, // Default: "sma"
} Output Structure ▼
pub struct StochOutput {
pub k: Vec<f64>, // %K (smoothed by slowk)
pub d: Vec<f64>, // %D (MA of K)
} Validation, Warmup & NaNs ▼
fastk_period > 0,slowk_period > 0,slowd_period > 0; otherwiseStochError::InvalidPeriod.- All input series must have equal length; else
StochError::MismatchedLength. Empty inputs =>EmptyData. - First finite H/L/C index =
first. Need at leastfastk_periodvalid values afterfirstorNotEnoughValidData. - Warmup indices are
NaNby design:raw %Kstarts atfirst + fastk_period - 1,Kat+ slowk_period - 1,Dat+ slowd_period - 1. - If
HH − LL ≈ 0, %K is set to50.0for that bar.
Error Handling ▼
use vectorta::indicators::stoch::{stoch, StochError};
match stoch(&input) {
Ok(out) => consume(out.k, out.d),
Err(StochError::EmptyData) => eprintln!("no data"),
Err(StochError::MismatchedLength) => eprintln!("mismatched series lengths"),
Err(StochError::AllValuesNaN) => eprintln!("all values are NaN"),
Err(StochError::InvalidPeriod { period, data_len }) => eprintln!("invalid period {} for len {}", period, data_len),
Err(StochError::NotEnoughValidData { needed, valid }) => eprintln!("need {} valid points after first finite, found {}", needed, valid),
Err(StochError::Other(e)) => eprintln!("error: {}", e),
} Python Bindings
Basic Usage ▼
Compute %K and %D from NumPy arrays:
import numpy as np
from vectorta import stoch
high = np.array([...], dtype=float)
low = np.array([...], dtype=float)
close = np.array([...], dtype=float)
k, d = stoch(
high, low, close,
fastk_period=14,
slowk_period=3,
slowk_ma_type='sma',
slowd_period=3,
slowd_ma_type='sma',
kernel='auto'
)
print(k[-3:], d[-3:]) Streaming Real-time Updates ▼
from vectorta import StochStream
stream = StochStream(14, 3, 'sma', 3, 'sma')
for (h, l, c) in hlc_feed:
upd = stream.update(h, l, c)
if upd is not None:
k, d = upd
handle(k, d) Batch Parameter Sweep ▼
import numpy as np
from vectorta import stoch_batch
hi = np.array([...], dtype=float)
lo = np.array([...], dtype=float)
cl = np.array([...], dtype=float)
res = stoch_batch(
hi, lo, cl,
fastk_range=(10, 20, 5),
slowk_range=(3, 5, 1),
slowk_ma_type='sma',
slowd_range=(3, 5, 1),
slowd_ma_type='sma',
kernel='auto'
)
k = res['k'] # shape: (num_combos, len(cl))
d = res['d']
fk = res['fastk_periods']; sk = res['slowk_periods']
kt = res['slowk_types']; sd = res['slowd_periods']; dt = res['slowd_types'] JavaScript/WASM Bindings
Basic Usage ▼
Compute %K and %D in JavaScript/TypeScript:
import { stoch } from 'vectorta-wasm';
const high = new Float64Array([/* ... */]);
const low = new Float64Array([/* ... */]);
const close = new Float64Array([/* ... */]);
// Args: high, low, close, fastk, slowk, slowk_ma_type, slowd, slowd_ma_type
const out = stoch(high, low, close, 14, 3, 'sma', 3, 'sma');
// out: { values: Float64Array, rows: 2, cols: N }
const cols = out.cols;
const values = out.values; // [K row..., D row...]
const k = values.slice(0, cols);
const d = values.slice(cols, 2 * cols); Memory-Efficient Operations ▼
Use zero‑copy operations with explicit alloc/free:
import { stoch_alloc, stoch_free, stoch_into, memory } from 'vectorta-wasm';
const len = close.length;
const hiPtr = stoch_alloc(len);
const loPtr = stoch_alloc(len);
const clPtr = stoch_alloc(len);
const kPtr = stoch_alloc(len);
const dPtr = stoch_alloc(len);
new Float64Array(memory.buffer, hiPtr, len).set(high);
new Float64Array(memory.buffer, loPtr, len).set(low);
new Float64Array(memory.buffer, clPtr, len).set(close);
// Args: hi_ptr, lo_ptr, cl_ptr, len, fastk, slowk, slowk_ma, slowd, slowd_ma, out_k_ptr, out_d_ptr
stoch_into(hiPtr, loPtr, clPtr, len, 14, 3, 'sma', 3, 'sma', kPtr, dPtr);
const k = new Float64Array(memory.buffer, kPtr, len).slice();
const d = new Float64Array(memory.buffer, dPtr, len).slice();
stoch_free(hiPtr, len); stoch_free(loPtr, len); stoch_free(clPtr, len);
stoch_free(kPtr, len); stoch_free(dPtr, len); Batch Processing ▼
Test multiple parameter combinations efficiently:
import { stoch_batch } from 'vectorta-wasm';
const hi = new Float64Array([/* ... */]);
const lo = new Float64Array([/* ... */]);
const cl = new Float64Array([/* ... */]);
// Args: hi, lo, cl, fastk_start, fastk_end, fastk_step, slowk_start, slowk_end, slowk_step, slowk_type, slowd_start, slowd_end, slowd_step, slowd_type
const res = stoch_batch(hi, lo, cl, 10, 20, 5, 3, 5, 1, 'sma', 3, 5, 1, 'sma');
// res: { values, combos, rows_per_combo: 2, cols }
const cols = res.cols;
const combos = res.combos; // array of StochParams objects
const values = res.values; // flattened [all K rows..., then all D rows...]
// Example: extract the first combo's K and D
const k0 = values.slice(0, cols);
const d0 = values.slice(values.length/2, values.length/2 + cols); CUDA Acceleration
CUDA support for Stoch is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.
# Coming soon: CUDA-accelerated Stoch calculations
# from vectorta import stoch_cuda_batch_dev, stoch_cuda_many_series_one_param_dev
# ... Performance Analysis
Across sizes, Rust CPU runs about 1.05× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05