Appearance
Personalize your experience
Trendline Break
Admin's ChoiceFreeBreaks of automatically drawn swing trendlines
Live engine preview
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.
About
Trades breaks of automatically drawn swing trendlines. The two latest swing highs form a falling resistance line and the two latest swing lows a rising support line; a line is valid only while no close has crossed it since its second swing. A close through a valid line by a margin is the signal: through falling resistance to go long, through rising support to go short. Entry: close beyond the valid line by `margin` ATR. Exit: stop at the last swing on the other side, target `reward` R, trailing after 1R. Risk: 1 % per trade.
Settings
Swing bars left: 8
Swing bars right: 4
Break margin (ATR): 0.3
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 valid line by `margin` ATR
Exit Conditions
- ▸ stop at the last swing on the other side, target `reward` R, trailing after 1R
Measured backtest
BTCUSDT 1h (Binance), 2025-11-01 to 2026-11-01 · backtest engine, script costs included
-13.2%
Return
-1.25
Sharpe
-19.8%
Max DD
22.2%
Win Rate
54
Trades
| Market | Trades | Return | Sharpe | Max DD | Win rate | Profit factor |
|---|---|---|---|---|---|---|
| BTCUSDT 1h | 54 | -13.2% | -1.25 | -19.8% | 22.2% | 0.64 |
| ETHUSDT 1h | 18 | -8.0% | -1.28 | -10.5% | 16.7% | 0.46 |
Past results on historical data do not predict future returns.
Source Code
Edit in IDE| 1 | strategy "Trendline Break" { |
| 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 | max_objects = 40 |
| 11 | } |
| 12 | /// Trades breaks of automatically drawn swing trendlines. The two latest swing highs form a falling |
| 13 | /// resistance line and the two latest swing lows a rising support line; a line is valid only while |
| 14 | /// no close has crossed it since its second swing. A close through a valid line by a margin is the |
| 15 | /// signal: through falling resistance to go long, through rising support to go short. |
| 16 | /// Entry: close beyond the valid line by `margin` ATR. Exit: stop at the last swing on the other |
| 17 | /// side, target `reward` R, trailing after 1R. Risk: 1 % per trade. |
| 18 | use "viz/premium" as pr |
| 19 | left = param.int(8, title = "Swing bars left", min = 2, max = 50, group = "Swings") |
| 20 | right = param.int(4, title = "Swing bars right", min = 1, max = 30, group = "Swings") |
| 21 | margin = param.float(0.3, title = "Break margin (ATR)", min = 0, max = 3, step = 0.05, group = "Entry") |
| 22 | reward = param.float(2.5, title = "Target (R)", min = 0.5, max = 10, step = 0.1, group = "Risk") |
| 23 | a = ta.atr(30) |
| 24 | ph = ta.pivot_high(left, right) |
| 25 | pl = ta.pivot_low(left, right) |
| 26 | persist h1x = na |
| 27 | persist h1y = na |
| 28 | persist h2x = na |
| 29 | persist h2y = na |
| 30 | persist l1x = na |
| 31 | persist l1y = na |
| 32 | persist l2x = na |
| 33 | persist l2y = na |
| 34 | persist res_ok = false |
| 35 | persist sup_ok = false |
| 36 | persist res_id = na |
| 37 | persist sup_id = na |
| 38 | if not math.is_na(ph) { |
| 39 | h1x := h2x |
| 40 | h1y := h2y |
| 41 | h2x := bar.index - right |
| 42 | h2y := ph |
| 43 | res_ok := not math.is_na(h1y) and h2y < h1y |
| 44 | if not math.is_na(res_id) { draw.segment.delete(res_id) } |
| 45 | res_id := res_ok ? draw.segment.create(h1x, h1y, h2x, h2y, color = color.rose.400, width = 1.5, ray = ray.right) : na |
| 46 | } |
| 47 | if not math.is_na(pl) { |
| 48 | l1x := l2x |
| 49 | l1y := l2y |
| 50 | l2x := bar.index - right |
| 51 | l2y := pl |
| 52 | sup_ok := not math.is_na(l1y) and l2y > l1y |
| 53 | if not math.is_na(sup_id) { draw.segment.delete(sup_id) } |
| 54 | sup_id := sup_ok ? draw.segment.create(l1x, l1y, l2x, l2y, color = color.emerald.400, width = 1.5, ray = ray.right) : na |
| 55 | } |
| 56 | res_y = res_ok ? h2y + (h2y - h1y) / math.max(h2x - h1x, 1) * (bar.index - h2x) : na |
| 57 | sup_y = sup_ok ? l2y + (l2y - l1y) / math.max(l2x - l1x, 1) * (bar.index - l2x) : na |
| 58 | brk_up = res_ok and close > res_y + margin * a |
| 59 | brk_dn = sup_ok and close < sup_y - margin * a |
| 60 | if brk_up { res_ok := false } |
| 61 | if brk_dn { sup_ok := false } |
| 62 | flat = position.size == 0 |
| 63 | if flat and brk_up and not math.is_na(l2y) and close > l2y { |
| 64 | order.market("L", side.long) |
| 65 | exit.bracket("L exit", entry = "L", stop = l2y, target = close + (close - l2y) * reward, trail_offset = close - l2y, trail_trigger = close + (close - l2y)) |
| 66 | } |
| 67 | if flat and brk_dn and not math.is_na(h2y) and close < h2y { |
| 68 | order.market("S", side.short) |
| 69 | exit.bracket("S exit", entry = "S", stop = h2y, target = close - (h2y - close) * reward, trail_offset = h2y - close, trail_trigger = close - (h2y - close)) |
| 70 | } |
| 71 | risk.max_drawdown(25) |
| 72 | render.line(res_y, "Resistance line", color = color.translucent(color.rose.400, 60), width = 1, stroke = style.dotted) |
| 73 | render.line(sup_y, "Support line", color = color.translucent(color.emerald.400, 60), width = 1, stroke = style.dotted) |
| 74 | render.mark(brk_up, shape = shape.arrow_up, at = anchor.below_bar, color = color.emerald.300, text = "Break", title = "Resistance break") |
| 75 | render.mark(brk_dn, shape = shape.arrow_down, at = anchor.above_bar, color = color.rose.300, text = "Break", title = "Support break") |
| 76 | persist t = draw.table.create(anchor.top_right, 4, 2) |
| 77 | if bar.is_last { |
| 78 | pr.heading(t, 2, "Trendline Break", "Strategy · swing trendlines") |
| 79 | pr.row(t, 2, "Resistance", res_ok ? str.format("{:.2f}", res_y) : "none", pr.BEAR) |
| 80 | pr.row(t, 3, "Support", sup_ok ? str.format("{:.2f}", sup_y) : "none", pr.BULL) |
| 81 | } |
| 82 |
Reviews
No reviews yet. Be the first to review this listing.