Historical Volatility Rank
hv_length = 10 | rank_length = 364 | annualization_days = 365 | bar_days = 1 Overview
Historical Volatility Rank begins with a rolling historical-volatility calculation and then asks where the current volatility value sits inside a longer ranking window. Instead of using percentile counts, it normalizes the current reading between the rolling minimum and maximum historical-volatility values observed over that rank window. The result is a 0 to 100 regime score that is straightforward to use in filters and dashboards.
The indicator returns both the rank line and the underlying historical-volatility line. The rank is the regime indicator, while the raw volatility series remains useful when you need the absolute annualized reading. Candle input uses close by default, and both annualization days and bar-day spacing are configurable so daily, weekly, or custom spacing can be modeled explicitly.
Defaults: Historical Volatility Rank uses `hv_length = 10`, `rank_length = 52 * 7`, `annualization_days = 365.0`, and `bar_days = 1.0`.
Implementation Examples
Compute the rank line and the underlying annualized volatility series from closes or candles.
use vector_ta::indicators::historical_volatility_rank::{
historical_volatility_rank,
HistoricalVolatilityRankInput,
HistoricalVolatilityRankParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let output = historical_volatility_rank(
&HistoricalVolatilityRankInput::from_slice(
&close,
HistoricalVolatilityRankParams {
hv_length: Some(10),
rank_length: Some(52 * 7),
annualization_days: Some(365.0),
bar_days: Some(1.0),
},
),
)?;
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = historical_volatility_rank(
&HistoricalVolatilityRankInput::with_default_candles(&candles),
)?;
println!("{:?}", output.hvr.last());
println!("{:?}", candle_output.hv.last()); API Reference
Input Methods ▼
// From candles
HistoricalVolatilityRankInput::from_candles(&Candles, HistoricalVolatilityRankParams)
-> HistoricalVolatilityRankInput
// From a slice
HistoricalVolatilityRankInput::from_slice(&[f64], HistoricalVolatilityRankParams)
-> HistoricalVolatilityRankInput
// From candles with default parameters
HistoricalVolatilityRankInput::with_default_candles(&Candles)
-> HistoricalVolatilityRankInput Parameters Structure ▼
pub struct HistoricalVolatilityRankParams {
pub hv_length: Option<usize>, // default 10
pub rank_length: Option<usize>, // default 52 * 7
pub annualization_days: Option<f64>, // default 365.0
pub bar_days: Option<f64>, // default 1.0
} Output Structure ▼
pub struct HistoricalVolatilityRankOutput {
pub hvr: Vec<f64>,
pub hv: Vec<f64>,
} Validation, Warmup & NaNs ▼
- Input must not be empty and must contain valid positive closes for volatility computation.
hv_lengthandrank_lengthmust be greater than0.annualization_daysandbar_daysmust be finite and positive.- Streaming exposes two warmups:
get_hv_warmup_period()for the volatility line andget_hvr_warmup_period()for the rank line. - Batch mode validates all axes and rejects unsupported kernels through
InvalidKernelForBatch.
Builder, Streaming & Batch APIs ▼
// Builder
HistoricalVolatilityRankBuilder::new()
.hv_length(usize)
.rank_length(usize)
.annualization_days(f64)
.bar_days(f64)
.kernel(Kernel)
.apply_slice(&[f64])
HistoricalVolatilityRankBuilder::new()
.apply_candles(&Candles)
.into_stream()
// Stream
HistoricalVolatilityRankStream::try_new(HistoricalVolatilityRankParams)
HistoricalVolatilityRankStream::update(f64) -> Option<(f64, f64)>
HistoricalVolatilityRankStream::get_hv_warmup_period() -> usize
HistoricalVolatilityRankStream::get_hvr_warmup_period() -> usize
// Batch
HistoricalVolatilityRankBatchBuilder::new()
.hv_length_range(usize, usize, usize)
.rank_length_range(usize, usize, usize)
.annualization_days_range(f64, f64, f64)
.bar_days_range(f64, f64, f64)
.kernel(Kernel)
.apply_slice(&[f64]) Error Handling ▼
pub enum HistoricalVolatilityRankError {
EmptyInputData,
AllValuesNaN,
InvalidHvLength { hv_length: usize, data_len: usize },
InvalidRankLength { rank_length: usize },
NotEnoughValidData { needed: usize, valid: usize },
InvalidAnnualizationDays { annualization_days: f64 },
InvalidBarDays { bar_days: f64 },
OutputLengthMismatch { expected: usize, got: usize },
InvalidRange { start: String, end: String, step: String },
InvalidKernelForBatch(Kernel),
BatchOutputLengthMismatch { dst_len: usize, expected_len: usize },
InvalidInput { msg: String },
} Python Bindings
Python exposes a scalar function, a stream class, and a batch sweep. The scalar and stream paths return the rank and the underlying historical-volatility reading together. Batch returns reshaped `hvr` and `hv` matrices plus the tested HV lengths, rank lengths, annualization days, and bar-day settings.
import numpy as np
from vector_ta import (
historical_volatility_rank,
historical_volatility_rank_batch,
HistoricalVolatilityRankStream,
)
data = np.asarray(close_values, dtype=np.float64)
hvr, hv = historical_volatility_rank(
data,
hv_length=10,
rank_length=52 * 7,
annualization_days=365.0,
bar_days=1.0,
kernel="auto",
)
stream = HistoricalVolatilityRankStream(
hv_length=10,
rank_length=52 * 7,
annualization_days=365.0,
bar_days=1.0,
)
print(stream.update(float(data[-1])))
batch = historical_volatility_rank_batch(
data,
hv_length_range=(10, 14, 4),
rank_length_range=(126, 252, 126),
annualization_days_range=(252.0, 365.0, 113.0),
bar_days_range=(1.0, 1.0, 0.0),
kernel="auto",
)
print(batch["hvr"].shape)
print(batch["rank_lengths"]) JavaScript/WASM Bindings
The WASM layer exposes scalar, batch, and into-buffer helpers. The scalar binding returns an object with `hvr` and `hv`. The batch binding returns flattened `hvr` and `hv` arrays plus the tested parameter combos and the matrix dimensions.
import init, {
historical_volatility_rank_js,
historical_volatility_rank_batch_js,
} from "@vectoralpha/vector_ta";
await init();
const single = historical_volatility_rank_js(close, 10, 52 * 7, 365.0, 1.0);
console.log(single.hvr);
console.log(single.hv);
const batch = historical_volatility_rank_batch_js(close, {
hv_length_range: [10, 14, 4],
rank_length_range: [126, 252, 126],
annualization_days_range: [252.0, 365.0, 113.0],
bar_days_range: [1.0, 1.0, 0.0],
});
console.log(batch.rows, batch.cols);
console.log(batch.combos); CUDA Bindings (Rust)
Additional details for the CUDA bindings can be found inside the VectorTA repository.
Performance Analysis
Across sizes, Rust CPU runs about 1.14× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)