Dual Momentum 90 252

How this strategy trades, what it scored, and the measurements the score was read from: every symbol and timeframe, on real and resampled history.

How It Trades

  1. Measure two trailing returns each bar: a quarterly one (90 bars back) and a yearly one (252 bars back), a fast clock and a slow clock for the trend.
  2. Buy only when both are positive: the market is up versus last quarter and versus last year, so the short and long views agree the trend is real.
  3. Sell as soon as either turns negative: one clock disagreeing is enough to step aside. Requiring agreement enters later than a single-window momentum strategy but avoids trades where a short rally fights a longer downtrend, or an old uptrend is already rolling over.

Example Strategy

Pine Script

Paste it into TradingView’s Pine Editor to run these rules on any chart.

//@version=6
// Dual Momentum 90 252 — sort.finance. Fills at the signal bar's close, 0.02% fee a side,
// whole account per trade, as the backtest. History and indicator warm-up
// differ from the site's, so expect close to the same trades, not identical.
strategy("Dual Momentum 90 252", overlay=false,
     initial_capital=100, default_qty_type=strategy.percent_of_equity,
     default_qty_value=100, commission_type=strategy.commission.percent,
     commission_value=0.02, process_orders_on_close=true, pyramiding=0)

// The bar the current position opened on, and the bar the last one closed on.
var int entryBar = na
var int exitBar = -1

// ── Signals ──────────────────────────────────────────────────────────────
fast = (close / close[90] - 1) * 100
slow = (close / close[252] - 1) * 100
aligned = fast > 0 and slow > 0
enterNow = aligned and not aligned[1]
exitNow = not aligned and aligned[1]

// ── Orders ───────────────────────────────────────────────────────────────
// Open on the first bar the entry holds while flat; close on the first
// later bar the exit holds; never reopen on the bar a position closed.
inTrade = strategy.position_size != 0
if inTrade and bar_index > entryBar and exitNow
    strategy.close("Long")
    exitBar := bar_index
else if not inTrade and bar_index > exitBar and enterNow
    strategy.entry("Long", strategy.long)
    entryBar := bar_index

// ── Drawing ──────────────────────────────────────────────────────────────
plot(fast, "Momentum 90", color=#4d8dff)
plot(slow, "Momentum 252", color=#e0a03a)
hline(0, "Zero", color=color.new(#8a92a0, 40), linestyle=hline.style_dashed)