Rolling Variance (VAR)
period = 14 | nbdev = 1 Overview
Rolling Variance quantifies the dispersion of price values around their mean over a sliding window, providing the mathematical foundation for volatility measurement in technical analysis. The indicator calculates variance using the sum of squared deviations from the mean, offering a precise statistical measure of how much prices fluctuate rather than simply trending in one direction. Unlike standard deviation which returns values in the same units as price, variance returns squared units, making it particularly useful for volatility modeling and options pricing applications. The implementation employs efficient windowed calculations using running sums and sums of squares for batch processing, while maintaining a ring buffer for constant time streaming updates. An optional nbdev scaling factor allows traders to adjust the sensitivity of variance readings to match different risk management frameworks. Higher variance values indicate greater price dispersion and uncertainty, while lower readings suggest tighter clustering and more predictable behavior. Default parameters use a 14 period window with an nbdev multiplier of 1.0, matching conventional volatility measurement standards.
Implementation Examples
Get started with VAR in just a few lines:
use vectorta::indicators::var::{var, VarInput, VarParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using with price data slice
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let params = VarParams { period: Some(14), nbdev: Some(1.0) };
let input = VarInput::from_slice(&prices, params);
let result = var(&input)?;
// Using with Candles and default parameters (period=14, nbdev=1.0; source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = VarInput::with_default_candles(&candles);
let result = var(&input)?;
// Access the VAR values
for value in result.values {
println!("VAR: {}", value);
} API Reference
Input Methods ▼
// From price slice
VarInput::from_slice(&[f64], VarParams) -> VarInput
// From candles with custom source
VarInput::from_candles(&Candles, &str, VarParams) -> VarInput
// From candles with default params (close prices, period=14, nbdev=1.0)
VarInput::with_default_candles(&Candles) -> VarInput Parameters Structure ▼
pub struct VarParams {
pub period: Option<usize>, // Default: 14
pub nbdev: Option<f64>, // Default: 1.0 (output scaled by nbdev²)
} Output Structure ▼
pub struct VarOutput {
pub values: Vec<f64>, // Rolling variance values (scaled)
} Validation, Warmup & NaNs ▼
period > 0andperiod ≤ len, otherwiseVarError::InvalidPeriod.- At least
periodvalid points after the first finite value; elseVarError::NotEnoughValidData. nbdevmust be finite (not NaN/∞); elseVarError::InvalidNbdev.- All inputs NaN →
VarError::AllValuesNaN. - Warmup: indices before
first + period − 1areNaN(also invar_into_sliceand batch). - Streaming:
VarStream::updatereturnsNoneuntil the buffer fillsperiodsamples.
Error Handling ▼
use vectorta::indicators::var::{var, VarError};
match var(&input) {
Ok(output) => process_results(output.values),
Err(VarError::AllValuesNaN) =>
eprintln!("All input values are NaN"),
Err(VarError::InvalidPeriod { period, data_len }) =>
eprintln!("Invalid period {} for data length {}", period, data_len),
Err(VarError::NotEnoughValidData { needed, valid }) =>
eprintln!("Need {} valid points, only {} available", needed, valid),
Err(VarError::InvalidNbdev { nbdev }) =>
eprintln!("nbdev must be finite, got {}", nbdev),
} Python Bindings
Basic Usage ▼
Calculate VAR using NumPy arrays (defaults: period=14, nbdev=1.0):
import numpy as np
from vectorta import var
# Prepare price data as NumPy array
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5])
# Calculate VAR with defaults (14, 1.0)
result = var(prices)
# Or specify custom parameters
result = var(prices, period=20, nbdev=1.5)
# Specify kernel for performance optimization
result = var(prices, period=20, nbdev=1.5, kernel="avx2")
print(f"VAR values: {result}") Streaming Real-time Updates ▼
Process real-time price updates efficiently:
from vectorta import VarStream
# Initialize streaming VAR calculator
stream = VarStream(period=14, nbdev=1.0)
# Process real-time price updates
for price in price_feed:
var_value = stream.update(price)
if var_value is not None:
print(f"Current VAR: {var_value}") Batch Parameter Optimization ▼
Test multiple parameter combinations for optimization:
import numpy as np
from vectorta import var_batch
prices = np.array([...])
# Define parameter ranges
period_range = (10, 30, 5) # 10, 15, 20, 25, 30
nbdev_range = (0.5, 2.0, 0.5) # 0.5, 1.0, 1.5, 2.0
results = var_batch(
prices,
period_range=period_range,
nbdev_range=nbdev_range,
kernel="auto"
)
print(results.keys()) # values, periods, nbdevs
print(results['values'].shape)
print(results['periods'])
print(results['nbdevs']) CUDA Acceleration ▼
CUDA support for VAR is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.
# Coming soon: CUDA-accelerated VAR calculations
# Will mirror the batch and many-series APIs used elsewhere in VectorTA. JavaScript/WASM Bindings
Basic Usage ▼
Compute VAR in the browser or Node via WASM:
import { var_js } from 'vectorta-wasm';
const prices = new Float64Array([100, 102, 101.5, 103, 105, 104.5]);
const period = 14;
const nbdev = 1.0;
const values = var_js(prices, period, nbdev);
console.log('VAR values:', values); Memory-Efficient Operations ▼
Use zero-copy operations for better performance with large datasets:
import { var_alloc, var_free, var_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* your data */]);
const length = prices.length;
// Allocate WASM memory for input and output
const inPtr = var_alloc(length);
const outPtr = var_alloc(length);
// Copy input data into WASM memory
new Float64Array(memory.buffer, inPtr, length).set(prices);
// Calculate VAR directly into allocated memory
// Args: in_ptr, out_ptr, len, period, nbdev
var_into(inPtr, outPtr, length, 14, 1.0);
// Read results
const varValues = new Float64Array(memory.buffer, outPtr, length).slice();
// Free allocated memory when done
var_free(inPtr, length);
var_free(outPtr, length);
console.log('VAR values:', varValues); Batch Processing ▼
Test multiple parameter combinations efficiently:
import { var_batch_js } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
// Define parameter sweep ranges
const config = {
period_range: [10, 30, 5], // 10, 15, 20, 25, 30
nbdev_range: [0.5, 2.0, 0.5] // 0.5, 1.0, 1.5, 2.0
};
const out = var_batch_js(prices, config);
// out.values is a flat array of length out.rows * out.cols
// out.combos is an array of VarParams objects with period/nbdev
// Reshape by rows/cols
const matrix: number[][] = [];
for (let r = 0; r < out.rows; r++) {
const start = r * out.cols;
matrix.push(out.values.slice(start, start + out.cols));
}
// Access specific parameter combination
const combo = out.combos[0]; // { period: 10, nbdev: 0.5 }
const firstRow = matrix[0]; Performance Analysis
Across sizes, Rust CPU runs about 1.36× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05