Appearance

Personalize your experience

Mode
Accent Color
Direction
MarketplacestrategiesTurtle Pyramid Breakout
QuaScript

Turtle Pyramid Breakout

Admin's ChoiceFree

Channel breakouts that pyramid up to four N-sized units

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
quascriptstrategybreakoutpyramidingtrend
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.

Turtle Pyramid 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

The classic channel-breakout trend system with volatility units and pyramiding. A close beyond the `entry_n`-bar channel opens one unit; every further N move in favour (N = the 20-bar ATR at the first entry) adds another unit, up to four. Every unit shares one stop, three N behind the newest entry, so the open risk stays bounded while winners compound. The trade ends on a close beyond the shorter `exit_n`-bar channel on the other side. Entry: close above the prior `entry_n`-bar high (below the low for shorts); add a unit each `add_n` N, up to `units`. Exit: shared stop at newest entry -/+ `stop_n` N (3 by default, wider than the daily-bar original because hourly noise is larger relative to N), or a close through the `exit_n`-bar opposite channel. Risk: 0.5 % of equity per unit at its stop. Method: public channel-breakout rules with N-based units (Donchian channels, ATR).


Settings

Entry channel: 55

Exit channel: 20

Maximum units: 4

Add every (N): 1

Stop (N): 3


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 above the prior `entry_n`-bar high (below the low for shorts); add a unit each `add_n` N, up to `units`

Exit Conditions

  • ▸ shared stop at newest entry -/+ `stop_n` N (3 by default, wider than the daily-bar original because hourly noise is larger relative to N), or a close through the `exit_n`-bar opposite channel

Measured backtest

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

Backtest this strategy

35.3%

Return

1.17

Sharpe

-27.5%

Max DD

28.5%

Win Rate

298

Trades

MarketTradesReturnSharpeMax DDWin rateProfit factor
BTCUSDT 1h29835.3%1.17-27.5%28.5%1.42
ETHUSDT 1h289-4.8%-0.06-27.5%30.4%0.93

Past results on historical data do not predict future returns.

Source Code

Edit in IDE
quascript
1strategy "Turtle Pyramid Breakout" {
2 overlay = true
3 capital = 100000
4 commission = 0.05
5 slippage = 1
6 sizing = risk_percent
7 max_leverage = 1
8 size = 0.5
9 pyramiding = 4
10}
11/// The classic channel-breakout trend system with volatility units and pyramiding. A close beyond
12/// the `entry_n`-bar channel opens one unit; every further N move in favour (N = the 20-bar
13/// ATR at the first entry) adds another unit, up to four. Every unit shares one stop, three N behind
14/// the newest entry, so the open risk stays bounded while winners compound. The trade ends on a
15/// close beyond the shorter `exit_n`-bar channel on the other side.
16/// Entry: close above the prior `entry_n`-bar high (below the low for shorts); add a unit each
17/// `add_n` N, up to `units`. Exit: shared stop at newest entry -/+ `stop_n` N (3 by default, wider
18/// than the daily-bar original because hourly noise is larger relative to N), or a close through the
19/// `exit_n`-bar opposite channel. Risk: 0.5 % of equity per unit at its stop.
20/// Method: public channel-breakout rules with N-based units (Donchian channels, ATR).
21use "viz/premium" as pr
22entry_n = param.int(55, title = "Entry channel", min = 10, max = 500, group = "Channels")
23exit_n = param.int(20, title = "Exit channel", min = 5, max = 300, group = "Channels")
24units = param.int(4, title = "Maximum units", min = 1, max = 4, group = "Pyramid")
25add_n = param.float(1.0, title = "Add every (N)", min = 0.1, max = 3, step = 0.1, group = "Pyramid")
26stop_n = param.float(3.0, title = "Stop (N)", min = 0.5, max = 6, step = 0.1, group = "Risk")
27n = ta.atr(20)
28hh = ta.highest(high, entry_n)
29ll = ta.lowest(low, entry_n)
30xh = ta.highest(high, exit_n)
31xl = ta.lowest(low, exit_n)
32brk_up = close > hh[1]
33brk_dn = close < ll[1]
34persist count = 0
35persist last_px = na
36persist unit_n = na
37persist stop = na
38if position.size == 0 { count := 0 }
39// shared stop for every open unit
40fn restop_long(count: int, stop: float) {
41 exit.bracket("L1 stop", entry = "L1", stop = stop)
42 if count >= 2 { exit.bracket("L2 stop", entry = "L2", stop = stop) }
43 if count >= 3 { exit.bracket("L3 stop", entry = "L3", stop = stop) }
44 if count >= 4 { exit.bracket("L4 stop", entry = "L4", stop = stop) }
45}
46fn restop_short(count: int, stop: float) {
47 exit.bracket("S1 stop", entry = "S1", stop = stop)
48 if count >= 2 { exit.bracket("S2 stop", entry = "S2", stop = stop) }
49 if count >= 3 { exit.bracket("S3 stop", entry = "S3", stop = stop) }
50 if count >= 4 { exit.bracket("S4 stop", entry = "S4", stop = stop) }
51}
52flat = position.size == 0
53if flat and brk_up {
54 unit_n := n
55 last_px := close
56 stop := close - stop_n * n
57 count := 1
58 order.market("L1", side.long)
59 restop_long(count, stop)
60} else if flat and brk_dn {
61 unit_n := n
62 last_px := close
63 stop := close + stop_n * n
64 count := 1
65 order.market("S1", side.short)
66 restop_short(count, stop)
67} else if position.size > 0 and count < units and close >= last_px + add_n * unit_n {
68 count := count + 1
69 last_px := close
70 stop := close - stop_n * unit_n
71 if count == 2 { order.market("L2", side.long) }
72 if count == 3 { order.market("L3", side.long) }
73 if count == 4 { order.market("L4", side.long) }
74 restop_long(count, stop)
75} else if position.size < 0 and count < units and close <= last_px - add_n * unit_n {
76 count := count + 1
77 last_px := close
78 stop := close + stop_n * unit_n
79 if count == 2 { order.market("S2", side.short) }
80 if count == 3 { order.market("S3", side.short) }
81 if count == 4 { order.market("S4", side.short) }
82 restop_short(count, stop)
83}
84if position.size > 0 and close < xl[1] { exit.close_all() }
85if position.size < 0 and close > xh[1] { exit.close_all() }
86risk.max_drawdown(30)
87up_p = render.line(hh, "Entry channel high", color = color.translucent(color.emerald.300, 45), width = 1)
88dn_p = render.line(ll, "Entry channel low", color = color.translucent(color.rose.300, 45), width = 1)
89render.band(up_p, dn_p, texture = "gradient", direction = "edges", upper_color = color.translucent(color.emerald.500, 88), lower_color = color.translucent(color.rose.500, 88), opacity = 1, title = "Channel")
90render.line(xh, "Exit channel high", color = color.translucent(color.slate.300, 65), width = 1, stroke = style.dotted)
91render.line(xl, "Exit channel low", color = color.translucent(color.slate.300, 65), width = 1, stroke = style.dotted)
92render.step(position.size != 0 ? stop : na, "Shared stop", color = color.amber.300, width = 1.25, stroke = style.dashed)
93render.mark(flat and brk_up, shape = shape.triangle_up, at = anchor.below_bar, color = color.emerald.300, text = "1", title = "First unit long")
94render.mark(flat and brk_dn, shape = shape.triangle_down, at = anchor.above_bar, color = color.rose.300, text = "1", title = "First unit short")
95render.mark(not flat and count > count[1], shape = shape.circle, at = anchor.below_bar, color = color.amber.200, size = 0.45, title = "Unit added")
96persist t = draw.table.create(anchor.top_right, 5, 2)
97if bar.is_last {
98 pr.heading(t, 2, "Turtle Pyramid Breakout", "Strategy · channel breakout, N units")
99 pr.row(t, 2, "Units open", str.format("{} / {}", position.size == 0 ? 0 : count, units), color.white)
100 pr.row(t, 3, "N (ATR 20)", str.format("{:.2f}", n), pr.LABEL)
101 pr.row(t, 4, "Shared stop", position.size != 0 ? str.format("{:.2f}", stop) : "Flat", pr.WARN)
102}
103 
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.