Skip to content

Commit fb4c471

Browse files
committed
docs: add frozen regime trend v1 specification
1 parent 3124fa8 commit fb4c471

1 file changed

Lines changed: 279 additions & 0 deletions

File tree

research/regime-trend-v1/spec.md

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
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

Comments
 (0)