Appearance
Personalize your experience
Trend Prism Follower
FreeTrades only unanimous, clean regression trends
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
Follows trends only while they are both unanimous and clean. Eight linear regressions from `base` to eight times `base` bars vote on direction with their slopes, and their mean R squared measures how straight the trend is. A position opens when every slope agrees and the fits are clean, and closes as soon as quality decays or the shortest fits turn against it, so the system sits out the noisy middle of ranges where trend followers lose most. Entry: all eight slopes up (down) and mean R squared above `q_in`. Exit: mean R squared below `q_out`, the two shortest slopes turning against the position, or a stop `stop_k` ATR beyond the longest regression (trailed, never loosened). Risk: 1 % per trade at the initial stop.
Settings
Shortest window: 12
Entry quality (R squared): 0.6
Exit quality (R squared): 0.35
Stop beyond long fit (ATR): 1.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
- ▸ all eight slopes up (down) and mean R squared above `q_in`
Exit Conditions
- ▸ mean R squared below `q_out`, the two shortest slopes turning against the position, or a stop `stop_k` ATR beyond the longest regression (trailed, never loosened)
Measured backtest
BTCUSDT 1h (Binance), 2025-11-01 to 2026-11-01 · backtest engine, script costs included
-8.9%
Return
-1.59
Sharpe
-10.2%
Max DD
22.0%
Win Rate
59
Trades
| Market | Trades | Return | Sharpe | Max DD | Win rate | Profit factor |
|---|---|---|---|---|---|---|
| BTCUSDT 1h | 59 | -8.9% | -1.59 | -10.2% | 22.0% | 0.55 |
| ETHUSDT 1h | 52 | 11.3% | 1.13 | -8.3% | 25.0% | 1.67 |
Past results on historical data do not predict future returns.
Source Code
Edit in IDE| 1 | strategy "Trend Prism Follower" { |
| 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 | /// Follows trends only while they are both unanimous and clean. Eight linear regressions from |
| 12 | /// `base` to eight times `base` bars vote on direction with their slopes, and their mean R squared |
| 13 | /// measures how straight the trend is. A position opens when every slope agrees and the fits are |
| 14 | /// clean, and closes as soon as quality decays or the shortest fits turn against it, so the system |
| 15 | /// sits out the noisy middle of ranges where trend followers lose most. |
| 16 | /// Entry: all eight slopes up (down) and mean R squared above `q_in`. Exit: mean R squared below |
| 17 | /// `q_out`, the two shortest slopes turning against the position, or a stop `stop_k` ATR beyond |
| 18 | /// the longest regression (trailed, never loosened). Risk: 1 % per trade at the initial stop. |
| 19 | use "viz/premium" as pr |
| 20 | base = param.int(12, title = "Shortest window", min = 4, max = 200, group = "Prism") |
| 21 | q_in = param.float(0.6, title = "Entry quality (R squared)", min = 0.1, max = 0.95, step = 0.05, group = "Signals") |
| 22 | q_out = param.float(0.35, title = "Exit quality (R squared)", min = 0.05, max = 0.9, step = 0.05, group = "Signals") |
| 23 | stop_k = param.float(1.5, title = "Stop beyond long fit (ATR)", min = 0.2, max = 6, step = 0.1, group = "Risk") |
| 24 | pos = 0 |
| 25 | neg = 0 |
| 26 | q_sum = 0.0 |
| 27 | s1 = 0.0 |
| 28 | s2 = 0.0 |
| 29 | v8 = na |
| 30 | prev = render.line(close, "Facet edge 0", color = color.transparent, width = 0) |
| 31 | for k in 1..=8 { |
| 32 | (v, sl, _) = stat.linreg(close, base * k, 0) |
| 33 | q = math.coalesce(stat.r_squared(close, base * k), 0) |
| 34 | if sl > 0 { pos := pos + 1 } |
| 35 | if sl < 0 { neg := neg + 1 } |
| 36 | if k == 1 { s1 := sl } |
| 37 | if k == 2 { s2 := sl } |
| 38 | if k == 8 { v8 := v } |
| 39 | q_sum := q_sum + q |
| 40 | edge = render.line(v, str.format("Regression {}", k), color = color.transparent, width = 0) |
| 41 | render.band(prev, edge, color = color.ramp(q, 0, 1, "viridis", 45 + k * 4), opacity = 1, title = str.format("Facet {}", k)) |
| 42 | prev := edge |
| 43 | } |
| 44 | quality = q_sum / 8 |
| 45 | a = ta.atr(14) |
| 46 | go_l = pos == 8 and quality >= q_in |
| 47 | go_s = neg == 8 and quality >= q_in |
| 48 | persist used = 0 |
| 49 | if quality < q_out { used := 0 } |
| 50 | persist trail = na |
| 51 | flat = position.size == 0 |
| 52 | if flat and go_l and used != 1 { |
| 53 | trail := math.min(v8 - stop_k * a, close - a) |
| 54 | order.market("L", side.long) |
| 55 | exit.bracket("L stop", entry = "L", stop = trail) |
| 56 | used := 1 |
| 57 | } |
| 58 | if flat and go_s and used != -1 { |
| 59 | trail := math.max(v8 + stop_k * a, close + a) |
| 60 | order.market("S", side.short) |
| 61 | exit.bracket("S stop", entry = "S", stop = trail) |
| 62 | used := -1 |
| 63 | } |
| 64 | if position.size > 0 { |
| 65 | trail := math.max(trail, v8 - stop_k * a) |
| 66 | exit.bracket("L stop", entry = "L", stop = trail) |
| 67 | if quality < q_out or (s1 < 0 and s2 < 0) { exit.close("L") } |
| 68 | } |
| 69 | if position.size < 0 { |
| 70 | trail := math.min(trail, v8 + stop_k * a) |
| 71 | exit.bracket("S stop", entry = "S", stop = trail) |
| 72 | if quality < q_out or (s1 > 0 and s2 > 0) { exit.close("S") } |
| 73 | } |
| 74 | risk.max_drawdown(25) |
| 75 | render.step(position.size != 0 ? trail : na, "Trailing stop", color = color.translucent(color.white, 30), width = 1, stroke = style.dashed) |
| 76 | render.mark(go_l and flat and used[1] != 1, shape = shape.triangle_up, at = anchor.below_bar, color = color.yellow.300, text = "Prism", title = "Long entry") |
| 77 | render.mark(go_s and flat and used[1] != -1, shape = shape.triangle_down, at = anchor.above_bar, color = color.violet.300, text = "Prism", title = "Short entry") |
| 78 | persist t = draw.table.create(anchor.top_right, 5, 2) |
| 79 | if bar.is_last { |
| 80 | pr.heading(t, 2, "Trend Prism Follower", "Strategy · regression consensus and quality") |
| 81 | pr.row(t, 2, "Slopes up / down", str.format("{} / {}", pos, neg), pos > neg ? pr.BULL : pr.BEAR) |
| 82 | pr.row(t, 3, "Mean R squared", str.format("{:.2f}", quality), quality >= q_in ? color.yellow.300 : pr.LABEL) |
| 83 | pr.row(t, 4, "Stance", position.size > 0 ? "Long" : position.size < 0 ? "Short" : "Flat", color.white) |
| 84 | } |
| 85 |
Reviews
No reviews yet. Be the first to review this listing.