Faber Timing Model

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. Compute a 10-month simple moving average of the close: 210 bars, treating every 21 bars as one month.
  2. Check the strategy only once a month, on every 21st bar; between reviews, nothing the market does matters. This monthly cadence is Faber's key idea: it ignores intra-month noise entirely and is what keeps the trade count tiny.
  3. At a review: if the close is above the 10-month average, be in the market; if below, be out. Buy or sell only when the answer changes from the previous review.

Example Strategy

Pine Script

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

//@version=6
// Faber Timing Model — 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.
// The review dates count from the first bar on the chart, and TradingView's
// history starts somewhere other than the backtest's, so the reviews here
// fall on different bars from the site's.
strategy("Faber Timing Model", overlay=true,
     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 ──────────────────────────────────────────────────────────────
average = ta.sma(close, 210)
// Reviewed once a "month" — every 21st bar from the 210th on — and
// only a change between two reviews trades.
review = bar_index >= 209 and (bar_index - 209) % 21 == 0
var bool reviewed = false
var bool wasAbove = false
enterNow = false
exitNow = false
if review
    nowAbove = close > average
    if reviewed
        enterNow := nowAbove and not wasAbove
        exitNow := not nowAbove and wasAbove
    wasAbove := nowAbove
    reviewed := true

// ── 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(average, "SMA 210", color=#4d8dff)