Skip to content
Open RaamTrade

MassIndex — Mass Index

A bulge in the ratio of single- to double-smoothed range, summed over 25 bars. Dorsey’s “reversal bulge”: the index rising above 27 and then falling back below 26.5 marks range expansion that often precedes a turn — in either direction, since it is direction-blind.

Signature

MassIndex(ema_period, sum_period, on=<source>)
Argument Type Required Notes
ema_period int Param or literal Yes Smoothing for both EMAs. Default 9, bounds 1–100.
sum_period int Param or literal Yes Summation window. Default 25, bounds 1–200.
on= symbol No Source symbol. Defaults to the trade symbol. Reads high and low.

Formula

$$ \text{MassIndex} = \sum_{i=1}^{m} \frac{\text{EMA}(H-L, n)}{\text{EMA}(\text{EMA}(H-L, n), n)} $$

Warmup

sum_period bars plus the EMA convergence. With the defaults the value sits near 25 (the sum of 25 ratios all near 1).

Reading the value

mi.value
mi > 27

Example

class ReversalBulge(Strategy):
"""Dorsey's bulge: exit when the mass index spikes and falls back."""
trade = Symbol()
sizing = FixedCapital()
def execute(self):
mi = MassIndex(9, 25, on=self.trade)
sma = SMA(50, on=self.trade)
if self.trade.close > sma.value and mi.value < 26 and self.trade.is_flat:
self.buy(self.trade, reason="Trend, no bulge")
if mi.value > 27 and self.trade.is_long:
self.sell(self.trade, self.trade.position, reason=f"Mass index {mi.value:.1f}")

Notes

  • Donald Dorsey, TASC (1992). The 27 / 26.5 thresholds are his and assume the 9/25 defaults — they do not transfer if you change the periods.
  • Proven by an assert-via-trade run on SPY daily (stayed in its expected band on every bar of a 140-bar run; zero alarm trades).
  • The recursion seeds from the first bar rather than from a warm-up window, so early values are not comparable with pandas_ta’s massi(9, 25), which seeds from an average of the first n; measured on a 300-bar tape the two agree to 1e-6 from bar 80 onward.