The original taxonomy was four classical families plus a statistics group, with the F1-F12 expansion slotted in as sub-categories. This regroups the whole 71-indicator catalogue into eight top-level families, each with at least five members: Moving Averages (12), Momentum Oscillators (13), Trend & Directional (9), Price Oscillators (5), Volatility & Bands (12), Trailing Stops (5), Volume (9), Price Statistics (7). - Wiki: docs/wiki/indicators/ reorganised into eight family folders; all 71 indicator pages moved with `git mv`. Every internal cross-link is normalised to `../<family>/Indicator-X.md`, each page's `Family` field is set to its new family, and two pre-existing `../Indicator-Chaining.md` links (should have been `../../`) are corrected. A link check confirms every relative wiki link resolves. - Indicators-Overview.md fully rewritten around the eight families; Home.md indicator reference and the README family table follow suit. - Warmup-Periods.md gains the eight F13 indicators; CHANGELOG records the 46-indicator expansion (25 -> 71) and the eight-family taxonomy. - Tests: Node indicators.test.js and Python test_new_indicators.py cover all eight new indicators (Node 91/91, Python 117/117 green). cargo fmt + clippy (core/wickra/data/wasm/node) clean; 508 core tests, 25 data tests and 74 doctests green.
5.9 KiB
WMA
Weighted Moving Average with linear weights
1, 2, …, period, so the most recent bar carries the most weight.
Quick reference
| Field | Value |
|---|---|
| Family | Moving Averages |
| Input type | f64 (single close) |
| Output type | f64 |
| Output range | unbounded; tracks the input price scale |
| Default parameters | period is required (no default in either binding) |
| Warmup period | period |
| Interpretation | Front-weighted trend filter; faster than Sma, smoother than Ema. |
Formula
weights = [1, 2, ..., n] // n = period
W = n * (n + 1) / 2 // sum of weights
WMA_t = (1 / W) * Σ_{i=0}^{n-1} (n - i) * price_{t-i}
= (1 / W) * (n * price_t + (n-1) * price_{t-1} + ... + 1 * price_{t-n+1})
Maintained in O(1) using the identity that, when sliding the window by
one, every retained element's weight drops by exactly one and the
newcomer enters at weight n:
new_weight_sum = old_weight_sum - old_value_sum + n * new_input
new_value_sum = old_value_sum - oldest_value + new_input
This is the bookkeeping in the steady-state branch of update; during
warmup the full Σ weight·value is computed once when the window first
fills.
Parameters
| Name | Type | Default | Valid range | Description |
|---|---|---|---|---|
period |
usize |
none | >= 1 |
Length of the rolling window. period = 0 errors with Error::PeriodZero. period = 1 is a pass-through. |
(The Python class wickra.WMA(period) does not set a #[pyo3(signature)]
default; pass the period explicitly.)
Inputs / Outputs
From crates/wickra-core/src/indicators/wma.rs:
impl Indicator for Wma {
type Input = f64;
type Output = f64;
// update(&mut self, input: f64) -> Option<f64>
}
Python returns float | None from update and a numpy.ndarray
(float64, NaN for warmup) from batch. Node returns number | null
and Array<number> (with NaN placeholders) respectively.
Warmup
Wma::new(period).warmup_period() == period. Like Sma, the first
emission lands on the period-th update() call: the window needs
exactly period values for the weighted sum to be defined. There is no
seeding step beyond filling the window.
Edge cases
- Constant series. For
[c; n], every element contributesc · weight_iand the result isc · ΣW / ΣW = c. The proptestproptest_matches_naiveexercises this implicitly across many random inputs; the textbookperiod = 4test confirmsWMA(4)of[1, 2, 3, 4]is exactly(1·1 + 2·2 + 3·3 + 4·4) / 10 = 30 / 10 = 3.0. - NaN / infinity inputs. The first line of
updateisif !input.is_finite() { return self.value(); }. Non-finite inputs are silently dropped — they do not advance warmup, do not corrupt the rolling sums, and the previously emitted value (if any) is returned. - Reset.
wma.reset()clears the window and both rolling sums; the nextupdatestarts a new warmup countdown.
Examples
Rust
use wickra::{BatchExt, Indicator, Wma};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut wma = Wma::new(4)?;
let out: Vec<Option<f64>> = wma.batch(&[1.0, 2.0, 3.0, 4.0]);
println!("{:?}", out);
println!("warmup_period = {}", wma.warmup_period());
Ok(())
}
Output:
[None, None, None, Some(3.0)]
warmup_period = 4
The fourth input emits (1·1 + 2·2 + 3·3 + 4·4) / (1+2+3+4) = 30 / 10 = 3.0.
This matches the known_values_period_4 unit test in
crates/wickra-core/src/indicators/wma.rs.
Python
import numpy as np
import wickra as ta
wma = ta.WMA(4)
print(wma.batch(np.array([1.0, 2.0, 3.0, 4.0])))
print("warmup_period =", wma.warmup_period())
Output:
[nan nan nan 3.]
warmup_period = 4
Node
const ta = require('wickra');
const wma = new ta.WMA(4);
console.log(wma.batch([1, 2, 3, 4]));
console.log('warmupPeriod:', wma.warmupPeriod());
Output:
[ NaN, NaN, NaN, 3 ]
warmupPeriod: 4
Interpretation
Wma sits between Sma and Ema on the lag/responsiveness spectrum:
because the most recent bar carries weight n (vs 1 for the oldest),
direction changes propagate faster than in Sma, but the smooth linear
decay produces less of the "exponential tail" overshoot you sometimes
see with Ema. The same two crossover signals (price-vs-WMA and
fast-WMA-vs-slow-WMA) apply.
The most important downstream use of Wma inside Wickra is Hma:
Hma is built entirely from three Wma instances (see
Indicator-Hma.md).
Common pitfalls
- Mistaking linear weights for exponential ones. A
Wma(20)is not anEma(20); the weights decay linearly(20, 19, 18, …, 1)rather than geometrically, so very old bars still contribute (weight 1) where in an EMA they would have decayed to near zero. If you want the exponential decay, useEma. - Comparing
Wma(period)to a "WMA" from a different library and finding the seed off. Wickra'sWmahas no separate seeding step — it simply returnsNoneuntil the window is full and then returns the exact weighted mean from inputperiodonward. Some libraries pre-seed with a partial-window value; that is a different convention and will produce different first-few-bar values.
References
The linearly-weighted moving average is older than most named indicators
and has no single canonical citation; TA-Lib's WMA is the standard
reference implementation and matches Wickra's output bit-for-bit.
See also
- Indicator-Sma.md — equal weights instead of linear.
- Indicator-Ema.md — exponential decay instead of linear.
- Indicator-Hma.md — Hull MA, built from three WMAs.
- Indicators-Overview.md — the full taxonomy.