Volume Adjusted Moving Average
length = 13 | vi_factor = 0.67 | strict = true | sample_period = 0 Overview
Volume Adjusted Moving Average dynamically modulates its effective lookback period based on trading volume intensity, creating a context aware smoothing system that responds to the strength behind price movements. The indicator compares each bar's volume against an average volume threshold, using a volume increment factor to adjust the effective window length inversely with volume activity. During high volume periods when institutional participation or significant news drives trading, the shortened window makes the average more responsive to capture the move's momentum. Conversely, during low volume consolidations when price movements lack conviction, the extended window provides greater smoothing to filter meaningless fluctuations. This volume sensitivity helps traders distinguish between price changes backed by substantial activity versus those occurring on thin participation. The strict mode setting determines whether the indicator accumulates full volume increments before producing values or uses available bars up to the length parameter. Default settings use a 13 period base length with a volume increment factor of 0.67, strict accumulation enabled, and cumulative volume averaging over all historical bars for normalization.
Implementation Examples
Calculate the Volume Adjusted MA from slices or candles:
use vectorta::indicators::moving_averages::volume_adjusted_ma::{
VolumeAdjustedMa, VolumeAdjustedMaInput, VolumeAdjustedMaParams
};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// From price and volume slices
let prices = vec![100.0, 101.5, 103.0, 102.5, 104.0];
let volumes = vec![2000.0, 1800.0, 2500.0, 1700.0, 3000.0];
let params = VolumeAdjustedMaParams { length: Some(13), vi_factor: Some(0.67), strict: Some(true), sample_period: Some(0) };
let input = VolumeAdjustedMaInput::from_slices(&prices, &volumes, params);
let out = VolumeAdjustedMa(&input)?;
// From Candles with defaults (source = "close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = VolumeAdjustedMaInput::with_default_candles(&candles);
let out = VolumeAdjustedMa(&input)?;
// Access values
for v in out.values { println!("VAMA: {}", v); } API Reference
Input Methods ▼
// From price and volume slices
VolumeAdjustedMaInput::from_slices(&[f64], &[f64], VolumeAdjustedMaParams) -> VolumeAdjustedMaInput
// From candles with custom source (e.g., "close")
VolumeAdjustedMaInput::from_candles(&Candles, &str, VolumeAdjustedMaParams) -> VolumeAdjustedMaInput
// From candles with defaults (close, length=13, vi_factor=0.67, strict=true, sample_period=0)
VolumeAdjustedMaInput::with_default_candles(&Candles) -> VolumeAdjustedMaInput Parameters Structure ▼
#[derive(Debug, Clone)]
pub struct VolumeAdjustedMaParams {
pub length: Option<usize>, // Default: 13 (must be > 0)
pub vi_factor: Option<f64>, // Default: 0.67 (must be > 0 and finite)
pub strict: Option<bool>, // Default: true
pub sample_period: Option<usize> // Default: 0 (0 = cumulative average)
} Output Structure ▼
pub struct VolumeAdjustedMaOutput {
pub values: Vec<f64>, // VAMA values
} Validation, Warmup & NaNs ▼
- Price and volume slices must be non‑empty and equal length; otherwise
DataLengthMismatchorEmpty…errors. length > 0andlength ≤ data_len; elseInvalidPeriod. Need at leastlengthvalid points after first finite; elseNotEnoughValidData.vi_factormust be finite and> 0; elseInvalidViFactor.- Warmup: indices
[0 .. first_finite + length − 2]areNaN. Withsample_period > 0, early indices before the first full window also yieldNaN. - Streaming:
update(price, volume)returnsNaNduring warmup; thereafter follows the batch semantics.
Error Handling ▼
use vectorta::indicators::moving_averages::volume_adjusted_ma::VolumeAdjustedMaError;
match VolumeAdjustedMa(&input) {
Ok(out) => process(out.values),
Err(VolumeAdjustedMaError::EmptyInputData) => eprintln!("price slice is empty"),
Err(VolumeAdjustedMaError::EmptyVolumeData) => eprintln!("volume slice is empty"),
Err(VolumeAdjustedMaError::AllValuesNaN) => eprintln!("all price values are NaN"),
Err(VolumeAdjustedMaError::InvalidPeriod { period, data_len }) => eprintln!("invalid length {} for data_len {}", period, data_len),
Err(VolumeAdjustedMaError::NotEnoughValidData { needed, valid }) => eprintln!("need {} valid points, have {}", needed, valid),
Err(VolumeAdjustedMaError::InvalidViFactor { vi_factor }) => eprintln!("invalid vi_factor {}", vi_factor),
Err(VolumeAdjustedMaError::DataLengthMismatch { price_len, volume_len }) => eprintln!("price={} volume={}", price_len, volume_len),
} Python Bindings
Basic Usage ▼
Compute from NumPy arrays of price and volume:
import numpy as np
from vectorta import VolumeAdjustedMa
prices = np.array([100.0, 101.5, 103.0, 102.5, 104.0])
volumes = np.array([2000.0, 1800.0, 2500.0, 1700.0, 3000.0])
# Defaults: length=13, vi_factor=0.67, strict=True, sample_period=0
result = VolumeAdjustedMa(prices, volumes)
# Custom parameters + kernel selection ("auto", "avx2", "avx512" if available)
result = VolumeAdjustedMa(prices, volumes, length=20, vi_factor=0.6, strict=True, sample_period=0, kernel="auto")
print(result) Streaming Real-time Updates ▼
from vectorta import VolumeAdjustedMaStream
stream = VolumeAdjustedMaStream(length=13, vi_factor=0.67, strict=True, sample_period=0)
for (price, volume) in price_volume_feed:
vama = stream.update(price, volume)
# During warmup, vama may be NaN
handle(vama) Batch Parameter Optimization ▼
import numpy as np
from vectorta import VolumeAdjustedMa_batch
prices = np.array([...], dtype=float)
volumes = np.array([...], dtype=float)
length_range = (10, 30, 5)
vi_factor_range = (0.5, 0.8, 0.1)
sample_period_range = (0, 0, 0) # keep cumulative avg
results = VolumeAdjustedMa_batch(
prices,
volumes,
length_range=length_range,
vi_factor_range=vi_factor_range,
sample_period_range=sample_period_range,
strict=True,
kernel="auto",
)
# Results is a dict: values (2D), lengths, vi_factors, sample_periods, stricts
print(results['values'].shape) CUDA Acceleration ▼
CUDA helpers are available for batch and multi‑series flows (when built with CUDA):
import numpy as np
from vectorta import (
volume_adjusted_ma_cuda_batch_dev,
volume_adjusted_ma_cuda_many_series_one_param_dev,
)
# One series, many parameter combos
prices_f32 = np.asarray(prices, dtype=np.float32)
volumes_f32 = np.asarray(volumes, dtype=np.float32)
out_dev = volume_adjusted_ma_cuda_batch_dev(
prices_f32,
volumes_f32,
length_range=(10, 30, 5),
vi_factor_range=(0.5, 0.8, 0.1),
sample_period_range=(0, 0, 0),
strict=True,
device_id=0,
)
# Many series (time-major), one parameter set
tm_prices = np.random.rand(1024, 64).astype(np.float32)
tm_vols = np.random.rand(1024, 64).astype(np.float32)
out_dev = volume_adjusted_ma_cuda_many_series_one_param_dev(
tm_prices, tm_vols,
length=13, vi_factor=0.67, strict=True, sample_period=0,
device_id=0,
) JavaScript/WASM Bindings
Basic Usage ▼
Compute in JS/TS using WASM exports:
import {
volume_adjusted_ma_js,
volume_adjusted_ma_unified_js,
} from 'vectorta-wasm';
const prices = new Float64Array([/* ... */]);
const volumes = new Float64Array([/* ... */]);
// Direct call with explicit params
const values = volume_adjusted_ma_js(prices, volumes, 13, 0.67, true, 0);
// Unified variant (optional parameters), returns {{ values }} object
const out = volume_adjusted_ma_unified_js(prices, volumes, 13, 0.67, true, 0);
const arr = (await out).values; Memory-Efficient Operations ▼
import { volume_adjusted_ma_alloc, volume_adjusted_ma_free, volume_adjusted_ma_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* ... */]);
const volumes = new Float64Array([/* ... */]);
const len = prices.length;
const pPtr = volume_adjusted_ma_alloc(len);
const vPtr = volume_adjusted_ma_alloc(len);
const oPtr = volume_adjusted_ma_alloc(len);
new Float64Array(memory.buffer, pPtr, len).set(prices);
new Float64Array(memory.buffer, vPtr, len).set(volumes);
// in_ptr_price, in_ptr_volume, out_ptr, len, length, vi_factor, strict, sample_period
await volume_adjusted_ma_into(pPtr, vPtr, oPtr, len, 13, 0.67, true, 0);
const out = new Float64Array(memory.buffer, oPtr, len).slice();
volume_adjusted_ma_free(pPtr, len);
volume_adjusted_ma_free(vPtr, len);
volume_adjusted_ma_free(oPtr, len); Batch Processing ▼
import { volume_adjusted_ma_batch } from 'vectorta-wasm';
const prices = new Float64Array([/* ... */]);
const volumes = new Float64Array([/* ... */]);
const cfg = {
length_range: [10, 30, 5],
vi_factor_range: [0.5, 0.8, 0.1],
sample_period_range: [0, 0, 0],
strict: true,
};
// Returns { values: Float64Array, combos: VolumeAdjustedMaParams[], rows, cols }
const res = volume_adjusted_ma_batch(prices, volumes, cfg); Performance Analysis
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05