June 10, 2026 • Amp AI Team
RA-Momentum: Computing Momentum for Rates
A precise methodology for computing vol-normalized, direction-signed momentum signals across horizons for rates trading — covering state classification, deterministic ordering, and worked examples.
Momentum in rates markets is noisier than in equities. Yields trend, but they also mean-revert, and the path matters as much as the level change. This post lays out a simple, deterministic methodology for computing a momentum trigger that accounts for all three: direction, magnitude relative to volatility, and path quality.
The Core Formula
The signal is vol-normalized and direction-signed across three horizons — 1 week (5 days), 1 month (21 days), and 3 months (63 days):
m_raw(w) = Δy(w) / (σ_daily × √w_days) windows w = 1w(5), 1m(21), 3m(63)
trade_yield_sign = −direction_sign (move in your P&L direction = positive)
m_signed(w) = trade_yield_sign × m_raw(w) ( >0 = moving in your favor )
M_signed = mean[ m_signed(1w, 1m, 3m) ]
ER (quality) = |Σ Δy| / Σ|Δy| over window (1 = clean trend, →0 = noise)
divergence = sign(m_signed 1w) ≠ sign(m_signed 3m) (early turn)
m_raw measures how many daily standard deviations yields have moved over the window. trade_yield_sign flips it into trade P&L space — a yield rise is positive for a payer and negative for a receiver. The efficiency ratio ER is the key quality gate: it equals 1 when every daily move went in the same direction, and collapses toward 0 when the net move was achieved through a noisy, oscillating path.
Momentum State Classification
Momentum, from m_raw at {5, 20, 60} (ER-gated) plus the m_day slope (positive = moving in the trade's favour):
| Pattern across windows | Momentum state | | --- | --- | | Segments agree positive, ER ≥ 1.3, m_day flat/rising | M-follow — aligned, continuing/accelerating | | Positive but m_day falling, or 5d rolling under 60d | M-exhausting — decelerating | | Was negative, 5d just flipped positive (ER ok) | M-turning — early favourable turn | | Agree negative, ER ≥ 1.3 | M-against — moving against the trade | | ER < 1.3 anywhere material, or signs disagree | M-noise — no clean trigger |
Step-by-Step Computation
Primitives (compute once)
Two thresholds: τ ≈ 0.4 (the σ-unit floor below which a window is directionally "flat"), and a small slope tolerance ε.
pos(w) = m_raw(w) ≥ +τ (favorable & material)
neg(w) = m_raw(w) ≤ −τ (adverse & material)
flat(w) = |m_raw(w)| < τ
material(w) = not flat(w)
gated(w) = ER*(w) ≥ 1.3
slope = m_day(5) − m_day(60), m_day(w) = m_raw(w)/√w
Two phrasing collapses worth noting:
- "m_day falling" and "5d rolling under 60d" are the same condition — both reduce to
slope < 0. The table lists them as if two triggers; they're one written two ways. - "ER < 1.3 anywhere material" is the key qualifier: the gate only bites a window that's actually making a directional claim. A flat window failing the gate is just flat (fine); a material window failing it is a directional claim built on noise. So
bad(w) = material(w) ∧ ¬gated(w).
The Ordered Procedure
1. M-turning neg(60) ∧ gated(60) ← genuine prior adverse trend
∧ pos(5) ∧ gated(5) ← clean favorable flip at the front
∧ slope > 0
2. M-noise (veto) bad(20) ∨ bad(60) ← material claim on a reliable window, noise-quality path
3. M-follow pos(20) ∧ pos(60) ∧ gated(20) ∧ gated(60)
∧ ¬neg(5) ← front not against
∧ slope ≥ −ε ← flat / rising
4. M-exhausting pos(20) ∧ pos(60) ∧ gated(20) ∧ gated(60)
∧ slope < −ε ← decelerating (= 5d rolling under 60d)
5. M-against neg(20) ∧ neg(60) ∧ gated(20) ∧ gated(60)
6. M-noise else ← signs scrambled, or all flat, or flat core
Why This Order
Turning is tested first because it is, by construction, a "signs disagree" reading (5d favorable, 60d adverse). If you ran the generic "signs disagree → noise" rule first, every early reversion — the exact trigger the mean-revert lens is waiting for — would be swallowed as noise. The most specific pattern must pre-empt the catch-all.
Turning requires the 60d to be gated-negative, not just negative. That's what makes it a turn off a genuine trend rather than a flip out of chop — and it's why placing the quality veto (step 2) after turning doesn't kill legitimate turns: a real turn already has its gated backdrop established in step 1.
The quality veto runs before follow/against (step 2) so that a strong-looking net move whose path was choppy can't be read as a clean signal. This is where "ER < 1.3 anywhere material" lives, scoped to the reliable windows {20, 60}.
Follow and exhausting are split only by slope — identical alignment, opposite acceleration. Testing follow first and exhausting as the slope < −ε complement makes them mutually exclusive with no gap.
The 5d gate matters in exactly one place — step 1, where a clean flip is the whole signal. Elsewhere the 5d is advisory (five path points → high ER variance), which is why the reliable gates in steps 2–5 key off the 20d and 60d.
Worked Disambiguation
Pay trade, σ_d = 6, τ = 0.4:
| Scenario | m_raw {5, 20, 60} | ER gated? | slope | Fires | State |
| --- | --- | --- | --- | --- | --- |
| Accelerating up | {+0.97, +1.27, +1.51} | all ✓ | +0.24 | step 3 | M-follow |
| Front fading | {+0.20, +1.20, +1.50} | all ✓ | −0.11 | step 4 (5d flat, slope<0) | M-exhausting |
| Early reversion | {+0.97, −0.67, −1.03} | all ✓ | +0.57 | step 1 (neg60 gated, pos5 gated, slope>0) | M-turning |
| Aligned adverse | {−0.80, −1.10, −1.30} | all ✓ | — | step 5 | M-against |
| Strong net, choppy path | {+0.50, +1.40, +1.60} | ER*(20)=1.0 ✗ | — | step 2 (bad(20)) | M-noise |
| Scrambled | {+0.90, −1.20, +1.40} | mixed | — | step 6 (no coherent alignment) | M-noise |
The second and third rows illustrate the cleanest disambiguation: the front-fading case (5d decelerating but still favorable-ish, trend up) is exhausting, while the early-reversion case (5d flipped favorable, trend down) is turning. Opposite trend backdrops, both keyed off the 5d-vs-trend relationship — and the procedure separates them cleanly because turning's negative-gated-60d predicate can't fire when the 60d is positive.