Garman-Klass Volatility

Parameters: lookback = 14

Overview

Garman-Klass Volatility is a realized-volatility estimator that uses the full OHLC bar instead of relying only on closing returns. The core variance term combines the logarithmic high-low range with the open-to-close move, then averages those terms across a rolling window before taking the square root. That gives a smoother estimate of recent volatility while still responding to bars that expand intraday range.

In VectorTA, the indicator works on complete OHLC candles and expects all four fields to stay finite and positive. The batch API sweeps multiple lookbacks, and the streaming API maintains the same rolling estimator online with O(1) updates once the warmup window has filled.

Defaults: Garman-Klass Volatility uses `lookback = 14`.

Implementation Examples

Compute the rolling Garman-Klass volatility series from OHLC slices or candle data.

use vector_ta::indicators::garman_klass_volatility::{
    garman_klass_volatility,
    GarmanKlassVolatilityInput,
    GarmanKlassVolatilityParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let open = vec![100.0, 101.0, 100.8, 102.3, 101.9, 103.1];
let high = vec![101.2, 102.4, 101.9, 103.5, 103.0, 104.2];
let low = vec![99.5, 100.2, 99.9, 101.4, 101.0, 102.5];
let close = vec![100.7, 101.9, 101.1, 102.8, 102.4, 103.9];

let output = garman_klass_volatility(&GarmanKlassVolatilityInput::from_slices(
    &open,
    &high,
    &low,
    &close,
    GarmanKlassVolatilityParams { lookback: Some(14) },
))?;

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

println!("latest volatility = {:?}", output.values.last());
println!("series length = {}", candle_output.values.len());

API Reference

Input Methods
// From candles
GarmanKlassVolatilityInput::from_candles(&Candles, GarmanKlassVolatilityParams)
    -> GarmanKlassVolatilityInput

// From OHLC slices
GarmanKlassVolatilityInput::from_slices(&[f64], &[f64], &[f64], &[f64], GarmanKlassVolatilityParams)
    -> GarmanKlassVolatilityInput

// From candles with default parameters
GarmanKlassVolatilityInput::with_default_candles(&Candles)
    -> GarmanKlassVolatilityInput
Parameters Structure
pub struct GarmanKlassVolatilityParams {
    pub lookback: Option<usize>, // default 14
}
Output Structure
pub struct GarmanKlassVolatilityOutput {
    pub values: Vec<f64>,
}
Validation, Warmup & NaNs
  • All OHLC inputs must be non-empty and have matching lengths.
  • Every valid bar must have finite, strictly positive open, high, low, and close values.
  • lookback must be greater than 0 and must not exceed the available series length.
  • The indicator requires at least lookback valid OHLC bars; otherwise it returns NotEnoughValidData.
  • One-shot output is NaN-prefixed until the first full valid rolling window has been observed.
  • Streaming returns None until the window is fully populated with valid bars, and invalid bars break the all-valid requirement for the current window.
  • Batch mode validates sweep ranges and rejects non-batch kernels through InvalidKernelForBatch.
Builder, Streaming & Batch APIs
// Builder
GarmanKlassVolatilityBuilder::new()
    .lookback(usize)
    .kernel(Kernel)
    .apply(&Candles)

GarmanKlassVolatilityBuilder::new()
    .apply_slices(&[f64], &[f64], &[f64], &[f64])

GarmanKlassVolatilityBuilder::new()
    .into_stream()

// Stream
GarmanKlassVolatilityStream::try_new(GarmanKlassVolatilityParams)
GarmanKlassVolatilityStream::update(f64, f64, f64, f64) -> Option<f64>
GarmanKlassVolatilityStream::get_warmup_period() -> usize

// Batch
GarmanKlassVolatilityBatchBuilder::new()
    .kernel(Kernel)
    .lookback_range(start, end, step)
    .lookback_static(value)
    .apply_slices(&[f64], &[f64], &[f64], &[f64])

GarmanKlassVolatilityBatchBuilder::new()
    .apply_candles(&Candles)

GarmanKlassVolatilityBatchBuilder::with_default_candles(&Candles)
Error Handling
pub enum GarmanKlassVolatilityError {
    EmptyInputData,
    AllValuesNaN,
    InvalidLookback { lookback: usize, data_len: usize },
    NotEnoughValidData { needed: usize, valid: usize },
    InconsistentSliceLengths {
        open_len: usize,
        high_len: usize,
        low_len: usize,
        close_len: usize,
    },
    OutputLengthMismatch { expected: usize, got: usize },
    InvalidRange { start: String, end: String, step: String },
    InvalidKernelForBatch(Kernel),
}

Python Bindings

Python exposes a scalar OHLC function, a streaming class, and a batch sweep. The scalar path returns one NumPy volatility array. Streaming returns one floating-point volatility estimate or `None`, while batch returns the flattened volatility matrix together with the tested lookback values and output dimensions.

import numpy as np
from vector_ta import (
    garman_klass_volatility,
    garman_klass_volatility_batch,
    GarmanKlassVolatilityStream,
)

open_ = np.asarray(open_values, dtype=np.float64)
high = np.asarray(high_values, dtype=np.float64)
low = np.asarray(low_values, dtype=np.float64)
close = np.asarray(close_values, dtype=np.float64)

values = garman_klass_volatility(
    open_,
    high,
    low,
    close,
    lookback=14,
    kernel="auto",
)

stream = GarmanKlassVolatilityStream(lookback=14)
print(stream.update(open_[-1], high[-1], low[-1], close[-1]))

batch = garman_klass_volatility_batch(
    open_,
    high,
    low,
    close,
    lookback_range=(10, 30, 10),
    kernel="auto",
)

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

JavaScript/WASM Bindings

The WASM surface includes a direct array-returning function, a batch function, and raw allocation and into-buffer helpers for preallocated memory workflows. The scalar binding returns a single volatility array. The batch binding returns the flattened values matrix plus the tested parameter combinations and output dimensions.

import init, {
  garman_klass_volatility_js,
  garman_klass_volatility_batch_js,
} from "@vectoralpha/vector_ta";

await init();

const values = garman_klass_volatility_js(open, high, low, close, 14);
console.log(values);

const batch = garman_klass_volatility_batch_js(open, high, low, close, {
  lookback_range: [10, 30, 10],
});

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