Variable Index Dynamic Average (VIDYA)
short_period = 2 | long_period = 5 | alpha = 0.2 (0.05–0.5) Overview
Variable Index Dynamic Average adapts its smoothing characteristics dynamically based on market volatility by modulating an exponential moving average's alpha parameter. The indicator measures standard deviation over both short and long windows, then scales a base smoothing factor by the ratio of short term to long term volatility to create a volatility adjusted alpha value. During high volatility periods when short term deviation exceeds long term norms, the increased alpha makes VIDYA more responsive to price changes, allowing it to track rapid moves more closely. Conversely, in low volatility environments where price action is subdued, the reduced alpha increases smoothing to filter out noise and provide steadier trend signals. This adaptive mechanism helps traders maintain appropriate sensitivity across varying market conditions without manual parameter adjustments. The exponential update style preserves the smooth characteristics traders expect from moving averages while adding intelligent responsiveness that simpler indicators lack. Default parameters use a 2 period short window, 5 period long window, and base alpha of 0.2, calibrated to provide balanced adaptation for most intraday and swing trading applications.
Implementation Examples
Get started with VIDYA in a few lines:
use vectorta::indicators::vidya::{vidya, VidyaInput, VidyaParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using with price data slice
let prices = vec![100.0, 101.0, 100.5, 102.0, 103.5, 102.8];
let params = VidyaParams { short_period: Some(2), long_period: Some(5), alpha: Some(0.2) };
let input = VidyaInput::from_slice(&prices, params);
let result = vidya(&input)?;
// Using with Candles data structure
// Quick and simple with default parameters (short=2, long=5, alpha=0.2; source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = VidyaInput::with_default_candles(&candles);
let result = vidya(&input)?;
// Access the VIDYA values
for value in result.values {
println!("VIDYA: {}", value);
} API Reference
Input Methods ▼
// From price slice
VidyaInput::from_slice(&[f64], VidyaParams) -> VidyaInput
// From candles with custom source
VidyaInput::from_candles(&Candles, &str, VidyaParams) -> VidyaInput
// From candles with default params (close prices, 2/5, alpha=0.2)
VidyaInput::with_default_candles(&Candles) -> VidyaInput Parameters Structure ▼
pub struct VidyaParams {
pub short_period: Option<usize>, // Default: 2 (min 2)
pub long_period: Option<usize>, // Default: 5 (≥ short, min 2)
pub alpha: Option<f64>, // Default: 0.2 (0.0..=1.0)
} Output Structure ▼
pub struct VidyaOutput {
pub values: Vec<f64>, // Adaptive moving average values
} Validation, Warmup & NaNs ▼
short_period ≥ 2,long_period ≥ 2, andshort_period ≤ long_period.0.0 ≤ alpha ≤ 1.0; otherwiseVidyaError::InvalidParameters.- There must be at least
long_periodvalid points after the first finite input; otherwiseVidyaError::NotEnoughValidData. - Outputs before
first + long_period − 2areNaN. At that index, VIDYA is seeded to the price; next index updates with adaptivek. - If
σlong = 0, the ratio is treated as 0 (factork=0), so the value holds steady. - Streaming: returns
Noneuntillong_period − 1updates; firstSomeequals the current price, then adapts.
Error Handling ▼
use vectorta::indicators::vidya::{vidya, VidyaError};
match vidya(&input) {
Ok(output) => process_results(output.values),
Err(VidyaError::EmptyData) =>
eprintln!("Input data is empty"),
Err(VidyaError::AllValuesNaN) =>
eprintln!("All input values are NaN"),
Err(VidyaError::NotEnoughValidData { needed, valid }) =>
eprintln!("Need {} data points after first finite, only {} valid", needed, valid),
Err(VidyaError::InvalidParameters { short, long, alpha }) =>
eprintln!("Invalid params: short={}, long={}, alpha={}", short, long, alpha),
Err(VidyaError::InvalidOutputLength { dst_len, data_len }) =>
eprintln!("Output length {} ≠ input length {}", dst_len, data_len),
} Python Bindings
Basic Usage ▼
Calculate VIDYA using NumPy arrays (defaults: short=2, long=5, alpha=0.2):
import numpy as np
from vectorta import vidya
# Prepare price data as NumPy array
prices = np.array([100.0, 101.0, 100.5, 102.0, 103.5, 102.8])
# Calculate VIDYA with defaults (2/5, alpha=0.2)
result = vidya(prices, short_period=2, long_period=5, alpha=0.2)
# Or specify custom parameters and kernel
result = vidya(prices, short_period=3, long_period=10, alpha=0.25, kernel="avx2")
# Result is a NumPy array matching input length
print(f"VIDYA values: {result}") Streaming Real-time Updates ▼
Process real-time price updates efficiently:
from vectorta import VidyaStream
# Initialize streaming VIDYA calculator
stream = VidyaStream(short_period=2, long_period=5, alpha=0.2)
# Process real-time price updates
for price in price_feed:
vidya_value = stream.update(price)
if vidya_value is not None:
# Value is ready (None during warmup period)
print(f"Current VIDYA: {vidya_value}") Batch Parameter Optimization ▼
Test multiple parameter combinations:
import numpy as np
from vectorta import vidya_batch
# Your price data
prices = np.array([...]) # Your historical prices
# Define parameter ranges to test (start, end, step)
short_range = (2, 6, 2) # 2, 4, 6
long_range = (5, 15, 5) # 5, 10, 15
alpha_range = (0.1, 0.3, 0.1) # 0.1, 0.2, 0.3
# Run batch calculation
results = vidya_batch(
prices,
short_period_range=short_range,
long_period_range=long_range,
alpha_range=alpha_range,
kernel="auto"
)
# Access results
values = results['values'] # shape: (num_combinations, len(prices))
shorts = results['short_periods']
longs = results['long_periods']
alphas = results['alphas'] CUDA Acceleration ▼
CUDA support for VIDYA is currently under development. The API will follow the same pattern as other CUDA-enabled indicators.
# Coming soon: CUDA-accelerated VIDYA calculations
# Patterns will mirror other CUDA-enabled indicators in this project. JavaScript/WASM Bindings
Basic Usage ▼
Calculate VIDYA in JavaScript/TypeScript:
import { vidya_js } from 'vectorta-wasm';
// Price data as Float64Array or regular array
const prices = new Float64Array([100.0, 101.0, 100.5, 102.0, 103.5, 102.8]);
// Calculate VIDYA with specified parameters
const result = vidya_js(prices, 2, 5, 0.2); // short=2, long=5, alpha=0.2
// Result is a Float64Array
console.log('VIDYA values:', result);
// Use with async/await for better error handling
async function calculateVIDYA(prices: Float64Array): Promise<Float64Array> {
try {
return vidya_js(prices, 2, 5, 0.2);
} catch (error) {
console.error('VIDYA calculation failed:', error);
throw error;
}
} Memory-Efficient Operations ▼
Use zero-copy operations for better performance with large datasets:
import { vidya_alloc, vidya_free, vidya_into, memory } from 'vectorta-wasm';
// Prepare your price data
const prices = new Float64Array([/* your data */]);
const length = prices.length;
// Allocate WASM memory for input and output
const inPtr = vidya_alloc(length);
const outPtr = vidya_alloc(length);
// Copy input data into WASM memory
new Float64Array(memory.buffer, inPtr, length).set(prices);
// Calculate VIDYA directly into allocated memory
// Args: in_ptr, out_ptr, len, short_period, long_period, alpha
vidya_into(inPtr, outPtr, length, 2, 5, 0.2);
// Read results from WASM memory (slice() to copy out)
const vidyaValues = new Float64Array(memory.buffer, outPtr, length).slice();
// Free allocated memory when done
vidya_free(inPtr, length);
vidya_free(outPtr, length);
console.log('VIDYA values:', vidyaValues); Batch Processing ▼
Test multiple parameter combinations efficiently:
import { vidya_batch } from 'vectorta-wasm';
// Your price data
const prices = new Float64Array([/* historical prices */]);
// Define parameter sweep ranges
const config = {
short_period_range: [2, 6, 2], // 2, 4, 6
long_period_range: [5, 15, 5], // 5, 10, 15
alpha_range: [0.1, 0.3, 0.1] // 0.1, 0.2, 0.3
};
// Calculate all combinations
const { values, combos, rows, cols } = vidya_batch(prices, config);
// values is a flat Float64Array of length rows*cols
// combos is an array of parameter structs ({ short_period, long_period, alpha })
// Reshape example: collect rows
const matrix: Float64Array[] = [];
for (let r = 0; r < rows; r++) {
const start = r * cols;
matrix.push(values.slice(start, start + cols));
}
console.log('Tested combos:', combos);
console.log('First-row VIDYA values:', matrix[0]); Performance Analysis
Across sizes, Rust CPU runs about 1.92× faster than Tulip C in this benchmark.
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