Wilder's Moving Average (Wilders)

Parameters: 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 > 0 and period ≤ len(data) or WildersError::InvalidPeriod.
  • Requires at least period valid points after the first finite value; else WildersError::NotEnoughValidData.
  • Empty slice: WildersError::EmptyInputData; all-NaN input: WildersError::AllValuesNaN.
  • Initial window must be finite; otherwise WildersError::NotEnoughValidData reports how many were valid.
  • Warmup prefix length is first + period − 1, filled with NaN. First finite output equals SMAN.
  • 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

Comparison:
View:

Across sizes, Rust CPU runs about 1.15× faster than Tulip C in this benchmark.

Loading chart...

AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU) | Benchmarks: 2026-01-05

Related Indicators