Skip to content
Open RaamTrade

CMO — Chande Momentum Oscillator

Unsmoothed gains minus losses over the window, scaled −100 to +100. RSI’s sharper, noisier cousin: the same ingredients with no Wilder smoothing, so it reacts a bar earlier and whipsaws more.

Signature

CMO(period, on=<source>)
Argument Type Required Notes
period int Param or literal Yes Lookback. Default 14, bounds 1–400.
on= symbol, OHLCV field, or indicator No Source. Defaults to the trade symbol’s close.

Formula

$$ \text{CMO} = 100,\frac{\sum \text{gains} - \sum \text{losses}}{\sum \text{gains} + \sum \text{losses}} $$

over the last period one-bar changes.

Warmup

period + 1 bars (one to establish the previous close, period changes); 0 until then, and 0 on a completely flat window.

Reading the value

cmo.value
cmo < -50
cmo.crossed_above(0)

Example

class CmoReversion(Strategy):
"""Fade a CMO extreme."""
period = Param(14, min=1, max=400)
trade = Symbol()
sizing = FixedCapital()
def execute(self):
cmo = CMO(self.period, on=self.trade)
if cmo.value < -50 and self.trade.is_flat:
self.buy(self.trade, reason=f"CMO {cmo.value:.0f}")
if cmo.value > 0 and self.trade.is_long:
self.sell(self.trade, self.trade.position, reason="CMO recovered")

Notes

  • Tushar Chande, The New Technical Trader (1994).
  • Proven by an assert-via-trade run on SPY daily (matched a strategy-side gain/loss reference to 0.01 on every bar; zero alarm trades).
  • ±50 here corresponds roughly to RSI 70/30. VIDYA uses |CMO|/100 as its speed control.
  • This is the plain N-bar sum of gains and losses; TA-Lib’s CMO Wilder-smooths them first (RSI’s smoothing), so the two never converge — a measured median ratio of 1.54 on a 300-bar tape.