Variable Length Moving Average (VLMA)
min_period = 5 | max_period = 50 | matype = sma | devtype = 0 Overview
Variable Length Moving Average intelligently adjusts its effective smoothing period based on how far current price deviates from a reference moving average, creating an adaptive system that responds appropriately to different market states. The indicator calculates a reference mean and deviation measure over the maximum period, then uses price distance from this mean to modulate the smoothing length between minimum and maximum bounds. When price pushes beyond wide deviation bands, indicating potential breakouts or strong trends, VLMA shortens its period to track the move more responsively. Conversely, when price hovers near the mean within narrow bands during consolidation, the period extends to filter noise and prevent whipsaw signals. This distance based adaptation helps traders avoid the twin pitfalls of lag during trends and false signals during ranges. The exponential style update preserves smooth output characteristics while the variable period provides the adaptive edge. Default parameters use minimum and maximum periods of 5 and 50 bars with SMA as the reference mean and standard deviation for banding, optimized for broad applicability across different trading styles.
Implementation Examples
Get started with VLMA in just a few lines:
use vectorta::indicators::vlma::{vlma, VlmaInput, VlmaParams};
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 = VlmaParams {
min_period: Some(5),
max_period: Some(50),
matype: Some("sma".to_string()),
devtype: Some(0),
};
let input = VlmaInput::from_slice(&prices, params);
let result = vlma(&input)?;
// Using with Candles data structure
// Quick and simple with default parameters (min=5, max=50; source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = VlmaInput::with_default_candles(&candles);
let result = vlma(&input)?;
// Access the VLMA values
for value in result.values {
println!("VLMA: {}", value);
} API Reference
Input Methods ▼
// From price slice
VlmaInput::from_slice(&[f64], VlmaParams) -> VlmaInput
// From candles with custom source
VlmaInput::from_candles(&Candles, &str, VlmaParams) -> VlmaInput
// From candles with default params (close, min=5, max=50)
VlmaInput::with_default_candles(&Candles) -> VlmaInput Parameters Structure ▼
#[derive(Debug, Clone)]
pub struct VlmaParams {
pub min_period: Option<usize>, // Default: 5
pub max_period: Option<usize>, // Default: 50
pub matype: Option<String>, // Default: "sma"
pub devtype: Option<usize>, // Default: 0 (0=std, 1=mad, 2=median)
} Output Structure ▼
#[derive(Debug, Clone)]
pub struct VlmaOutput {
pub values: Vec<f64>, // Adaptive moving average values
} Validation, Warmup & NaNs ▼
VlmaError::EmptyDataif input slice is empty.VlmaError::InvalidPeriodRangewhenmin_period > max_period.VlmaError::InvalidPeriodwhenmax_period == 0ormax_period > data_len.VlmaError::AllValuesNaNif all inputs areNaN.VlmaError::NotEnoughValidData { needed, valid }if fewer thanmax_periodvalid points exist after the first finite value.- Warmup: output at
first_validequals that input; indices untilfirst_valid + max_period − 1areNaN. Values start at warmup end. - Post‑warmup: if an input at index
iisNaN, the output atiisNaN(pass‑through). - Period adapts by ±1 per bar and is clamped to
[min_period, max_period]. Smoothing usesα = 2/(p+1).
Error Handling ▼
use vectorta::indicators::vlma::{vlma, VlmaError};
match vlma(&input) {
Ok(output) => process_results(output.values),
Err(VlmaError::EmptyData) =>
eprintln!("vlma: empty data"),
Err(VlmaError::InvalidPeriodRange { min_period, max_period }) =>
eprintln!("min_period {} must be <= max_period {}", min_period, max_period),
Err(VlmaError::InvalidPeriod { min_period, max_period, data_len }) =>
eprintln!("invalid period (min={}, max={}) for data_len={}", min_period, max_period, data_len),
Err(VlmaError::AllValuesNaN) =>
eprintln!("all input values are NaN"),
Err(VlmaError::NotEnoughValidData { needed, valid }) =>
eprintln!("need {} valid points after first finite, only {}", needed, valid),
Err(VlmaError::MaError(e)) =>
eprintln!("reference MA error: {}", e),
Err(VlmaError::DevError(e)) =>
eprintln!("deviation error: {}", e),
} Python Bindings
Basic Usage ▼
Calculate VLMA using NumPy arrays (defaults: min=5, max=50, matype="sma", devtype=0):
import numpy as np
from vectorta import vlma
# Prepare price data as NumPy array
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5])
# Calculate VLMA with defaults
result = vlma(prices)
# Or specify custom parameters and kernel
result = vlma(prices, min_period=5, max_period=50, matype="sma", devtype=0, kernel="avx2")
print(f"VLMA values: {result}") Streaming Real-time Updates ▼
Process real-time price updates efficiently:
from vectorta import VlmaStream
# Initialize streaming VLMA calculator
stream = VlmaStream(min_period=5, max_period=50, matype="sma", devtype=0)
for price in price_feed:
vlma_value = stream.update(price)
if vlma_value is not None:
print(f"Current VLMA: {vlma_value}") Batch Parameter Optimization ▼
Test multiple parameter combinations for optimization:
import numpy as np
from vectorta import vlma_batch
prices = np.array([...])
# Define ranges as (start, end, step)
min_range = (5, 15, 5)
max_range = (30, 60, 10)
dev_range = (0, 2, 1)
results = vlma_batch(
prices,
min_period_range=min_range,
max_period_range=max_range,
devtype_range=dev_range,
matype="sma",
kernel="auto",
)
print(results["values"].shape) # (num_combos, len(prices))
print(results["min_periods"]) # list of min periods per row
print(results["max_periods"]) # list of max periods per row
print(results["devtypes"]) # list of devtypes per row
print(results["matypes"]) # list of matypes per row CUDA Acceleration ▼
CUDA support for VLMA is coming soon.
JavaScript/WASM Bindings
Basic Usage ▼
Calculate VLMA in JavaScript/TypeScript:
import { vlma_js } from 'vectorta-wasm';
const prices = new Float64Array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5]);
// Args: data, min_period, max_period, matype, devtype
const values = vlma_js(prices, 5, 50, 'sma', 0);
console.log('VLMA values:', values); Memory-Efficient Operations ▼
Use zero-copy operations for large datasets:
import { vlma_alloc, vlma_free, vlma_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* your data */]);
const n = prices.length;
const inPtr = vlma_alloc(n);
const outPtr = vlma_alloc(n);
new Float64Array(memory.buffer, inPtr, n).set(prices);
// in_ptr, out_ptr, len, min_period, max_period, matype, devtype
vlma_into(inPtr, outPtr, n, 5, 50, 'sma', 0);
const out = new Float64Array(memory.buffer, outPtr, n).slice();
vlma_free(inPtr, n);
vlma_free(outPtr, n);
console.log('VLMA values:', out); Batch Processing ▼
Compute multiple parameter combinations:
import { vlma_batch } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
// Unified batch API: config object
const cfg = {
min_period_range: [5, 15, 5], // start, end, step
max_period_range: [30, 60, 10],
devtype_range: [0, 2, 1],
matype: 'sma'
};
// Returns { values, combos, rows, cols }
const res = vlma_batch(prices, cfg);
// values is flat [row0..., row1..., ...] with rows = combos.length
const matrix = [];
for (let r = 0; r < res.rows; r++) {
const start = r * res.cols;
matrix.push(res.values.slice(start, start + res.cols));
}
// Access combo parameters
console.log(res.combos[0]); // { min_period, max_period, matype, devtype }
console.log(matrix[0]); // VLMA for first combo Performance Analysis
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05
CUDA note
In our benchmark workload, the Rust CPU implementation is faster than CUDA for this indicator. Prefer the Rust/CPU path unless your workload differs.
Related Indicators
Arnaud Legoux Moving Average
Moving average indicator
Compound Ratio Moving Average (CoRa Wave)
Moving average indicator
Centered Weighted Moving Average
Moving average indicator
Double Exponential Moving Average
Moving average indicator
Ehlers Distance Coefficient Filter
Moving average indicator
Ehlers Error-Correcting EMA (ECEMA)
Moving average indicator