Wilder's Moving Average (Wilders)
period = 5 Overview
J. Welles Wilder Jr. introduced his smoothing method in 1978 through his groundbreaking book "New Concepts in Technical Trading Systems," which also unveiled RSI, ATR, ADX, and Parabolic SAR to the trading world. Wilder developed his averaging technique before computers were prevalent in trading, designing it to be calculated efficiently by hand while still providing responsive yet stable trend smoothing. The method uses a smoothing factor of 1/N rather than the 2/(N+1) used by standard EMAs, making it respond more gradually to price changes and effectively requiring about twice the period length to achieve similar responsiveness. This deliberate design choice reduces whipsaws and false signals, particularly valuable when Wilder applied it as the foundation for RSI and ATR calculations where stability matters more than speed. The smoothing initializes with a simple average over the first N values, then updates recursively by adding 1/N of the difference between the new price and previous average, creating a balance between recent price emphasis and historical context. Nearly five decades later, Wilder's smoothing remains essential in technical analysis, proving that his pre-computer era mathematical insights captured something fundamental about how markets trend and reverse, with his original formulations still powering some of the most trusted indicators in modern trading systems.
Implementation Examples
Compute Wilders from slices or candles:
use vectorta::indicators::moving_averages::wilders::{wilders, WildersInput, WildersParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};
// From a price slice
let prices = vec![100.0, 102.0, 101.5, 103.0, 105.0, 104.5];
let params = WildersParams { period: Some(5) };
let input = WildersInput::from_slice(&prices, params);
let out = wilders(&input)?;
// From candles (defaults: period=5, source="close")
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = WildersInput::with_default_candles(&candles);
let out = wilders(&input)?;
for v in out.values { println!("Wilders: {}", v); } API Reference
Input Methods ▼
// From price slice
WildersInput::from_slice(&[f64], WildersParams) -> WildersInput
// From candles with custom source
WildersInput::from_candles(&Candles, &str, WildersParams) -> WildersInput
// From candles with default params (close, period=5)
WildersInput::with_default_candles(&Candles) -> WildersInput Parameters Structure ▼
pub struct WildersParams {
pub period: Option<usize>, // Default: 5
} Output Structure ▼
pub struct WildersOutput {
pub values: Vec<f64>, // Wilder's MA values
} Validation, Warmup & NaNs ▼
period > 0andperiod ≤ len(data)orWildersError::InvalidPeriod.- Requires at least
periodvalid points after the first finite value; elseWildersError::NotEnoughValidData. - Empty slice:
WildersError::EmptyInputData; all-NaN input:WildersError::AllValuesNaN. - Initial window must be finite; otherwise
WildersError::NotEnoughValidDatareports how many were valid. - Warmup prefix length is
first + period − 1, filled withNaN. First finite output equalsSMAN. - For
period=1, values equal the input from the warmup index onward (identity).
Error Handling ▼
use vectorta::indicators::moving_averages::wilders::{wilders, WildersError, WildersInput, WildersParams};
let input = WildersInput::from_slice(&prices, WildersParams { period: Some(5) });
match wilders(&input) {
Ok(output) => process(output.values),
Err(WildersError::EmptyInputData) => eprintln!("Input data is empty"),
Err(WildersError::AllValuesNaN) => eprintln!("All values are NaN"),
Err(WildersError::InvalidPeriod { period, data_len }) =>
eprintln!("Invalid period {} for data length {}", period, data_len),
Err(WildersError::NotEnoughValidData { needed, valid }) =>
eprintln!("Need {} valid points after first finite; have {}", needed, valid),
Err(WildersError::OutputLengthMismatch { .. }) => eprintln!("Output length mismatch"),
Err(WildersError::InvalidKernelType { kernel }) => eprintln!("Invalid batch kernel: {}", kernel),
} Python Bindings
Basic Usage ▼
Compute Wilder's MA with NumPy arrays:
import numpy as np
from vectorta import wilders
prices = np.array([100.0, 102.0, 101.5, 103.0, 105.0], dtype=np.float64)
# period (>=1), optional kernel: 'auto' | 'scalar' | 'avx2' | 'avx512'
values = wilders(prices, 5, kernel='auto')
print(values.shape) Streaming Real-time Updates ▼
Process real-time Wilder values:
from vectorta import WildersStream
stream = WildersStream(period=14)
for price in price_feed:
val = stream.update(price)
if val is not None:
handle(val) Batch Parameter Optimization ▼
Test multiple period values and get structured outputs:
import numpy as np
from vectorta import wilders_batch
prices = np.array([...], dtype=np.float64)
results = wilders_batch(
prices,
period_range=(5, 30, 5),
kernel='auto'
)
# results is a dict with 2D array and metadata
print(results['values'].shape) # (num_combinations, len(prices))
print(results['periods']) # np.array of periods tested CUDA Acceleration ▼
CUDA-backed Wilders APIs are available when built with Python+CUDA features.
from vectorta import wilders_cuda_batch_dev
import numpy as np
# One series, many period values (parameter sweep on device)
prices_f32 = np.array([...], dtype=np.float32)
dev_out = wilders_cuda_batch_dev(prices_f32, period_range=(5, 30, 1), device_id=0)
# dev_out is a device array wrapper; consult your environment for how to pull back to host. JavaScript/WASM Bindings
Basic Usage ▼
Calculate Wilder's MA in JavaScript/TypeScript:
import { wilders_js } from 'vectorta-wasm';
const prices = new Float64Array([100, 102, 101.5, 103, 105]);
const period = 5;
const values = wilders_js(prices, period);
console.log('Wilders values:', values); Memory-Efficient Operations ▼
Use zero-copy operations for large arrays:
import { wilders_alloc, wilders_free, wilders_into, memory } from 'vectorta-wasm';
const prices = new Float64Array([/* data */]);
const len = prices.length;
const inPtr = wilders_alloc(len);
const outPtr = wilders_alloc(len);
new Float64Array(memory.buffer, inPtr, len).set(prices);
wilders_into(inPtr, outPtr, len, 5);
const values = new Float64Array(memory.buffer, outPtr, len).slice();
wilders_free(inPtr, len);
wilders_free(outPtr, len); Batch Processing ▼
Test multiple period values using the unified API:
import { wilders_batch } from 'vectorta-wasm';
const prices = new Float64Array([/* historical prices */]);
// Unified batch API with config
const out = wilders_batch(prices, { period_range: [5, 30, 5] });
// out: { values: Float64Array, combos: { period?: number }[], rows: number, cols: number }
console.log(out.rows, out.cols);
// Deprecated legacy variant also exists: wilders_batch_js(prices, start, end, step)
// which returns a flat Float64Array of length rows * cols. Performance Analysis
Across sizes, Rust CPU runs about 1.15× faster 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