|
| 1 | +# Regime Trend v1 — Frozen Strategy Specification |
| 2 | + |
| 3 | +Status: **Frozen pilot specification** |
| 4 | + |
| 5 | +Strategy ID: `regime-trend-v1` |
| 6 | + |
| 7 | +Purpose: Test whether a simple, cost-aware, long-only trend-following system on liquid crypto spot markets shows a robust positive historical edge under the PineForge validation protocol. |
| 8 | + |
| 9 | +This specification defines the strategy. Code must follow this document; this document must not be rewritten to match code or backtest results. |
| 10 | + |
| 11 | +## 1. Approved market universe |
| 12 | + |
| 13 | +Pilot symbols: |
| 14 | + |
| 15 | +- BTCUSDT spot |
| 16 | +- ETHUSDT spot |
| 17 | +- BNBUSDT spot |
| 18 | + |
| 19 | +Exchange data source: Binance spot OHLCV. |
| 20 | + |
| 21 | +Base timeframe: 4 hours. |
| 22 | + |
| 23 | +Timezone: UTC. |
| 24 | + |
| 25 | +No short positions, leverage, funding, borrowing or liquidation logic. |
| 26 | + |
| 27 | +## 2. Indicators |
| 28 | + |
| 29 | +All indicators use completed 4-hour candles only. |
| 30 | + |
| 31 | +### 2.1 Trend direction |
| 32 | + |
| 33 | +- Fast EMA length: 50 |
| 34 | +- Slow EMA length: 200 |
| 35 | + |
| 36 | +Trend regime is bullish when both are true at the close of signal candle `t`: |
| 37 | + |
| 38 | +1. `EMA50[t] > EMA200[t]` |
| 39 | +2. `close[t] > EMA200[t]` |
| 40 | + |
| 41 | +Otherwise the market is not in the bullish regime. |
| 42 | + |
| 43 | +### 2.2 Breakout trigger |
| 44 | + |
| 45 | +- Donchian lookback: 20 completed candles |
| 46 | +- The breakout level at signal candle `t` is the highest high from candles `t-20` through `t-1`. |
| 47 | +- The current candle must not be included in the breakout level. |
| 48 | + |
| 49 | +A breakout occurs when: |
| 50 | + |
| 51 | +`close[t] > highest(high[t-20:t-1])` |
| 52 | + |
| 53 | +### 2.3 Volatility |
| 54 | + |
| 55 | +- ATR length: 14 |
| 56 | +- ATR definition: Wilder RMA true range, equivalent to TradingView `ta.atr(14)` after warm-up. |
| 57 | + |
| 58 | +ATR is measured on signal candle `t` and frozen for the new trade. |
| 59 | + |
| 60 | +### 2.4 Volatility floor |
| 61 | + |
| 62 | +The normalized ATR on signal candle `t` is: |
| 63 | + |
| 64 | +`ATR14[t] / close[t]` |
| 65 | + |
| 66 | +A new position is allowed only when normalized ATR is at least `0.005` (0.50%). |
| 67 | + |
| 68 | +This is intended to avoid entries whose expected movement is too small relative to trading costs. |
| 69 | + |
| 70 | +## 3. Entry rule |
| 71 | + |
| 72 | +A LONG signal occurs at the close of candle `t` only when all conditions are true: |
| 73 | + |
| 74 | +1. All indicators are fully warmed up. |
| 75 | +2. No position is open. |
| 76 | +3. Bullish trend regime is true. |
| 77 | +4. Breakout trigger is true. |
| 78 | +5. Normalized ATR is at least 0.50%. |
| 79 | + |
| 80 | +The order is filled at the next candle open, candle `t+1`. |
| 81 | + |
| 82 | +Entry slippage for a buy is adverse: |
| 83 | + |
| 84 | +`entry_fill = open[t+1] * (1 + 0.0005)` |
| 85 | + |
| 86 | +Entry commission: |
| 87 | + |
| 88 | +`entry_fee = entry_fill * quantity * 0.001` |
| 89 | + |
| 90 | +No order is created if candle `t+1` is missing. |
| 91 | + |
| 92 | +## 4. Position sizing |
| 93 | + |
| 94 | +Initial research uses normalized one-unit exposure rather than compounding portfolio risk. |
| 95 | + |
| 96 | +For each trade: |
| 97 | + |
| 98 | +- quantity = `1 / entry_fill` |
| 99 | +- gross entry notional is approximately 1 quote-currency unit before slippage and fee. |
| 100 | + |
| 101 | +This keeps percentage returns comparable across assets and prevents equity compounding from hiding strategy behavior. |
| 102 | + |
| 103 | +Portfolio aggregation may sum normalized trade returns but must also report each symbol separately. |
| 104 | + |
| 105 | +## 5. Initial stop |
| 106 | + |
| 107 | +Frozen signal ATR: |
| 108 | + |
| 109 | +`entry_atr = ATR14[t]` |
| 110 | + |
| 111 | +Initial stop distance: |
| 112 | + |
| 113 | +`2.5 * entry_atr` |
| 114 | + |
| 115 | +Initial stop price: |
| 116 | + |
| 117 | +`initial_stop = entry_fill - 2.5 * entry_atr` |
| 118 | + |
| 119 | +The stop is fixed from the entry fill and must never move downward. |
| 120 | + |
| 121 | +## 6. Trailing stop |
| 122 | + |
| 123 | +After entry, calculate a candidate trailing stop at the close of each completed candle `u`: |
| 124 | + |
| 125 | +`candidate_stop[u] = highest_close_since_entry[u] - 3.0 * ATR14[u]` |
| 126 | + |
| 127 | +where `highest_close_since_entry[u]` includes completed closes from the entry candle through candle `u`. |
| 128 | + |
| 129 | +The active stop after candle `u` closes is: |
| 130 | + |
| 131 | +`active_stop[u] = max(previous_active_stop, candidate_stop[u])` |
| 132 | + |
| 133 | +Rules: |
| 134 | + |
| 135 | +- The stop can only stay unchanged or move upward. |
| 136 | +- It may not move downward when ATR expands. |
| 137 | +- A stop update calculated from candle `u` becomes effective starting with candle `u+1`. |
| 138 | +- The entry candle uses the initial stop only; no close-derived trailing update is allowed before that candle closes. |
| 139 | + |
| 140 | +## 7. Trend exit |
| 141 | + |
| 142 | +A trend-exit signal occurs at the close of candle `t` when: |
| 143 | + |
| 144 | +`close[t] < EMA50[t]` |
| 145 | + |
| 146 | +If a position is open and the stop has not already exited the trade during candle `t`, the trend-exit order is filled at the next candle open `t+1`. |
| 147 | + |
| 148 | +Sell slippage is adverse: |
| 149 | + |
| 150 | +`trend_exit_fill = open[t+1] * (1 - 0.0005)` |
| 151 | + |
| 152 | +If candle `t+1` is missing, the trade remains open and must be marked unresolved at dataset end. |
| 153 | + |
| 154 | +## 8. Stop execution using OHLC data |
| 155 | + |
| 156 | +For a candle with an active stop known before the candle opens: |
| 157 | + |
| 158 | +1. If `open <= active_stop`, the stop gaps through and fills at `open * (1 - 0.0005)`. |
| 159 | +2. Otherwise, if `low <= active_stop`, it fills at `active_stop * (1 - 0.0005)`. |
| 160 | +3. Otherwise, no stop exit occurs on that candle. |
| 161 | + |
| 162 | +A stop exit takes precedence over any trend-exit signal calculated at that candle close. |
| 163 | + |
| 164 | +There is no profit target in v1. |
| 165 | + |
| 166 | +## 9. Same-candle and ordering rules |
| 167 | + |
| 168 | +- Entry orders fill at next-bar open; therefore the signal candle cannot also stop out the new trade. |
| 169 | +- On an entry candle, the initial stop is active immediately after the entry fill. |
| 170 | +- If the entry candle opens below the computed initial stop, use the conservative immediate exit model: enter at adverse buy fill, then exit at adverse sell fill based on the same open. This event must be flagged in the ledger. |
| 171 | +- If a stop is touched during a candle, that exit wins over a trend-exit signal at the close. |
| 172 | +- No re-entry is allowed on the same candle as an exit. |
| 173 | +- A new signal may be evaluated only at a later completed candle while flat. |
| 174 | + |
| 175 | +## 10. Fees and net PnL |
| 176 | + |
| 177 | +Exit commission: |
| 178 | + |
| 179 | +`exit_fee = exit_fill * quantity * 0.001` |
| 180 | + |
| 181 | +Gross PnL: |
| 182 | + |
| 183 | +`gross_pnl = (exit_fill - entry_fill) * quantity` |
| 184 | + |
| 185 | +Net PnL: |
| 186 | + |
| 187 | +`net_pnl = gross_pnl - entry_fee - exit_fee` |
| 188 | + |
| 189 | +Trade return on entry notional: |
| 190 | + |
| 191 | +`net_return = net_pnl / (entry_fill * quantity)` |
| 192 | + |
| 193 | +All reports must include gross PnL, both fees, slippage-adjusted fills and net PnL. |
| 194 | + |
| 195 | +## 11. End-of-data handling |
| 196 | + |
| 197 | +An open position at the end of a partition is not silently closed at the final close. |
| 198 | + |
| 199 | +It must be reported as an unresolved open trade and excluded from closed-trade performance metrics. Exposure and unrealized PnL may be reported separately. |
| 200 | + |
| 201 | +Partitions must not leak state into one another for headline metrics. Each partition begins with indicator warm-up history but with no inherited open position. |
| 202 | + |
| 203 | +## 12. Required trade-ledger fields |
| 204 | + |
| 205 | +Every closed trade must contain: |
| 206 | + |
| 207 | +- strategy_id |
| 208 | +- implementation_version |
| 209 | +- dataset_hash |
| 210 | +- symbol |
| 211 | +- timeframe |
| 212 | +- direction |
| 213 | +- signal_timestamp |
| 214 | +- entry_timestamp |
| 215 | +- raw_entry_open |
| 216 | +- entry_fill |
| 217 | +- entry_atr |
| 218 | +- initial_stop |
| 219 | +- exit_timestamp |
| 220 | +- raw_exit_reference |
| 221 | +- exit_fill |
| 222 | +- exit_reason (`initial_stop`, `trailing_stop`, `trend_exit`, `immediate_entry_stop`) |
| 223 | +- quantity |
| 224 | +- entry_fee |
| 225 | +- exit_fee |
| 226 | +- gross_pnl |
| 227 | +- net_pnl |
| 228 | +- net_return |
| 229 | +- bars_held |
| 230 | +- immediate_entry_stop_flag |
| 231 | + |
| 232 | +## 13. Synthetic fixtures required before market data |
| 233 | + |
| 234 | +At minimum: |
| 235 | + |
| 236 | +1. Valid bullish-regime breakout enters on next open. |
| 237 | +2. Breakout without bullish regime produces no trade. |
| 238 | +3. Bullish regime without breakout produces no trade. |
| 239 | +4. Breakout rejected below normalized ATR floor. |
| 240 | +5. Current candle high is excluded from Donchian calculation. |
| 241 | +6. Duplicate breakout while long produces no second entry. |
| 242 | +7. Initial stop is frozen from signal ATR. |
| 243 | +8. Rising trailing stop never moves downward after ATR expansion. |
| 244 | +9. Gap below stop fills at adverse next-candle open. |
| 245 | +10. Intrabar stop touch fills at stop minus sell slippage. |
| 246 | +11. Trend exit fills at next open. |
| 247 | +12. Stop during candle overrides trend exit at close. |
| 248 | +13. Commission and slippage arithmetic matches a hand-calculated trade. |
| 249 | +14. Truncated history produces identical earlier signals. |
| 250 | +15. Prepended warm-up data does not alter stable-period signals. |
| 251 | + |
| 252 | +## 14. Parameters frozen for v1 |
| 253 | + |
| 254 | +- EMA fast: 50 |
| 255 | +- EMA slow: 200 |
| 256 | +- Donchian lookback: 20 |
| 257 | +- ATR length: 14 |
| 258 | +- normalized ATR floor: 0.50% |
| 259 | +- initial stop ATR multiple: 2.5 |
| 260 | +- trailing stop ATR multiple: 3.0 |
| 261 | +- commission: 0.10% per side |
| 262 | +- slippage: 0.05% per side |
| 263 | +- timeframe: 4h |
| 264 | +- direction: long only |
| 265 | + |
| 266 | +These parameters may not be optimized after the final holdout is opened. Any change creates `regime-trend-v2`. |
| 267 | + |
| 268 | +## 15. Classification rule |
| 269 | + |
| 270 | +This version is not considered useful because its code compiles or because development data is profitable. |
| 271 | + |
| 272 | +It becomes a Paper Candidate only after: |
| 273 | + |
| 274 | +- synthetic correctness passes, |
| 275 | +- Python/Pine trade parity passes, |
| 276 | +- lookahead and recursive-stability checks pass, |
| 277 | +- validation and final-holdout results satisfy `research/validation-protocol-v1.md`. |
| 278 | + |
| 279 | +If correctly implemented v1 fails those performance gates, v1 stops. Its parameters will not be repeatedly tuned against the final holdout. |
0 commit comments