Files
wickra/docs/wiki/indicators/trend-directional/Indicator-MassIndex.md
T
kingchenc d2f99efd78 F13c: restructure the indicator catalogue into eight families
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.
2026-05-22 21:21:56 +02:00

5.4 KiB
Raw Blame History

MassIndex

Mass Index — Donald Dorsey's range-expansion indicator: it watches the highlow range widen and contract to anticipate reversals.

Quick reference

Field Value
Family Trend & Directional
Input type Candle (uses high, low)
Output type f64
Output range > 0, oscillates around sum_period
Default parameters (ema_period = 9, sum_period = 25) (Python)
Warmup period 2·ema_period + sum_period 2
Interpretation A rise above 27 then fall below 26.5 flags a reversal.

Formula

range_t   = high_t  low_t
single_t  = EMA(range, ema_period)_t
double_t  = EMA(single, ema_period)_t
ratio_t   = single_t / double_t
MassIndex = Σ ratio over sum_period

The Mass Index ignores direction entirely — it tracks volatility shape. When the highlow range widens, the single EMA pulls ahead of the double EMA, the ratio climbs above 1, and the windowed sum rises. Dorsey's "reversal bulge" is the classic pattern: the Mass Index rising above 27 and then falling back below 26.5 warns that a range expansion is about to resolve — often into a trend reversal.

Parameters

Name Type Default Valid range Description
ema_period usize 9 (Python) >= 1 Period of both EMAs in the cascade. 0 errors with Error::PeriodZero.
sum_period usize 25 (Python) >= 1 Length of the summation window.

The Python binding defaults the pair to (9, 25). The periods property returns (ema_period, sum_period).

Inputs / Outputs

From crates/wickra-core/src/indicators/mass_index.rs:

impl Indicator for MassIndex {
    type Input = Candle;
    type Output = f64;
    // update(&mut self, input: Candle) -> Option<f64>
}

MassIndex is a candle-input indicator: it reads high and low. In Python the streaming update accepts a 6-tuple or a dict; the batch helper takes high and low numpy arrays. Node and WASM expose update(high, low) and batch(high, low).

Warmup

warmup_period() == 2·ema_period + sum_period 2. The first EMA seeds at input ema_period; the second EMA, stacked on it, seeds at 2·ema_period 1; the summation window then needs sum_period ratios. For the default (9, 25) that is 41 bars.

Edge cases

  • Constant range. When every bar has the same highlow range, both EMAs converge to the same value, every ratio is 1, and the Mass Index equals sum_period (constant_range_sums_to_sum_period pins this).
  • Zero-range market. A flat market (high == low) drives both EMAs to 0; the 0 / 0 is guarded with the neutral ratio 1, so the Mass Index again equals sum_period (zero_range_market_sums_to_sum_period pins this).
  • Candle validation. Candle::new rejects invalid bars upstream.
  • Reset. mi.reset() clears both EMAs, the window and the sum.

Examples

Rust

use wickra::{BatchExt, Candle, Indicator, MassIndex};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut mi = MassIndex::new(3, 4)?;
    // Constant high-low range of 2.0; the Mass Index settles at sum_period.
    let candles: Vec<Candle> = (0..40)
        .map(|i| {
            let mid = 100.0 + f64::from(i);
            Candle::new(mid, mid + 1.0, mid - 1.0, mid, 1.0, i64::from(i)).unwrap()
        })
        .collect();
    let out = mi.batch(&candles);
    println!("warmup_period = {}", mi.warmup_period());
    println!("last = {:?}", out.last().unwrap());
    Ok(())
}

Output:

warmup_period = 8
last = Some(4.0)

A constant range makes every ratio 1, so the sum equals sum_period (4). This matches the constant_range_sums_to_sum_period test in crates/wickra-core/src/indicators/mass_index.rs.

Python

import numpy as np
import wickra as ta

mi = ta.MassIndex()  # (ema_period=9, sum_period=25)
mid = np.arange(100.0, 160.0)
high = mid + 1.0
low = mid - 1.0
print(mi.batch(high, low)[-1])  # constant range -> 25

Output:

25.0

Node

const ta = require('wickra');
const mi = new ta.MassIndex(9, 25);
const mid = Array.from({ length: 60 }, (_, i) => 100 + i);
const high = mid.map((m) => m + 1);
const low = mid.map((m) => m - 1);
console.log(mi.batch(high, low).at(-1)); // 25

Interpretation

MassIndex is a reversal-warning tool, not a direction tool — it never tells you which way price will go, only that a turn is likely. The textbook use is the "reversal bulge" on the default (9, 25) settings: watch for the index to push above 27, then act when it drops back under 26.5, using a directional indicator (a moving average, ADX) to pick the side.

Common pitfalls

  • Expecting a direction. The Mass Index is direction-blind; always pair it with a trend indicator.
  • Feeding it scalar prices. It needs high/low; it takes a Candle, not an f64.

References

Donald Dorsey, "The Mass Index", Technical Analysis of Stocks & Commodities (1992). The double-EMA-of-range construction and the (9, 25) defaults follow Dorsey's original.

See also