Cubic Weighted Moving Average (CWMA)
period = 14 Overview
The Cubic Weighted Moving Average (CWMA) applies cubic weighting to price data, creating a moving average that responds more aggressively to recent price changes than linear or squared weighted averages. The indicator assigns weights based on the cube of each data point's position in the window. The most recent price receives a weight of n cubed, while the oldest receives a weight of 1 cubed, with intermediate values following the cubic progression. This cubic relationship creates a steep weighting curve that heavily favors recent prices while still considering the full lookback period for smoothness.
CWMA strikes a balance between responsiveness and stability by using polynomial weighting rather than exponential decay. The cubic function provides stronger emphasis on recent data than WMA's linear weights or even quadratic weighting schemes. This makes CWMA particularly effective at tracking price movements during trend accelerations while maintaining enough historical context to avoid excessive whipsaws. The steeper weight distribution means CWMA turns faster than traditional weighted averages when trends change direction. However, it remains smoother than extremely responsive averages like Hull or Zero Lag variations.
Traders use CWMA as a trend following tool that adapts quickly to momentum shifts without sacrificing too much stability. The indicator works well for identifying dynamic support and resistance levels in trending markets where its responsiveness helps it stay close to price action. CWMA crossovers with price or other moving averages generate trading signals similar to other MA systems, but with potentially earlier entries due to the cubic weighting. Many traders combine CWMA with slower moving averages to create crossover systems that balance speed and reliability. The indicator also serves as a baseline for other calculations, providing a responsive yet stable price proxy for momentum oscillators or volatility bands.
Implementation Examples
Compute CWMA from slices or candles:
use vectorta::indicators::cwma::{cwma, CwmaInput, CwmaParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// Using with a price slice
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let params = CwmaParams { period: Some(14) }; // Default 14 if None
let input = CwmaInput::from_slice(&prices, params);
let result = cwma(&input)?;
// Using with Candles (defaults: period=14, source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = CwmaInput::with_default_candles(&candles);
let result = cwma(&input)?;
// Access values
for v in result.values { println!("CWMA: {}", v); } API Reference
Input Methods ▼
// From price slice
CwmaInput::from_slice(&[f64], CwmaParams) -> CwmaInput
// From candles with custom source
CwmaInput::from_candles(&Candles, &str, CwmaParams) -> CwmaInput
// From candles with default params (close, period=14)
CwmaInput::with_default_candles(&Candles) -> CwmaInput Parameters Structure ▼
pub struct CwmaParams {
pub period: Option<usize>, // Default: 14
} Output Structure ▼
pub struct CwmaOutput {
pub values: Vec<f64>, // CWMA values
} Validation, Warmup & NaNs ▼
period ≥ 2;period ≤ len(data)orCwmaError::InvalidPeriod.- Finds the first finite input; requires at least
periodvalid values after it, otherwiseCwmaError::NotEnoughValidData. - All-NaN input yields
CwmaError::AllValuesNaN. Empty input yieldsCwmaError::EmptyInputData. - Warmup: outputs are
NaNthrough indexfirst_non_nan + period - 2. First valid value appears atfirst_non_nan + period - 1. - Streaming:
updatereturnsNoneduring warmup, thenSome(value); returnsSome(NaN)if anyNaNis inside the active window.
Error Handling ▼
use vectorta::indicators::cwma::{cwma, CwmaError};
match cwma(&input) {
Ok(output) => process(output.values),
Err(CwmaError::EmptyInputData) => eprintln!("no data"),
Err(CwmaError::AllValuesNaN) => eprintln!("all values are NaN"),
Err(CwmaError::InvalidPeriod { period, data_len }) => {
eprintln!("invalid period {} for data length {}", period, data_len)
}
Err(CwmaError::NotEnoughValidData { needed, valid }) => {
eprintln!("need {} valid points, found {}", needed, valid)
}
} Python Bindings
Basic Usage ▼
Calculate CWMA using NumPy arrays (default period=14; optional kernel selection):
import numpy as np
from vectorta import cwma
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5], dtype=float)
# Defaults (period=14)
vals = cwma(prices, period=14)
# Specify kernel ("auto", "scalar", "avx2", "avx512")
vals = cwma(prices, period=14, kernel="auto")
print(vals) Streaming Real-time Updates ▼
from vectorta import CwmaStream
stream = CwmaStream(period=14)
for price in price_feed:
value = stream.update(price)
if value is not None:
handle(value) Batch Parameter Optimization ▼
import numpy as np
from vectorta import cwma_batch
prices = np.array([...], dtype=float)
results = cwma_batch(prices, period_range=(5, 30, 5), kernel="auto")
print(results["values"].shape) # (num_periods, len(prices))
print(results["periods"]) CUDA Acceleration ▼
CUDA-backed CWMA APIs are available when built with CUDA support.
# from vectorta import cwma_cuda_batch_dev, cwma_cuda_many_series_one_param_dev
# prices_f32 = np.array([...], dtype=np.float32)
# out = cwma_cuda_batch_dev(prices_f32, period_range=(5, 30, 1), device_id=0)
# grid = cwma_cuda_many_series_one_param_dev(data_tm_f32=tm_prices, period=14, device_id=0) JavaScript/WASM Bindings
Basic Usage ▼
Calculate CWMA in JavaScript/TypeScript:
import { cwma_js } from 'vectorta-wasm';
const prices = new Float64Array([100.0, 102.0, 101.5, 103.0, 105.0, 104.5]);
const result = cwma_js(prices, 14); // period=14
console.log('CWMA values:', result); Memory-Efficient Operations ▼
Use zero-copy operations for large arrays:
import { cwma_alloc, cwma_free, cwma_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* data */]);
const len = prices.length;
const inPtr = cwma_alloc(len);
const outPtr = cwma_alloc(len);
new Float64Array(memory.buffer, inPtr, len).set(prices);
cwma_into(inPtr, outPtr, len, 14);
const values = new Float64Array(memory.buffer, outPtr, len).slice();
cwma_free(inPtr, len);
cwma_free(outPtr, len); Batch Processing ▼
Test many periods across one series:
import { cwma_batch_js, cwma_batch_metadata_js } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
const meta = cwma_batch_metadata_js(5, 30, 5); // [period1, period2, ...]
const numCombos = meta.length;
const flat = cwma_batch_js(prices, 5, 30, 5);
const rows = numCombos, cols = prices.length;
const matrix: Float64Array[] = [];
for (let i = 0; i < rows; i++) {
const start = i * cols;
matrix.push(flat.slice(start, start + cols));
} Performance Analysis
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
Double Exponential Moving Average
Moving average indicator
Ehlers Distance Coefficient Filter
Moving average indicator
Ehlers Error-Correcting EMA (ECEMA)
Moving average indicator
Ehlers Instantaneous Trendline
Moving average indicator