Elastic Volume Weighted Moving Average
length = 30 | absolute_volume_millions = 134 | use_volume_sum = Overview
Elastic Volume Weighted Moving Average is a recursive smoother that treats volume as the mechanism that decides how much of the current bar should override the previous average. Each update blends the latest price with the prior EVWMA value, using current volume as the active weight. Heavy-volume bars therefore pull the line more aggressively toward price, while light-volume bars leave more inertia in the previous average.
This implementation supports two weighting regimes. The default path compares each bar against a fixed absolute volume base expressed in millions, which makes the indicator behave consistently across the whole run. The optional volume-sum mode instead uses the rolling sum of the last `length` volume values as the denominator, making the line adapt to local participation. Candle mode defaults to `hlcc4`, and the API always requires explicit volume data when you operate on slices.
Defaults: Elastic Volume Weighted Moving Average uses `length = 30`, `absolute_volume_millions = 134.0`, `use_volume_sum = false`, and defaults candle input to `hlcc4`.
Implementation Examples
Compute EVWMA from explicit price and volume slices or from candle data.
use vector_ta::indicators::moving_averages::elastic_volume_weighted_moving_average::{
elastic_volume_weighted_moving_average,
ElasticVolumeWeightedMovingAverageInput,
ElasticVolumeWeightedMovingAverageParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let prices = vec![100.0, 100.6, 101.4, 100.9, 101.8, 102.3];
let volumes = vec![1_200_000.0, 1_450_000.0, 1_380_000.0, 980_000.0, 1_620_000.0, 1_710_000.0];
let output = elastic_volume_weighted_moving_average(
&ElasticVolumeWeightedMovingAverageInput::from_slice(
&prices,
&volumes,
ElasticVolumeWeightedMovingAverageParams {
length: Some(30),
absolute_volume_millions: Some(134.0),
use_volume_sum: Some(false),
},
)
)?;
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = elastic_volume_weighted_moving_average(
&ElasticVolumeWeightedMovingAverageInput::with_default_candles(&candles)
)?;
println!("latest EVWMA = {:?}", output.values.last());
println!("series length = {}", candle_output.values.len()); API Reference
Input Methods ▼
// From candles and a named source field
ElasticVolumeWeightedMovingAverageInput::from_candles(
&Candles,
&str,
ElasticVolumeWeightedMovingAverageParams,
) -> ElasticVolumeWeightedMovingAverageInput
// From price and volume slices
ElasticVolumeWeightedMovingAverageInput::from_slice(
&[f64],
&[f64],
ElasticVolumeWeightedMovingAverageParams,
) -> ElasticVolumeWeightedMovingAverageInput
// From candles with default parameters
ElasticVolumeWeightedMovingAverageInput::with_default_candles(&Candles)
-> ElasticVolumeWeightedMovingAverageInput Parameters Structure ▼
pub struct ElasticVolumeWeightedMovingAverageParams {
pub length: Option<usize>, // default 30
pub absolute_volume_millions: Option<f64>, // default 134.0
pub use_volume_sum: Option<bool>, // default false
} Output Structure ▼
pub struct ElasticVolumeWeightedMovingAverageOutput {
pub values: Vec<f64>,
} Validation, Warmup & NaNs ▼
- Price and volume slices must both be non-empty and have identical lengths.
lengthmust be in1..=4096.- When
use_volume_sum = false,absolute_volume_millionsmust be finite and strictly positive. - The line is NaN-prefixed only until the first valid input index; once valid price and volume arrive, the recursive EVWMA starts emitting values immediately.
- Streaming returns
Nonefor non-finite price or volume inputs and resets internal continuity when that happens. - In volume-sum mode, the denominator is the rolling sum of the last
lengthvolume values; otherwise it is the fixed absolute volume base converted into shares. - Batch mode validates the length range and rejects unsupported kernels through
InvalidKernelForBatch.
Builder, Streaming & Batch APIs ▼
// Builder
ElasticVolumeWeightedMovingAverageBuilder::new()
.length(usize)
.absolute_volume_millions(f64)
.use_volume_sum(bool)
.kernel(Kernel)
.apply_slice(&[f64], &[f64])
ElasticVolumeWeightedMovingAverageBuilder::new()
.apply(&Candles)
ElasticVolumeWeightedMovingAverageBuilder::new()
.into_stream()
// Stream
ElasticVolumeWeightedMovingAverageStream::try_new(
ElasticVolumeWeightedMovingAverageParams
)
ElasticVolumeWeightedMovingAverageStream::update(f64, f64) -> Option<f64>
ElasticVolumeWeightedMovingAverageStream::reset()
// Batch
ElasticVolumeWeightedMovingAverageBatchBuilder::new()
.length_range(start, end, step)
.length_static(usize)
.absolute_volume_millions(f64)
.use_volume_sum(bool)
.kernel(Kernel)
.apply_slice(&[f64], &[f64]) Error Handling ▼
pub enum ElasticVolumeWeightedMovingAverageError {
EmptyInputData,
AllValuesNaN,
DataLengthMismatch { price_len: usize, volume_len: usize },
InvalidLength { length: usize },
InvalidAbsoluteVolumeMillions { absolute_volume_millions: f64 },
OutputLengthMismatch { expected: usize, got: usize },
InvalidLengthRange { start: usize, end: usize, step: usize },
InvalidKernelForBatch(Kernel),
} Python Bindings
Python exposes an array-returning single-run function, a streaming class, and a batch function. The single-run binding returns one NumPy array of EVWMA values. Batch returns the values matrix plus the tested length, absolute-volume, and volume-sum settings for each row.
import numpy as np
from vector_ta import (
elastic_volume_weighted_moving_average,
elastic_volume_weighted_moving_average_batch,
ElasticVolumeWeightedMovingAverageStream,
)
prices = np.asarray(close_values, dtype=np.float64)
volumes = np.asarray(volume_values, dtype=np.float64)
values = elastic_volume_weighted_moving_average(
prices,
volumes,
length=30,
absolute_volume_millions=134.0,
use_volume_sum=False,
kernel="auto",
)
stream = ElasticVolumeWeightedMovingAverageStream(
length=30,
absolute_volume_millions=134.0,
use_volume_sum=False,
)
print(stream.update(prices[-1], volumes[-1]))
batch = elastic_volume_weighted_moving_average_batch(
prices,
volumes,
length_range=(10, 30, 10),
absolute_volume_millions=134.0,
use_volume_sum=False,
kernel="auto",
)
print(batch["values"].shape)
print(batch["lengths"], batch["absolute_volume_millions"], batch["use_volume_sum"]) JavaScript/WASM Bindings
The WASM layer exposes a direct array-returning single-run wrapper, an object-returning batch wrapper, and lower-level allocation and in-place exports. The standard JavaScript path returns one EVWMA array, while batch returns flattened values, parameter combos, and the rows and cols shape.
import init, {
elastic_volume_weighted_moving_average_js,
elastic_volume_weighted_moving_average_batch_js,
} from "/pkg/vector_ta.js";
await init();
const prices = new Float64Array(closeValues);
const volumes = new Float64Array(volumeValues);
const values = elastic_volume_weighted_moving_average_js(
prices,
volumes,
30,
134.0,
false,
);
console.log(values);
const batch = elastic_volume_weighted_moving_average_batch_js(prices, volumes, {
length_range: [10, 30, 10],
absolute_volume_millions: 134.0,
use_volume_sum: false,
});
console.log(batch.values, batch.combos, batch.rows, batch.cols); CUDA Bindings (Rust)
Additional details for the CUDA bindings can be found inside the VectorTA repository.
Performance Analysis
Across sizes, Rust CPU runs about 1.14× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)
Related Indicators
Accumulation/Distribution
Technical analysis indicator
Accumulation/Distribution Oscillator
Technical analysis indicator
Balance of Power
Technical analysis indicator
Buff Averages
Technical analysis indicator
Chaikin Flow Oscillator
Technical analysis indicator
Elder Force Index
Technical analysis indicator