Williams Accumulation/Distribution (WAD)

Overview

Larry Williams developed the Accumulation/Distribution indicator in the 1970s to measure buying and selling pressure using pure price action without requiring volume data, making it universally applicable across all markets. The indicator accumulates values based on the relationship between consecutive closes and their true ranges, adding positive values when price closes higher than the previous bar and negative values when it closes lower. Williams specifically designed this indicator to identify divergences between price action and internal market strength, believing that distribution occurs when price makes new highs but the indicator fails to confirm them. His remarkable trading success, including turning $10,000 into over $1,100,000 in the 1987 World Cup Championship of Futures Trading, lent credibility to his technical analysis methods. Unlike the volume-based Chaikin Accumulation/Distribution, Williams' version focuses solely on price relationships, using true high and true low calculations that can reveal hidden weakness or strength when price extremes don't align with indicator extremes. Traders primarily watch for divergences where price makes new highs or lows that WAD fails to confirm, signaling potential reversals as smart money accumulates during apparent weakness or distributes during apparent strength.

Implementation Examples

Compute WAD from slices or candles:

use vectorta::indicators::wad::{wad, WadError, WadInput, WadParams};
use vectorta::utilities::data_loader::{Candles, read_candles_from_csv};

// From high/low/close slices
let high = vec![10.0, 11.0, 11.0, 12.0];
let low  = vec![ 9.0,  9.0, 10.0, 10.0];
let close= vec![ 9.5, 10.5, 10.5, 11.5];
let input = WadInput::from_slices(&high, &low, &close);
let out = wad(&input)?; // WadOutput { values: Vec<f64> }

// From candles (defaults to high/low/close sources)
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = WadInput::from_candles(&candles);
let out = wad(&input)?;

API Reference

Input Methods
// From candles (uses high/low/close)
WadInput::from_candles(&Candles) -> WadInput

// From explicit high/low/close slices
WadInput::from_slices(&[f64], &[f64], &[f64]) -> WadInput

// Convenience (same as from_candles)
WadInput::with_default_candles(&Candles) -> WadInput
Parameters Structure
pub struct WadParams; // No parameters
Output Structure
pub struct WadOutput {
    pub values: Vec<f64>, // cumulative WAD values
}
Validation, Warmup & NaNs
  • Inputs must be non-empty and equal length; otherwise WadError::EmptyData.
  • If all values in any of the three inputs are NaNWadError::AllValuesNaN.
  • Warmup: values[0] = 0.0; accumulation starts at index 1 using the previous close.
  • Kernel: wad(...) uses Kernel::Auto; builders allow Kernel::Scalar, Avx2, Avx512 (if compiled).
  • Streaming: WadStream::update(h,l,c) returns the cumulative value each tick; first update returns 0.0.
Error Handling
use vectorta::indicators::wad::{wad, WadError, WadInput};

match wad(&input) {
    Ok(output) => process_results(output.values),
    Err(WadError::EmptyData) => eprintln!("wad: empty or mismatched input"),
    Err(WadError::AllValuesNaN) => eprintln!("wad: all inputs are NaN"),
    Err(WadError::InvalidKernel) => eprintln!("wad: invalid batch kernel for batch API"),
}

Python Bindings

Basic Usage
import numpy as np
from vectorta import wad

high = np.array([10.0, 11.0, 11.0, 12.0], dtype=float)
low  = np.array([ 9.0,  9.0, 10.0, 10.0], dtype=float)
close= np.array([ 9.5, 10.5, 10.5, 11.5], dtype=float)

# One-shot calculation (kernel optional: 'auto', 'scalar', 'avx2', 'avx512' if available)
values = wad(high, low, close, kernel='auto')
print(values)
Streaming
import numpy as np
from vectorta import WadStream

stream = WadStream()
for h, l, c in zip(high, low, close):
    val = stream.update(h, l, c)
    handle(val)
Batch
import numpy as np
from vectorta import wad_batch

res = wad_batch(high, low, close, kernel='auto')
# res is a dict with 'values' shaped [1, len]
values = res['values'][0]  # first/only row
print(values)
CUDA Acceleration

If built with CUDA support, a device API is available:

import numpy as np
from vectorta import wad_cuda_dev

# Float32 inputs recommended for device APIs
high32 = high.astype(np.float32)
low32  = low.astype(np.float32)
close32= close.astype(np.float32)

dev_arr = wad_cuda_dev(high32, low32, close32, device_id=0)
# dev_arr is a device-backed array wrapper; transfer or use per your pipeline

JavaScript/WASM Bindings

Basic Usage

Compute WAD in JavaScript/TypeScript:

import { wad_js } from 'vectorta-wasm';

const high = new Float64Array([/* ... */]);
const low  = new Float64Array([/* ... */]);
const close= new Float64Array([/* ... */]);

const values = wad_js(high, low, close);
console.log('WAD:', values);
Memory-Efficient Operations

Use zero-copy into/alloc for large datasets:

import { wad_alloc, wad_free, wad_into, memory } from 'vectorta-wasm';

const len = close.length;
const highPtr = wad_alloc(len);
const lowPtr  = wad_alloc(len);
const closePtr= wad_alloc(len);
const outPtr  = wad_alloc(len);

new Float64Array(memory.buffer, highPtr, len).set(high);
new Float64Array(memory.buffer, lowPtr,  len).set(low);
new Float64Array(memory.buffer, closePtr,len).set(close);

// Args: high_ptr, low_ptr, close_ptr, out_ptr, len
wad_into(highPtr, lowPtr, closePtr, outPtr, len);

const values = new Float64Array(memory.buffer, outPtr, len).slice();

wad_free(highPtr, len); wad_free(lowPtr, len);
wad_free(closePtr, len); wad_free(outPtr, len);
Batch Processing

Unified batch API (returns a flat array and matrix dims):

import { wad_batch_unified_js } from 'vectorta-wasm';

// Unified batch call (no parameters for WAD)
const res = wad_batch_unified_js(high, low, close, {});
// res: { values: number[], rows: number, cols: number }

// For WAD, rows = 1; reshape as needed
const matrix = [] as number[][];
for (let r = 0; r < res.rows; r++) {
  const start = r * res.cols;
  matrix.push(res.values.slice(start, start + res.cols));
}
console.log('WAD row:', matrix[0]);

Performance Analysis

Comparison:
View:

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

Loading chart...

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

CUDA note

In our benchmark workload, the Rust CPU implementation is faster than CUDA for this indicator. Prefer the Rust/CPU path unless your workload differs.

Related Indicators