Appearance
Personalize your experience
Regime Probability Allocator
FreeLong, short or cash from softmax regime probabilities
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
Holds a position only when one regime is clearly more probable. Trend (regression slope in ATR units), trend quality (R squared) and order (one minus return entropy) are combined and turned into bull / neutral / bear probabilities with a softmax; the strategy is long while the bull probability exceeds the confidence level, short while the bear probability does, flat otherwise. Entry: a regime passes the confidence level. Exit: the regime loses confidence (falls below the exit level) or the opposite regime takes over; a protective ATR stop on every entry. Risk: 95 % of equity while invested, 30 % drawdown halt.
Settings
Regression window: 50
Entropy window: 60
Softmax temperature: 1
Entry confidence (%): 60
Exit confidence (%): 45
Protective stop (ATR): 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
- ▸ a regime passes the confidence level
Exit Conditions
- ▸ the regime loses confidence (falls below the exit level) or the opposite regime takes over; a protective ATR stop on every entry
Measured backtest
BTCUSDT 1h (Binance), 2025-11-01 to 2026-11-01 · backtest engine, script costs included
-26.4%
Return
-1.31
Sharpe
-30.3%
Max DD
31.8%
Win Rate
88
Trades
| Market | Trades | Return | Sharpe | Max DD | Win rate | Profit factor |
|---|---|---|---|---|---|---|
| BTCUSDT 1h | 88 | -26.4% | -1.31 | -30.3% | 31.8% | 0.61 |
| ETHUSDT 1h | 37 | -9.2% | -0.33 | -30.6% | 37.8% | 0.83 |
Past results on historical data do not predict future returns.
Source Code
Edit in IDE| 1 | strategy "Regime Probability Allocator" { |
| 2 | overlay = true |
| 3 | capital = 100000 |
| 4 | commission = 0.05 |
| 5 | slippage = 1 |
| 6 | sizing = percent_equity |
| 7 | size = 95 |
| 8 | pyramiding = 1 |
| 9 | } |
| 10 | /// Holds a position only when one regime is clearly more probable. Trend (regression slope in ATR |
| 11 | /// units), trend quality (R squared) and order (one minus return entropy) are combined and turned |
| 12 | /// into bull / neutral / bear probabilities with a softmax; the strategy is long while the bull |
| 13 | /// probability exceeds the confidence level, short while the bear probability does, flat otherwise. |
| 14 | /// Entry: a regime passes the confidence level. Exit: the regime loses confidence (falls below |
| 15 | /// the exit level) or the opposite regime takes over; a protective ATR stop on every entry. |
| 16 | /// Risk: 95 % of equity while invested, 30 % drawdown halt. |
| 17 | use "viz/premium" as pr |
| 18 | len = param.int(50, title = "Regression window", min = 10, max = 500, group = "Factors") |
| 19 | ent = param.int(60, title = "Entropy window", min = 20, max = 1000, group = "Factors") |
| 20 | temp = param.float(1.0, title = "Softmax temperature", min = 0.2, max = 5, step = 0.1, group = "Model") |
| 21 | conf = param.float(60, title = "Entry confidence (%)", min = 40, max = 95, group = "Signals") |
| 22 | exit_c = param.float(45, title = "Exit confidence (%)", min = 20, max = 90, group = "Signals") |
| 23 | stop_k = param.float(4, title = "Protective stop (ATR)", min = 1, max = 15, step = 0.5, group = "Risk") |
| 24 | (_, slope, _) = stat.linreg(close, len, 0) |
| 25 | a = ta.atr(len) |
| 26 | sl = slope / math.max(a, 1e-12) * math.sqrt(len) |
| 27 | q = math.coalesce(stat.r_squared(close, len), 0) |
| 28 | o = 1 - math.coalesce(stat.entropy(math.log(close / close[1]), ent, 10), 1) |
| 29 | strength = q * (1 + 3 * o) |
| 30 | bull_s = sl * strength / temp |
| 31 | bear_s = -sl * strength / temp |
| 32 | neut_s = (1 - q) * 1.5 / temp |
| 33 | mx = math.max(math.max(bull_s, bear_s), neut_s) |
| 34 | eb = math.exp(bull_s - mx) |
| 35 | en = math.exp(neut_s - mx) |
| 36 | er = math.exp(bear_s - mx) |
| 37 | pb = 100 * eb / (eb + en + er) |
| 38 | prb = 100 * er / (eb + en + er) |
| 39 | // one entry per regime episode: after a stop, wait until the regime resets |
| 40 | regime = pb > conf ? 1 : prb > conf ? -1 : 0 |
| 41 | persist used = 0 |
| 42 | if regime != regime[1] { used := 0 } |
| 43 | if position.size <= 0 and regime == 1 and used != 1 { |
| 44 | order.market("L", side.long) |
| 45 | exit.bracket("L exit", entry = "L", stop = close - stop_k * a) |
| 46 | used := 1 |
| 47 | } |
| 48 | if position.size >= 0 and regime == -1 and used != -1 { |
| 49 | order.market("S", side.short) |
| 50 | exit.bracket("S exit", entry = "S", stop = close + stop_k * a) |
| 51 | used := -1 |
| 52 | } |
| 53 | if (position.side > 0 and pb < exit_c) or (position.side < 0 and prb < exit_c) { exit.close_all() } |
| 54 | risk.max_drawdown(30) |
| 55 | render.background(pb > conf ? color.translucent(color.emerald.500, 92) : prb > conf ? color.translucent(color.rose.500, 92) : na) |
| 56 | render.line(ta.ema(close, len), "Regime mean", color = pb > prb ? color.emerald.300 : color.rose.300, width = 2) |
| 57 | persist t = draw.table.create(anchor.top_right, 5, 2) |
| 58 | if bar.is_last { |
| 59 | pr.heading(t, 2, "Regime Probability Allocator", "Strategy · softmax regime model") |
| 60 | pr.row(t, 2, "Bull probability", str.format("{:.0f} %", pb), pr.BULL) |
| 61 | pr.row(t, 3, "Bear probability", str.format("{:.0f} %", prb), pr.BEAR) |
| 62 | pr.row(t, 4, "Allocation", position.side > 0 ? "Long" : position.side < 0 ? "Short" : "Cash", color.white) |
| 63 | } |
| 64 |
Reviews
No reviews yet. Be the first to review this listing.