Appearance

Personalize your experience

Mode
Accent Color
Direction
MarketplacestrategiesVariance Ratio Breakout
QuaScript

Variance Ratio Breakout

Free

Keltner breakouts only when variance ratios say momentum pays

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
quascriptstrategybreakoutvariance-ratio
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.

Variance Ratio Breakoutengine 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

Takes breakouts only when they statistically tend to continue. The Lo-MacKinlay variance ratio at the holding period compares the variance of q-bar returns with q times the one-bar variance: above one, moves extend; below one, they reverse. Breakouts of a volatility-scaled channel are traded only when the ratio says momentum pays, and held for about the holding period. Entry: close beyond the Keltner channel with VR(q) above the threshold. Exit: ATR stop, a target of `reward` R, or a time stop after twice the holding period. Risk: 1 % per trade. Method: Lo and MacKinlay (1988).


Settings

Holding period (bars): 8

Estimation window: 200

Minimum variance ratio: 1.1

Channel length: 20

Channel width (ATR): 2

Stop (ATR): 1.8

Target (R): 2.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

  • ▸ close beyond the Keltner channel with VR(q) above the threshold

Exit Conditions

  • ▸ ATR stop, a target of `reward` R, or a time stop after twice the holding period

Measured backtest

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

Backtest this strategy

-8.4%

Return

-1.17

Sharpe

-15.2%

Max DD

29.3%

Win Rate

41

Trades

MarketTradesReturnSharpeMax DDWin rateProfit factor
BTCUSDT 1h41-8.4%-1.17-15.2%29.3%0.68
ETHUSDT 1h55-3.3%-0.33-9.6%34.5%0.89

Past results on historical data do not predict future returns.

Source Code

Edit in IDE
quascript
1strategy "Variance Ratio Breakout" {
2 overlay = true
3 capital = 100000
4 commission = 0.05
5 slippage = 1
6 sizing = risk_percent
7 max_leverage = 1
8 size = 1
9 pyramiding = 1
10}
11/// Takes breakouts only when they statistically tend to continue. The Lo-MacKinlay variance ratio
12/// at the holding period compares the variance of q-bar returns with q times the one-bar variance:
13/// above one, moves extend; below one, they reverse. Breakouts of a volatility-scaled channel are
14/// traded only when the ratio says momentum pays, and held for about the holding period.
15/// Entry: close beyond the Keltner channel with VR(q) above the threshold. Exit: ATR stop, a
16/// target of `reward` R, or a time stop after twice the holding period.
17/// Risk: 1 % per trade. Method: Lo and MacKinlay (1988).
18use "viz/premium" as pr
19q = param.int(8, title = "Holding period (bars)", min = 2, max = 60, group = "Test")
20vr_len = param.int(200, title = "Estimation window", min = 50, max = 3000, group = "Test")
21vr_min = param.float(1.1, title = "Minimum variance ratio", min = 0.8, max = 3, step = 0.01, group = "Test")
22kc_len = param.int(20, title = "Channel length", min = 5, max = 200, group = "Entry")
23kc_mult = param.float(2.0, title = "Channel width (ATR)", min = 0.5, max = 5, step = 0.1, group = "Entry")
24stop_k = param.float(1.8, title = "Stop (ATR)", min = 0.5, max = 8, step = 0.1, group = "Risk")
25reward = param.float(2.5, title = "Target (R)", min = 0.5, max = 10, step = 0.1, group = "Risk")
26vr = hft.variance_ratio(close, vr_len, q)
27(kc_mid, kc_up, kc_lo) = ta.keltner(close, kc_len, kc_mult, kc_len)
28a = ta.atr(20)
29momentum = vr > vr_min
30flat = position.size == 0
31if flat and momentum and close > kc_up and close[1] <= kc_up[1] {
32 order.market("L", side.long)
33 exit.bracket("L exit", entry = "L", stop = close - stop_k * a, target = close + stop_k * a * reward)
34}
35if flat and momentum and close < kc_lo and close[1] >= kc_lo[1] {
36 order.market("S", side.short)
37 exit.bracket("S exit", entry = "S", stop = close + stop_k * a, target = close - stop_k * a * reward)
38}
39if position.size != 0 and position.bars_held >= 2 * q { exit.close_all() }
40risk.max_drawdown(25)
41pu = render.line(kc_up, "Channel high", color = color.translucent(color.amber.300, 40), width = 1)
42pl = render.line(kc_lo, "Channel low", color = color.translucent(color.amber.300, 40), width = 1)
43render.band(pu, pl, color = momentum ? color.amber.500 : color.slate.600, opacity = 0.06, title = "Channel")
44render.line(kc_mid, "Channel mid", color = momentum ? color.amber.300 : color.slate.500, width = 1.5)
45persist t = draw.table.create(anchor.top_right, 4, 2)
46if bar.is_last {
47 pr.heading(t, 2, "Variance Ratio Breakout", "Strategy · Lo-MacKinlay filter")
48 pr.row(t, 2, str.format("VR({})", q), str.format("{:.3f}", vr), momentum ? pr.BULL : pr.LABEL)
49 pr.row(t, 3, "Breakouts", momentum ? "Traded" : "Ignored", momentum ? pr.BULL : pr.LABEL)
50}
51 
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.