Appearance
Personalize your experience
Velocity Tracker Trend
FreeAlpha-beta velocity trend with a tracking-error trailing stop
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
Trend following on a tracked velocity instead of a moving-average cross. An alpha-beta filter (the steady-state constant-velocity Kalman filter) estimates price level and velocity together. A trade starts when the velocity, in ATR per bar, passes a threshold while acceleration agrees, so the system joins moves that are speeding up rather than any drift. The stop trails at a multiple of the tracking error below the tracked level. Entry: velocity above `v_in` ATR per bar with positive smoothed acceleration and price inside the two-sigma envelope (no chasing shocks); mirror for shorts. Exit: trailing stop at the level minus `k_err` tracking errors (never loosened), or velocity back through zero. Risk: 1 % per trade at the initial stop.
Settings
Alpha (level gain): 0.18
Beta (velocity gain): 0.006
Error window: 50
Entry velocity (ATR / bar): 0.08
Trailing stop (tracking errors): 4
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
- ▸ velocity above `v_in` ATR per bar with positive smoothed acceleration and price inside the two-sigma envelope (no chasing shocks); mirror for shorts
Exit Conditions
- ▸ trailing stop at the level minus `k_err` tracking errors (never loosened), or velocity back through zero
Measured backtest
BTCUSDT 1h (Binance), 2025-11-01 to 2026-11-01 · backtest engine, script costs included
-4.8%
Return
-0.40
Sharpe
-15.3%
Max DD
29.8%
Win Rate
94
Trades
| Market | Trades | Return | Sharpe | Max DD | Win rate | Profit factor |
|---|---|---|---|---|---|---|
| BTCUSDT 1h | 94 | -4.8% | -0.40 | -15.3% | 29.8% | 0.87 |
| ETHUSDT 1h | 84 | -3.2% | -0.32 | -8.7% | 30.9% | 0.88 |
Past results on historical data do not predict future returns.
Source Code
Edit in IDE| 1 | strategy "Velocity Tracker Trend" { |
| 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 | /// Trend following on a tracked velocity instead of a moving-average cross. An alpha-beta filter |
| 12 | /// (the steady-state constant-velocity Kalman filter) estimates price level and velocity together. |
| 13 | /// A trade starts when the velocity, in ATR per bar, passes a threshold while acceleration agrees, |
| 14 | /// so the system joins moves that are speeding up rather than any drift. The stop trails at a |
| 15 | /// multiple of the tracking error below the tracked level. |
| 16 | /// Entry: velocity above `v_in` ATR per bar with positive smoothed acceleration and price inside |
| 17 | /// the two-sigma envelope (no chasing shocks); mirror for shorts. Exit: trailing stop at the level |
| 18 | /// minus `k_err` tracking errors (never loosened), or velocity back through zero. Risk: 1 % per |
| 19 | /// trade at the initial stop. |
| 20 | use "viz/premium" as pr |
| 21 | alpha = param.float(0.18, title = "Alpha (level gain)", min = 0.01, max = 0.9, step = 0.01, group = "Tracker") |
| 22 | beta = param.float(0.006, title = "Beta (velocity gain)", min = 0.0005, max = 0.5, step = 0.0005, group = "Tracker") |
| 23 | err_n = param.int(50, title = "Error window", min = 5, max = 1000, group = "Tracker") |
| 24 | v_in = param.float(0.08, title = "Entry velocity (ATR / bar)", min = 0.005, max = 1, step = 0.005, group = "Signals") |
| 25 | k_err = param.float(4.0, title = "Trailing stop (tracking errors)", min = 0.5, max = 10, step = 0.1, group = "Risk") |
| 26 | persist lvl = na |
| 27 | persist vel = 0.0 |
| 28 | pred = math.is_na(lvl) ? close : lvl + vel |
| 29 | resid = close - pred |
| 30 | lvl := pred + alpha * resid |
| 31 | vel := vel + beta * resid |
| 32 | err = stat.stdev(resid, err_n) |
| 33 | a = ta.atr(14) |
| 34 | v = vel / math.max(a, 1e-12) |
| 35 | acc = ta.ema(v - v[1], 5) |
| 36 | calm = math.abs(close - lvl) < 2 * err |
| 37 | go_l = v > v_in and acc > 0 and calm |
| 38 | go_s = v < -v_in and acc < 0 and calm |
| 39 | persist used = 0 |
| 40 | if v < 0 and used == 1 { used := 0 } |
| 41 | if v > 0 and used == -1 { used := 0 } |
| 42 | persist trail = na |
| 43 | flat = position.size == 0 |
| 44 | if flat and go_l and used != 1 { |
| 45 | trail := lvl - k_err * err |
| 46 | order.market("L", side.long) |
| 47 | exit.bracket("L stop", entry = "L", stop = trail) |
| 48 | used := 1 |
| 49 | } |
| 50 | if flat and go_s and used != -1 { |
| 51 | trail := lvl + k_err * err |
| 52 | order.market("S", side.short) |
| 53 | exit.bracket("S stop", entry = "S", stop = trail) |
| 54 | used := -1 |
| 55 | } |
| 56 | if position.size > 0 { |
| 57 | trail := math.max(trail, lvl - k_err * err) |
| 58 | exit.bracket("L stop", entry = "L", stop = trail) |
| 59 | if v < 0 { exit.close("L") } |
| 60 | } |
| 61 | if position.size < 0 { |
| 62 | trail := math.min(trail, lvl + k_err * err) |
| 63 | exit.bracket("S stop", entry = "S", stop = trail) |
| 64 | if v > 0 { exit.close("S") } |
| 65 | } |
| 66 | risk.max_drawdown(25) |
| 67 | tone = color.ramp(math.clamp(v, -0.25, 0.25), -0.25, 0.25, "coolwarm") |
| 68 | u = render.line(lvl + err, "Envelope top", color = color.transparent, width = 0) |
| 69 | d = render.line(lvl - err, "Envelope bottom", color = color.transparent, width = 0) |
| 70 | render.band(u, d, color = color.ramp(math.clamp(v, -0.25, 0.25), -0.25, 0.25, "coolwarm", 65), opacity = 1, title = "Velocity envelope") |
| 71 | render.line(lvl, "Tracked level", color = tone, width = 2) |
| 72 | render.step(position.size != 0 ? trail : na, "Trailing stop", color = color.translucent(color.white, 30), width = 1, stroke = style.dashed) |
| 73 | render.mark(go_l and flat and used[1] != 1, shape = shape.triangle_up, at = anchor.below_bar, color = color.red.300, text = "v+", title = "Long entry") |
| 74 | render.mark(go_s and flat and used[1] != -1, shape = shape.triangle_down, at = anchor.above_bar, color = color.blue.300, text = "v-", title = "Short entry") |
| 75 | persist t = draw.table.create(anchor.top_right, 5, 2) |
| 76 | if bar.is_last { |
| 77 | pr.heading(t, 2, "Velocity Tracker Trend", "Strategy · alpha-beta velocity") |
| 78 | pr.row(t, 2, "Velocity", str.format("{:+.3f} ATR / bar", v), v > 0 ? pr.BULL : pr.BEAR) |
| 79 | pr.row(t, 3, "Acceleration", acc > 0 ? "Speeding up" : "Slowing", acc > 0 ? pr.BULL : pr.BEAR) |
| 80 | pr.row(t, 4, "Trailing stop", position.size != 0 ? str.format("{:.2f}", trail) : "Flat", color.white) |
| 81 | } |
| 82 |
Reviews
No reviews yet. Be the first to review this listing.