Standard Deviation (STDDEV)

Parameters: period = 5 | nbdev = 1

Overview

Standard Deviation measures the dispersion of price values around their mean over a rolling window. The indicator calculates how much individual prices deviate from the average by computing the square root of the average squared difference from the mean. Higher values indicate greater volatility and price dispersion, while lower values suggest prices are clustering tightly around the mean. Traders use standard deviation to gauge market volatility, size position risk appropriately, and identify periods of consolidation versus expansion. The indicator often serves as a core component in volatility based strategies like Bollinger Bands, where it defines the width of price channels. Default period is 5 with an nbdev multiplier of 1.0, matching common volatility measurement conventions in technical analysis.

Implementation Examples

Compute rolling standard deviation from slices or candles:

use vectorta::indicators::stddev::{stddev, StdDevInput, StdDevParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};

// From a price slice (defaults: period=5, nbdev=1.0)
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let input = StdDevInput::from_slice(&prices, StdDevParams::default());
let out = stddev(&input)?;

// From candles with defaults (source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = StdDevInput::with_default_candles(&candles);
let out = stddev(&input)?;

// Access values
for v in out.values { println!("stddev: {}", v); }

API Reference

Input Methods
// From price slice
StdDevInput::from_slice(&[f64], StdDevParams) -> StdDevInput

// From candles with custom source
StdDevInput::from_candles(&Candles, &str, StdDevParams) -> StdDevInput

// From candles with default params (close prices, period=5, nbdev=1.0)
StdDevInput::with_default_candles(&Candles) -> StdDevInput
Parameters Structure
pub struct StdDevParams {
    pub period: Option<usize>, // Default: 5
    pub nbdev: Option<f64>,    // Default: 1.0 (≥ 0)
}
Output Structure
pub struct StdDevOutput {
    pub values: Vec<f64>, // Rolling stddev × nbdev
}
Validation, Warmup & NaNs
  • period > 0, nbdev ≥ 0, nbdev must be finite; else StdDevError::InvalidPeriod / InvalidNbdev.
  • Finds first finite input index first; requires at least period valid points after first or StdDevError::NotEnoughValidData.
  • Warmup: indices < first + period − 1 are NaN. First finite output at warmup index.
  • Constant windows yield 0.0 (variance ≤ 0). Subsequent NaN inputs propagate to NaN outputs.
  • Population variance is used: σ² = E[x²] − (E[x])² with E[⋅] over the window (divide by n).
Error Handling
use vectorta::indicators::stddev::{stddev, StdDevInput, StdDevParams, StdDevError};

match stddev(&StdDevInput::from_slice(&prices, StdDevParams::default())) {
    Ok(output) => handle(output.values),
    Err(StdDevError::EmptyInputData) => eprintln!("Input is empty"),
    Err(StdDevError::AllValuesNaN) => eprintln!("All input values are NaN"),
    Err(StdDevError::InvalidPeriod { period, data_len }) =>
        eprintln!("Invalid period {} for length {}", period, data_len),
    Err(StdDevError::NotEnoughValidData { needed, valid }) =>
        eprintln!("Need {} valid points, have {}", needed, valid),
    Err(StdDevError::InvalidNbdev { nbdev }) =>
        eprintln!("nbdev must be non-negative and finite, got {}", nbdev),
    Err(StdDevError::MismatchedOutputLen { dst_len, expected_len }) =>
        eprintln!("Output len {} != expected {}", dst_len, expected_len),
    Err(StdDevError::InvalidKernel { msg }) =>
        eprintln!("Kernel error: {}", msg),
}

Python Bindings

Basic Usage

Calculate STDDEV in Python (population variance, nbdev scale):

import numpy as np
from vectorta import stddev

prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5], dtype=np.float64)
values = stddev(prices, period=5, nbdev=1.0, kernel='auto')
print(values)
Streaming
from vectorta import StdDevStream

stream = StdDevStream(period=20, nbdev=2.0)
for p in price_stream:
    s = stream.update(p)  # None until the window is full
    if s is not None:
        handle(s)
Batch Parameter Sweep
import numpy as np
from vectorta import stddev_batch

prices = np.asarray(prices, dtype=np.float64)
res = stddev_batch(
    prices,
    period_range=(5, 30, 5),   # 5,10,15,20,25,30
    nbdev_range=(1.0, 3.0, 0.5),
    kernel='auto'
)

# res is a dict with keys: 'values' [rows x cols], 'periods', 'nbdevs'
values = res['values']
periods = res['periods']
nbdevs = res['nbdevs']
CUDA Acceleration

CUDA support for STDDEV is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.

# Coming soon: CUDA-accelerated STDDEV calculations
# from vectorta import stddev_cuda_batch, stddev_cuda_many_series_one_param
# ...

JavaScript/WASM Bindings

Basic Usage

Calculate STDDEV in JavaScript/TypeScript:

import { stddev_js } from 'vectorta-wasm';

const prices = new Float64Array([100, 102, 101.5, 103, 105, 104.5]);
const values = stddev_js(prices, 20, 2.0);
console.log('STDDEV:', values);
Memory-Efficient Operations

Use zero-copy operations with preallocated WASM memory:

import { stddev_alloc, stddev_free, stddev_into, memory } from 'vectorta-wasm';

const prices = new Float64Array([/* your data */]);
const n = prices.length;
const inPtr = stddev_alloc(n);
const outPtr = stddev_alloc(n);
new Float64Array(memory.buffer, inPtr, n).set(prices);

// Args: in_ptr, out_ptr, len, period, nbdev
stddev_into(inPtr, outPtr, n, 20, 2.0);
const out = new Float64Array(memory.buffer, outPtr, n).slice();

stddev_free(inPtr, n);
stddev_free(outPtr, n);
Batch Processing

Test parameter sweeps via a unified config:

import { stddev_batch } from 'vectorta-wasm';

const prices = new Float64Array([/* historical prices */]);
const config = {
  period_range: [5, 30, 5],   // start, end, step
  nbdev_range: [1.0, 3.0, 0.5]
};

// Returns a JSON-like object with values (flat), periods, nbdevs, rows, cols
const res = stddev_batch(prices, config);
// reshape if desired based on rows/cols

Performance Analysis

Comparison:
View:

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

Loading chart...

AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05

Related Indicators