Appearance

Personalize your experience

Mode
Accent Color
Direction
MarketplacestrategiesMulti-Horizon Momentum
QuaScript

Multi-Horizon Momentum

Admin's ChoiceFree

Time-series momentum voted across twelve horizons

0.0(0)
0 installs 0 0 comments
Q
159 listings

The QuaTick team's QuaScript analyses, run by the native C++ engine.

View Profile
quascriptstrategymomentumtime-series
Free
Backtest this strategy Open in QuaTick IDE Edit in IDE
Version
Updated
Compatible

Live engine preview

QuaScriptQuaScript

The QuaScript engine's own output on the chart the terminal uses. Change the settings or edit the code and press Run to recompute it.

Multi-Horizon Momentumengine result
Loading the engine result…
quatick-charts · QuaScript engine on synthetic 1-minute bars · drag to pan · scroll to zoom · Run executes the script on the engine (⌘/Ctrl+Enter while editing)

About

Time-series momentum voted across twelve horizons. Each horizon votes with the sign of its volatility-scaled return; the position follows the vote only when a clear majority agrees, and goes flat when the horizons disagree. Using many horizons avoids betting on one lookback. Entry: net votes at or beyond the majority in either direction. Exit: the vote falls back below the hold level; a protective ATR stop on every entry; one entry per vote episode. Risk: 95 % of equity while invested, 30 % drawdown halt. Method: time-series momentum (Moskowitz, Ooi and Pedersen, 2012).


Settings

Shortest horizon: 12

Horizon step: 12

Majority (of 12): 8

Hold level: 4

Protective stop (ATR): 5


Measured backtests

Run by the backtest engine on public candles, 2025-11-01 to 2026-11-01, with the script's own commission and slippage, on BTCUSDT 1h (Binance) and ETHUSDT 1h (Binance). The figures per market are in the Measured backtest panel below. Past results do not predict future returns.


Backtest it yourself

Open it on the backtesting page to run it on any symbol, interval and date range, then use Monte Carlo, optimisation, walk-forward and robustness tests.

Strategy Rules

Entry Conditions

  • ▸ net votes at or beyond the majority in either direction

Exit Conditions

  • ▸ the vote falls back below the hold level; a protective ATR stop on every entry; one entry per vote episode

Measured backtest

BTCUSDT 1h (Binance), 2025-11-01 to 2026-11-01 · backtest engine, script costs included

Backtest this strategy

-18.1%

Return

-0.69

Sharpe

-30.1%

Max DD

23.3%

Win Rate

86

Trades

MarketTradesReturnSharpeMax DDWin rateProfit factor
BTCUSDT 1h86-18.1%-0.69-30.1%23.3%0.76
ETHUSDT 1h70-21.5%-0.58-30.2%21.4%0.74

Past results on historical data do not predict future returns.

Source Code

Edit in IDE
quascript
1strategy "Multi-Horizon Momentum" {
2 overlay = true
3 capital = 100000
4 commission = 0.05
5 slippage = 1
6 sizing = percent_equity
7 size = 95
8 pyramiding = 1
9}
10/// Time-series momentum voted across twelve horizons. Each horizon votes with the sign of its
11/// volatility-scaled return; the position follows the vote only when a clear majority agrees, and
12/// goes flat when the horizons disagree. Using many horizons avoids betting on one lookback.
13/// Entry: net votes at or beyond the majority in either direction. Exit: the vote falls back below
14/// the hold level; a protective ATR stop on every entry; one entry per vote episode.
15/// Risk: 95 % of equity while invested, 30 % drawdown halt.
16/// Method: time-series momentum (Moskowitz, Ooi and Pedersen, 2012).
17use "viz/premium" as pr
18h_min = param.int(12, title = "Shortest horizon", min = 2, max = 200, group = "Vote")
19h_step = param.int(12, title = "Horizon step", min = 1, max = 200, group = "Vote")
20enter = param.int(8, title = "Majority (of 12)", min = 6, max = 12, group = "Vote")
21keep = param.int(4, title = "Hold level", min = 0, max = 11, group = "Vote")
22stop_k = param.float(5, title = "Protective stop (ATR)", min = 1, max = 20, step = 0.5, group = "Risk")
23sd = math.max(stat.stdev(math.log(close / close[1]), 100), 1e-12)
24net = 0
25for k in 0..=11 {
26 hz = h_min + k * h_step
27 z = math.log(close / close[hz]) / (sd * math.sqrt(hz))
28 if z > 0.25 { net := net + 1 }
29 if z < -0.25 { net := net - 1 }
30}
31a = ta.atr(50)
32vote = net >= enter ? 1 : net <= -enter ? -1 : 0
33persist used = 0
34if vote != vote[1] { used := 0 }
35if vote == 1 and position.side <= 0 and used != 1 {
36 order.market("L", side.long)
37 exit.bracket("L exit", entry = "L", stop = close - stop_k * a)
38 used := 1
39}
40if vote == -1 and position.side >= 0 and used != -1 {
41 order.market("S", side.short)
42 exit.bracket("S exit", entry = "S", stop = close + stop_k * a)
43 used := -1
44}
45if (position.side > 0 and net < keep) or (position.side < 0 and net > -keep) { exit.close_all() }
46risk.max_drawdown(30)
47render.line(ta.ema(close, h_min + 6 * h_step), "Momentum mean", color = net > 0 ? color.emerald.300 : net < 0 ? color.rose.300 : color.slate.500, width = 2)
48render.background(vote == 1 ? color.translucent(color.emerald.500, 93) : vote == -1 ? color.translucent(color.rose.500, 93) : na)
49persist t = draw.table.create(anchor.top_right, 4, 2)
50if bar.is_last {
51 pr.heading(t, 2, "Multi-Horizon Momentum", "Strategy · 12-horizon vote")
52 pr.row(t, 2, "Net votes", str.format("{:+d}", net), net > 0 ? pr.BULL : net < 0 ? pr.BEAR : pr.LABEL)
53 pr.row(t, 3, "Stance", vote > 0 ? "Long" : vote < 0 ? "Short" : "Flat", color.white)
54}
55 
Read-only preview. Open in the QuaTick IDE to edit and deploy.

Reviews

No reviews yet. Be the first to review this listing.

Discussion

Sign in to join the discussion. Your posts and replies show up on your profile.