TradingView indicators

Chande Momentum Oscillator: formula and limits

The Chande Momentum Oscillator (CMO) compares the sum of upward price changes with the sum of downward changes over a rolling window. It divides their difference by their combined magnitude, then multiplies by 100. The result is bounded by −100 and +100 when the denominator is positive.

CMO = 100 × (U − D) / (U + D)

U and D are sums of consecutive price changes, not sums of prices. A flat window makes the denominator zero. Neither a high reading nor a threshold crossing establishes a reversal.

Inspect the Pine Script example

Calculate each change once

For every bar, subtract the preceding source value from the current value. Add positive differences to U and the magnitudes of negative differences to D over the last N changes. A length of 5 therefore needs 6 source observations. In Pine, ta.change(src) supplies the consecutive difference.

Do not sum src − src[i] for i = 1 through N: that compares every historical value with today and counts earlier movement multiple times. The correct historical difference is src[i] − src[i + 1], starting at i = 0, or a rolling sum of ta.change(src).

Bounds, flat windows and exact thresholds

Since U and D are nonnegative, |U − D| ≤ U + D. That proves the ±100 bound whenever U + D is positive. Gaps can change the sums, but cannot invalidate this inequality. Clamping a wrong result conceals the calculation error.

Formula boundary checks; no market assumptions
WindowConditionCMO
Only upward or flat changes; at least one riseU > 0, D = 0+100
Only downward or flat changes; at least one fallU = 0, D > 0−100
Equal nonzero upward and downward totalsU = D > 00
Every change is zeroU = D = 0Undefined; this code returns na
Upward total is three times downward totalU = 3D, D > 0+50 exactly
Downward total is three times upward totalD = 3U, U > 0−50 exactly

The usual overbought/oversold regions are above +50 and below −50. Equality is a boundary, not entry into either strict region. At +50, U is three times D; this is a ratio of movement amounts, not a count of rising bars or a probability of the next move. Strong trends can remain in an extreme region.

CMO vs RSI on the same price sequence

This hypothetical calculation starts at close 100 and uses length 5 for both indicators. The prices are invented to make every operation checkable; they are not a backtest.

Initial close: 100; each row adds one consecutive change
BarCloseChangeUp amountDown amount
1102+220
2101−101
3104+330
4104000
5102−202
6105+330

At bar 5, U = 2 + 3 = 5 and D = 1 + 2 = 3. CMO is 100 × (5 − 3) / 8 = 25. At bar 6, the first +2 leaves the five-change window and +3 enters: U = 6, D = 3, CMO = 33.3333.

A window-only RSI calculation would be 100 × U / (U + D). Algebra then gives CMO = 2 × window RSI − 100. Using averages instead of sums does not change that ratio if both averages use the same five observations. The distinction from TradingView RSI is its Wilder RMA smoothing, not simply sums versus averages.

Seed Wilder averages at bar 5 with gain 5/5 = 1 and loss 3/5 = 0.6. On bar 6, update each average as (previous × 4 + current) / 5: gain becomes 1.4 and loss 0.48. RSI is 100 × 1.4 / 1.88 = 74.4681.

Same length and prices; RSI explicitly seeded at bar 5
BarCMOWindow RSIWilder RSI2 × Wilder RSI − 100
525.000062.500062.500025.0000
633.333366.666774.468148.9362

The equal values at the seed do not make the methods equivalent. CMO drops the oldest change completely; Wilder RSI carries a decaying contribution from earlier changes. A chart with more preceding history can have a different RSI seed. This example establishes neither indicator as an earlier or better signal.

Pine Script v6: audit the CMO calculation

This indicator retains editable source and length inputs, plots CMO and its reference levels, and exposes both sums and a comparison with ta.cmo in the Data Window. The optional orange line rescales ta.rsi to the same axis; it does not turn RSI into CMO. Length 9 is an example input.

Pine Script v6
//@version=6
indicator("Chande Momentum Oscillator audit", shorttitle="CMO audit", overlay=false)

length = input.int(9, "Length", minval=2, maxval=500)
src = input.source(close, "Source")
showRsi = input.bool(false, "Show RSI rescaled to -100 / +100")

// Each change compares consecutive bars, not today's price with every past bar.
change = ta.change(src)
up = math.max(change, 0.0)
down = math.max(-change, 0.0)
upSum = math.sum(up, length)
downSum = math.sum(down, length)
validCount = math.sum(na(change) ? 0.0 : 1.0, length)
ready = validCount == length
movement = upSum + downSum
// Policy: missing inputs, warm-up and a flat window are undefined.
cmoValue = ready and movement > 0.0 ? 100.0 * (upSum - downSum) / movement : na
builtIn = ta.cmo(src, length)
rsiValue = ta.rsi(src, length)

plot(cmoValue, "Manual CMO", color=color.blue, linewidth=2, style=plot.style_linebr)
plot(showRsi ? 2.0 * rsiValue - 100.0 : na, "2 x Wilder RSI - 100", color=color.orange)
plot(builtIn, "Built-in CMO", display=display.data_window)
plot(cmoValue - builtIn, "Manual minus built-in", display=display.data_window)
plot(upSum, "Upward change sum", display=display.data_window)
plot(downSum, "Downward change sum", display=display.data_window)
hline(100, "+100", color=color.gray, linestyle=hline.style_dotted)
hline(50, "+50", color=color.gray, linestyle=hline.style_dashed)
hline(0, "Zero", color=color.gray)
hline(-50, "-50", color=color.gray, linestyle=hline.style_dashed)
hline(-100, "-100", color=color.gray, linestyle=hline.style_dotted)

crossUp = ta.crossover(cmoValue, 50.0)
crossDown = ta.crossunder(cmoValue, -50.0)
validPair = not na(cmoValue) and not na(cmoValue[1])
alertcondition(barstate.isconfirmed and validPair and crossUp, "CMO above +50 on close", "CMO crossed above +50 on a completed bar")
alertcondition(barstate.isconfirmed and validPair and crossDown, "CMO below -50 on close", "CMO crossed below -50 on a completed bar")

The manual series requires N valid consecutive changes and returns na for a zero denominator. Missing source values also invalidate the window. Compare the built-in only on populated, nonflat windows; do not assume matching missing-data policies. The difference should be zero within floating-point tolerance when both calculations use the same valid changes.

The +50 alert requires a current value strictly above +50 and a previous value at or below +50. The −50 alert uses a current value strictly below −50 and a previous value at or above −50. Both require valid current and previous values and barstate.isconfirmed. A move from 49 to 50 does not trigger; 50 to 51 does. Repeated bars above +50 do not repeat the crossing.

The plotted value still changes while a realtime bar is open. Create an alert from the desired condition and use Once Per Bar Close. The code requests no other timeframe and submits no orders. Syntax validation checks compilation; compare actual bar values before using the conditions in a strategy.

Settings and chart verification

  1. Match the inputs. Use the same symbol, source, length, timeframe, session and chart type. A close-based CMO and an HLC3-based CMO need not agree. Length counts bars, not calendar days.
  2. Check a completed bar. In TradingView, add the code through Pine Editor and inspect U, D, manual CMO and built-in CMO in the Data Window. Recalculate a small window from consecutive source values.
  3. Inspect boundary cases. Verify positive-only, negative-only, balanced and flat changes. Zero with movement means U = D; na on a flat window means the ratio has no defined value. Do not silently substitute one for the other.
  4. Change one setting at a time. A shorter length removes older changes sooner and gives a new change a larger share of the window. A longer length retains more history. Neither establishes a better trading outcome.
  5. Separate signals from execution. A zero crossing, threshold crossing or divergence needs its own rule. Pivot-based divergence also needs a stated confirmation delay. Define entries, exits, sizing, fees and slippage before testing any trading claim.

Educational calculation example, not investment advice or evidence of future returns.

Turn the calculation contract into a custom script

Pineify's Pine Script AI Coding Agent can help write or modify the indicator. Give it the source, lookback, flat-window policy and bar-close rule, then check the resulting values against the example before adding strategy orders.

Build a CMO indicator using consecutive close changes and a configurable length. Return na when a full valid window is unavailable or total movement is zero. Show upward and downward sums in the Data Window. Alert only on confirmed crosses above +50 or below −50 with valid values on both bars. Keep orders out until entry, exit and cost rules are specified.
Build a custom CMO script

Chande Momentum Oscillator FAQ

CMO = 100 × (U − D) / (U + D). U sums positive consecutive source changes over N bars; D sums the absolute values of negative changes over the same bars. Flat changes contribute zero. N changes require N + 1 source observations.

A correctly calculated CMO cannot exceed +100 or fall below −100 when its denominator is positive. Both sums are nonnegative, so the absolute difference cannot exceed their sum. A price gap does not break this bound; investigate the formula and input data before clamping unexpected values.

All changes in the window are zero, so the formula is 0/0 and undefined. The example returns na and suppresses crossing alerts until both the current and preceding CMO values exist. Returning zero would be a separate convention that also changes signal behavior.

Only if the RSI-style calculation uses the same unsmoothed window sums: CMO = 2 × window RSI − 100. TradingView RSI uses Wilder RMA averages, so that identity does not generally hold for ta.rsi. Use the same source and length before comparing their behavior.

There is no universal best length or threshold established here. The code starts at 9 bars as an editable example, not a recommended optimum or a universal platform default. Compare lengths with the same source, timeframe, session and confirmation rule; assess trading rules separately with exits and costs.

No. With a positive denominator, +50 means upward change totals are three times downward change totals. A value above +50 can persist during an advance. The example alert marks entry into that region; it is not an order or a tested reversal strategy.

Sources and related reading

Sources reviewed October 17, 2026. The calculation tables are hypothetical examples derived from the formulas.