Historical Volatility

Parameters: lookback = 20 | annualization_days = 250

Overview

Historical Volatility is the direct realized-volatility measure in this group. It converts a price series into percentage returns, computes the rolling standard deviation of those returns over the chosen lookback, and then annualizes the result. The output is the raw volatility line that other regime tools such as volatility rank and volatility percentile build on top of.

Because the indicator is intentionally simple, it works well as a baseline diagnostic for volatility expansion and contraction, and as an input into position sizing or regime filters. Candle input supports any supported source field, while slice input can be used directly for closes or other precomputed values.

Defaults: Historical Volatility uses `lookback = 20`, `annualization_days = 250.0`, and candle source `close`.

Implementation Examples

Compute rolling realized volatility from a series or directly from candles.

use vector_ta::indicators::historical_volatility::{
    historical_volatility,
    HistoricalVolatilityInput,
    HistoricalVolatilityParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let output = historical_volatility(
    &HistoricalVolatilityInput::from_slice(
        &close,
        HistoricalVolatilityParams {
            lookback: Some(20),
            annualization_days: Some(250.0),
        },
    ),
)?;

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

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

API Reference

Input Methods
// From candles
HistoricalVolatilityInput::from_candles(&Candles, &str, HistoricalVolatilityParams)
    -> HistoricalVolatilityInput

// From a slice
HistoricalVolatilityInput::from_slice(&[f64], HistoricalVolatilityParams)
    -> HistoricalVolatilityInput

// From candles with default parameters
HistoricalVolatilityInput::with_default_candles(&Candles)
    -> HistoricalVolatilityInput
Parameters Structure
pub struct HistoricalVolatilityParams {
    pub lookback: Option<usize>,            // default 20
    pub annualization_days: Option<f64>,    // default 250.0
}
Output Structure
pub struct HistoricalVolatilityOutput {
    pub values: Vec<f64>,
}
Validation, Warmup & NaNs
  • Input must not be empty and must contain enough valid returns to fill the requested lookback window.
  • lookback must be greater than 0 and compatible with the supplied data length.
  • annualization_days must be finite and positive.
  • Streaming warmup is exactly lookback bars.
  • Batch mode validates both axes and rejects unsupported kernels through InvalidKernelForBatch.
Builder, Streaming & Batch APIs
// Builder
HistoricalVolatilityBuilder::new()
    .lookback(usize)
    .annualization_days(f64)
    .kernel(Kernel)
    .apply(&Candles, &str)

HistoricalVolatilityBuilder::new()
    .apply_slice(&[f64])
    .into_stream()

// Stream
HistoricalVolatilityStream::try_new(HistoricalVolatilityParams)
HistoricalVolatilityStream::update(f64) -> Option<f64>
HistoricalVolatilityStream::get_warmup_period() -> usize

// Batch
HistoricalVolatilityBatchBuilder::new()
    .lookback_range(usize, usize, usize)
    .annualization_days_range(f64, f64, f64)
    .kernel(Kernel)
    .apply_slice(&[f64])
Error Handling
pub enum HistoricalVolatilityError {
    EmptyInputData,
    AllValuesNaN,
    InvalidLookback { lookback: usize, data_len: usize },
    NotEnoughValidData { needed: usize, valid: usize },
    InvalidAnnualizationDays { annualization_days: f64 },
    OutputLengthMismatch { expected: usize, got: usize },
    InvalidRange { start: String, end: String, step: String },
    InvalidKernelForBatch(Kernel),
}

Python Bindings

Python exposes a scalar function, a stream class, and a batch sweep. The scalar and stream paths return the annualized volatility line directly. Batch returns a reshaped `values` matrix plus the tested lookbacks and annualization settings.

import numpy as np
from vector_ta import (
    historical_volatility,
    historical_volatility_batch,
    HistoricalVolatilityStream,
)

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

values = historical_volatility(
    data,
    lookback=20,
    annualization_days=250.0,
    kernel="auto",
)

stream = HistoricalVolatilityStream(lookback=20, annualization_days=250.0)
print(stream.update(float(data[-1])))

batch = historical_volatility_batch(
    data,
    lookback_range=(14, 20, 6),
    annualization_days_range=(250.0, 365.0, 115.0),
    kernel="auto",
)

print(batch["values"].shape)
print(batch["lookbacks"])

JavaScript/WASM Bindings

The WASM layer exposes scalar, batch, and into-buffer helpers. The scalar binding returns the volatility array directly. The batch binding returns flattened values together with parameter combos and matrix dimensions.

import init, {
  historical_volatility_js,
  historical_volatility_batch_js,
} from "@vectoralpha/vector_ta";

await init();

const single = historical_volatility_js(close, 20, 250.0);
console.log(single);

const batch = historical_volatility_batch_js(close, {
  lookback_range: [14, 20, 6],
  annualization_days_range: [250.0, 365.0, 115.0],
});

console.log(batch.values);
console.log(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