Multi-Length Stochastic Average

Parameters: length = 14 | presmooth = 10 | premethod = sma | postsmooth = 10 | postmethod = sma

Overview

Multi-Length Stochastic Average turns one price source into a composite stochastic oscillator. It can pre-smooth the source first, then for each bar it measures where the newest pre-smoothed value sits inside every rolling min-max window from length 4 up to the configured maximum length, averages those normalized readings, and scales the result to a 0 to 100 range.

An optional post-smoothing stage can then smooth that averaged stochastic output again. Candle mode defaults to `close`, smoothing method names are normalized to lowercase, and the streaming implementation resets when it receives a non-finite input or when the current rolling range collapses to zero.

Defaults: `length = 14`, `presmooth = 10`, `premethod = "sma"`, `postsmooth = 10`, `postmethod = "sma"`, and candle input defaults to `close`.

Implementation Examples

Run the indicator on a raw slice or on candle data with the default close source.

use vector_ta::indicators::multi_length_stochastic_average::{
    multi_length_stochastic_average,
    MultiLengthStochasticAverageInput,
    MultiLengthStochasticAverageParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let close = vec![101.0, 101.8, 102.4, 101.9, 103.1, 104.0, 103.6, 104.8];

let output = multi_length_stochastic_average(&MultiLengthStochasticAverageInput::from_slice(
    &close,
    MultiLengthStochasticAverageParams::default(),
))?;

let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = multi_length_stochastic_average(
    &MultiLengthStochasticAverageInput::with_default_candles(&candles),
)?;

println!("{:?}", output.values.last());
println!("{}", candle_output.values.len());

API Reference

Input Methods
// From candles and a named source field
MultiLengthStochasticAverageInput::from_candles(
    &Candles,
    &str,
    MultiLengthStochasticAverageParams,
) -> MultiLengthStochasticAverageInput

// From a raw slice
MultiLengthStochasticAverageInput::from_slice(
    &[f64],
    MultiLengthStochasticAverageParams,
) -> MultiLengthStochasticAverageInput

// From candles with defaults
MultiLengthStochasticAverageInput::with_default_candles(&Candles)
    -> MultiLengthStochasticAverageInput
Parameters Structure
pub struct MultiLengthStochasticAverageParams {
    pub length: Option<usize>,       // default 14, minimum 4
    pub presmooth: Option<usize>,    // default 10, minimum 1
    pub premethod: Option<String>,   // none | sma | tma | lsma
    pub postsmooth: Option<usize>,   // default 10, minimum 1
    pub postmethod: Option<String>,  // none | sma | tma | lsma
}
Output Structure
pub struct MultiLengthStochasticAverageOutput {
    pub values: Vec<f64>,
}
Validation, Warmup & NaNs
  • The input slice must be non-empty and contain at least one finite value.
  • length must be at least 4 and cannot exceed the input length.
  • presmooth and postsmooth must both be greater than 0.
  • Supported smoothing methods are none, sma, tma, and lsma; method names are canonicalized to lowercase.
  • Total warmup is pre_warmup + (length - 1) + post_warmup, where none -> 0, sma and lsma -> method_length - 1, and tma -> 2 * (method_length - 1).
  • Single-run mode requires at least total_warmup + 1 consecutive finite values; output slots before the warmup point are NaN.
  • Streaming resets on non-finite input and also resets the post-smoother if the current rolling max and min are effectively equal.
  • Batch range expansion accepts ascending or descending integer ranges, but a zero step is only valid when the start and end are the same.
Builder, Streaming & Batch APIs
// Builder
MultiLengthStochasticAverageBuilder::new()
    .length(usize)
    .presmooth(usize)
    .premethod(impl Into<String>)
    .postsmooth(usize)
    .postmethod(impl Into<String>)
    .kernel(Kernel)
    .apply_slice(&[f64])

MultiLengthStochasticAverageBuilder::new()
    .apply(&Candles, &str)

MultiLengthStochasticAverageBuilder::new()
    .into_stream()

// Stream
MultiLengthStochasticAverageStream::try_new(MultiLengthStochasticAverageParams)
MultiLengthStochasticAverageStream::update(f64) -> Option<f64>
MultiLengthStochasticAverageStream::get_warmup_period() -> usize
MultiLengthStochasticAverageStream::reset()

// Batch
MultiLengthStochasticAverageBatchBuilder::new()
    .length_range(start, end, step)
    .presmooth_range(start, end, step)
    .postsmooth_range(start, end, step)
    .premethod(impl Into<String>)
    .postmethod(impl Into<String>)
    .kernel(Kernel)
    .apply_slice(&[f64])

MultiLengthStochasticAverageBatchBuilder::new()
    .apply_candles(&Candles, &str)
Error Handling
pub enum MultiLengthStochasticAverageError {
    EmptyInputData,
    AllValuesNaN,
    InvalidLength { length: usize, data_len: usize },
    InvalidPresmooth { presmooth: usize },
    InvalidPostsmooth { postsmooth: usize },
    InvalidPreMethod { premethod: String },
    InvalidPostMethod { postmethod: String },
    NotEnoughValidData { needed: usize, valid: usize },
    OutputLengthMismatch { expected: usize, got: usize },
    InvalidRange { start: String, end: String, step: String },
    InvalidKernelForBatch(Kernel),
}

Python Bindings

Python exposes a NumPy-returning single-run function, a streaming class with a warmup_period property, and a batch function that returns the output matrix plus the parameter grid used for each row.

import numpy as np
from vector_ta import (
    multi_length_stochastic_average,
    multi_length_stochastic_average_batch,
    MultiLengthStochasticAverageStream,
)

data = np.asarray(close_values, dtype=np.float64)

values = multi_length_stochastic_average(
    data,
    length=14,
    presmooth=10,
    premethod="sma",
    postsmooth=10,
    postmethod="sma",
    kernel="auto",
)

stream = MultiLengthStochasticAverageStream(
    length=14,
    presmooth=10,
    premethod="sma",
    postsmooth=10,
    postmethod="lsma",
)
print(stream.warmup_period)
print(stream.update(data[-1]))

batch = multi_length_stochastic_average_batch(
    data,
    length_range=(14, 20, 2),
    presmooth_range=(5, 15, 5),
    premethod="sma",
    postsmooth_range=(5, 10, 5),
    postmethod="lsma",
    kernel="auto",
)

print(batch["values"].shape)
print(batch["lengths"])
print(batch["premethods"])
print(batch["rows"], batch["cols"])

JavaScript/WASM Bindings

The WASM layer exposes an object-returning scalar wrapper, an object-returning batch wrapper, and lower-level alloc, free, into, and batch_into exports. The scalar wrapper returns an object with a single values array, while batch adds the flattened matrix, per-row parameter arrays, combos, and the rows and cols shape.

import init, {
  multi_length_stochastic_average_js,
  multi_length_stochastic_average_batch_js,
} from "/pkg/vector_ta.js";

await init();

const data = new Float64Array(closeValues);

const single = multi_length_stochastic_average_js(
  data,
  14,
  10,
  "sma",
  10,
  "sma",
);
console.log(single.values);

const batch = multi_length_stochastic_average_batch_js(data, {
  length_range: [14, 20, 2],
  presmooth_range: [5, 15, 5],
  premethod: "sma",
  postsmooth_range: [5, 10, 5],
  postmethod: "lsma",
});

console.log(batch.values);
console.log(batch.lengths, batch.presmooths, batch.postsmooths);
console.log(batch.premethods, batch.postmethods);
console.log(batch.combos, batch.rows, batch.cols);

CUDA Bindings (Rust)

Additional details for the CUDA bindings can be found inside the VectorTA repository.

Performance Analysis

Comparison:
View:
Placeholder data (no recorded benchmarks for this indicator)

Across sizes, Rust CPU runs about 1.14× faster than Tulip C in this benchmark.

Loading chart...

AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)

Related Indicators