Momentum in Python — Coding It from Scratch (pandas)

The difference form, the ratio form, and a smoothed signal

Momentum computed in Python
Momentum computed in Python

Momentum is the shortest possible indicator: subtract a past price from the present one. The explainer covers the concept; here it is in pandas, both the difference and ratio forms.

What you’ll need

  • Python 3.9+, pandas
  • A close series.

The difference form (classic)

def momentum(close, period: int = 10):
    return close - close.shift(period)

Positive above zero, negative below — the oscillator from the output chart. That’s genuinely the whole thing.

The ratio form (100-centered)

Some platforms (MetaTrader among them) use the ratio version, which oscillates around 100:

def momentum_ratio(close, period: int = 10):
    return 100 * close / close.shift(period)

Above 100 = price higher than N bars ago; below 100 = lower. Same information, shifted scale — know which one your platform draws before comparing.

Momentum vs ROC

They differ by one operation — Momentum is absolute, ROC is percentage:

mom = close - close.shift(10)                 # points
roc = 100 * (close - close.shift(10)) / close.shift(10)   # percent

Use ROC when comparing across instruments; use Momentum when raw point-change on one instrument is what you want.

Smoothing and signals

mom = momentum(df["close"], 10)
mom_smooth = mom.rolling(3).mean()            # calm the noise
above = mom > 0
df["mom_bull"] = above & ~above.shift(1, fill_value=False)   # crossed above zero

mom_bull is a clean zero-cross signal to backtest in AlgoGen, ideally behind a trend filter since Momentum has no fixed levels.

Gotchas

  • Absolute, not percentage. Momentum’s raw points aren’t comparable across markets — reach for ROC if you need comparability.
  • Difference vs ratio. Around zero (difference) or around 100 (ratio). Don’t mix them up when reading signals.
  • No fixed levels; noisy. Judge extremes relative to recent range, and smooth if the raw line is too jumpy.

Bonus: cross-sectional momentum

The chart indicator is time-series momentum. Its famous cousin, cross-sectional momentum, ranks many instruments by recent return and buys the leaders — a few lines across a DataFrame of prices:

# prices: DataFrame, one column per instrument.
lookback = 126                       # ~6 months of daily bars
returns = prices / prices.shift(lookback) - 1
ranks = returns.rank(axis=1, ascending=False)
longs = ranks <= 5                   # top-5 momentum names each day

This is the shape of the momentum factor from the history — the same “recent strength persists” intuition, applied across a universe rather than one chart.

The lazy one-liner

import pandas_ta as ta
df["mom10"] = ta.mom(df["close"], length=10)   # difference form

Same indicator elsewhere: MQL5, Pine Script, EasyLanguage, NinjaScript.


This post is educational, not financial advice. Indicators describe the past; they don’t predict the future. Backtest anything before you risk real money on it.

Sources and further reading

  1. Windowing operations (pandas documentation)

Historical research from the Algogen archive. Not investment advice.

Blog

Have a strategy idea?

Describe it in plain English, preview where your rules fire, then decide whether the evidence is worth a backtest.

Keep me postedHow it works