Volume Weighted Moving Average (VWMA)
period = 20 Overview
The Volume Weighted Moving Average (VWMA) incorporates trading volume into moving average calculations by weighting each price point by its session volume across the lookback window. Unlike traditional moving averages that treat all periods equally, VWMA multiplies each price by its volume, sums these products, then divides by total volume over the period. This volume weighting ensures that prices accompanied by heavy trading activity exert greater influence on the average than those occurring during quiet periods. The resulting line tracks not just price movement but also the conviction behind that movement as measured by participation levels. When VWMA diverges significantly from simple or exponential moving averages, it reveals that volume distribution differs from price distribution, potentially signaling accumulation or distribution phases. Traders use VWMA crossovers and price interactions similarly to other moving averages but with added confidence from volume confirmation. The default 20-period setting aligns with standard moving average analysis while allowing the volume weighting to highlight institutional activity and meaningful price levels supported by actual trading interest.
Defaults: period = 20.
Implementation Examples
Compute VWMA from slices or Candles:
use vectorta::indicators::vwma::{vwma, VwmaInput, VwmaParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using price and volume data slices
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let volumes = vec![1200.0, 1600.0, 900.0, 2000.0, 1800.0, 1500.0];
let params = VwmaParams { period: Some(20) };
let input = VwmaInput::from_slice(&prices, &volumes, params);
let result = vwma(&input)?;
// Using Candles with default params (source="close", period=20)
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = VwmaInput::with_default_candles(&candles);
let result = vwma(&input)?;
// Access the VWMA values
for value in result.values {
println!("VWMA: {}", value);
} API Reference
Input Methods ▼
// From price and volume slices
VwmaInput::from_slice(&[f64], &[f64], VwmaParams) -> VwmaInput
// From candles with custom source for prices (volume is taken from candles)
VwmaInput::from_candles(&Candles, &str, VwmaParams) -> VwmaInput
// From candles plus an explicit price slice (volume from candles)
VwmaInput::from_candles_plus_prices(&Candles, &[f64], VwmaParams) -> VwmaInput
// From candles with defaults (source="close", period=20)
VwmaInput::with_default_candles(&Candles) -> VwmaInput Parameters Structure ▼
pub struct VwmaParams {
pub period: Option<usize>, // Default: 20
} Output Structure ▼
pub struct VwmaOutput {
pub values: Vec<f64>, // VWMA values
} Validation, Warmup & NaNs ▼
period > 0andperiod ≤ data_len; otherwiseVwmaError::InvalidPeriod.- Price and volume lengths must match; otherwise
VwmaError::PriceVolumeMismatch. - Searches for the first index where both price and volume are finite; if none,
VwmaError::AllValuesNaN. - There must be at least
periodvalid pairs from the first finite pair; otherwiseVwmaError::NotEnoughValidData. - Warmup: indices before
first + period − 1areNaN. Streaming returnsNoneuntil the window fills.
Error Handling ▼
use vectorta::indicators::vwma::{vwma, VwmaError};
match vwma(&input) {
Ok(output) => process_results(output.values),
Err(VwmaError::InvalidPeriod { period, data_len }) =>
eprintln!("Invalid period {} for data length {}", period, data_len),
Err(VwmaError::PriceVolumeMismatch { price_len, volume_len }) =>
eprintln!("Mismatched lengths: prices={}, volumes={}", price_len, volume_len),
Err(VwmaError::AllValuesNaN) =>
eprintln!("All price-volume pairs are NaN"),
Err(VwmaError::NotEnoughValidData { needed, valid }) =>
eprintln!("Need {} valid pairs, only {} available", needed, valid),
} Python Bindings
Basic Usage ▼
Compute VWMA from NumPy arrays of prices and volumes:
import numpy as np
from vectorta import vwma
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5], dtype=np.float64)
volumes = np.array([1200.0, 1600.0, 900.0, 2000.0, 1800.0, 1500.0], dtype=np.float64)
# period is required; kernel is optional: 'auto' | 'scalar' | 'avx2' | 'avx512'
values = vwma(prices, volumes, period=20, kernel="auto")
print(values) Streaming ▼
Incremental updates with (price, volume) tuples:
from vectorta import VwmaStream
stream = VwmaStream(period=20)
for (price, volume) in data_stream:
vw = stream.update(price, volume)
if vw is not None:
print("VWMA:", vw) Batch Parameter Optimization ▼
Sweep multiple periods in one pass:
import numpy as np
from vectorta import vwma_batch
prices = np.asarray([...], dtype=np.float64)
volumes = np.asarray([...], dtype=np.float64)
# (start, end, step)
result = vwma_batch(prices, volumes, period_range=(10, 30, 5), kernel="auto")
print(result['values'].shape) # (num_periods, len(prices))
print(result['periods']) # list of tested periods CUDA Acceleration ▼
CUDA APIs are available behind optional features:
# Requires build with CUDA + Python features enabled
from vectorta import vwma_cuda_batch_dev, vwma_cuda_many_series_one_param_dev
import numpy as np
# 1) One series, many periods (device output wrapper)
prices_f32 = np.asarray([...], dtype=np.float32)
vols_f32 = np.asarray([...], dtype=np.float32)
dev = vwma_cuda_batch_dev(prices_f32, vols_f32, period_range=(10, 30, 1), device_id=0)
# 2) Many series (time-major), one period
data_tm_f32 = np.asarray([...], dtype=np.float32) # shape [T, N]
vol_tm_f32 = np.asarray([...], dtype=np.float32) # shape [T, N]
dev2 = vwma_cuda_many_series_one_param_dev(data_tm_f32, vol_tm_f32, period=20, device_id=0) JavaScript/WASM Bindings
Basic Usage ▼
Calculate VWMA in JavaScript/TypeScript:
import { vwma_js } from 'vectorta-wasm';
const prices = new Float64Array([100, 102, 101.5, 103, 105, 104.5]);
const volumes = new Float64Array([1200, 1600, 900, 2000, 1800, 1500]);
// period = 20 by convention
const values = vwma_js(prices, volumes, 20);
console.log('VWMA values:', values); Memory-Efficient Operations ▼
Use zero-copy buffers with alloc/into:
import { vwma_alloc, vwma_free, vwma_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* your data */]);
const volumes = new Float64Array([/* your data */]);
const len = prices.length;
const pPtr = vwma_alloc(len);
const vPtr = vwma_alloc(len);
const outPtr = vwma_alloc(len);
// Copy inputs into WASM memory
new Float64Array(memory.buffer, pPtr, len).set(prices);
new Float64Array(memory.buffer, vPtr, len).set(volumes);
// Compute into pre-allocated buffer
vwma_into(pPtr, vPtr, outPtr, len, 20);
// Read results
const out = new Float64Array(memory.buffer, outPtr, len).slice();
// Free buffers
vwma_free(pPtr, len);
vwma_free(vPtr, len);
vwma_free(outPtr, len);
console.log('VWMA values:', out); Batch Processing ▼
Sweep period values and reshape results:
import { vwma_batch_js, vwma_batch_metadata_js } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
const volumes = new Float64Array([/* historical volumes */]);
const start = 10, end = 30, step = 5; // 10, 15, 20, 25, 30
// Metadata returns tested periods
const periods = vwma_batch_metadata_js(start, end, step);
const numCombos = periods.length;
// Flat matrix: [row1..., row2..., ...]
const flat = vwma_batch_js(prices, volumes, start, end, step);
// Reshape into rows
const rows = [] as Float64Array[];
for (let i = 0; i < numCombos; i++) {
const s = i * prices.length;
rows.push(flat.slice(s, s + prices.length));
}
console.log('Periods:', periods);
console.log('VWMA[period=20] row:', rows[periods.indexOf(20)]); Performance Analysis
Across sizes, Rust CPU runs about 1.02× slower than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05
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