178 lines
8.8 KiB
Markdown
178 lines
8.8 KiB
Markdown
# Post-stop re-entry: daily policy study and production decision
|
||
|
||
## Decision
|
||
|
||
Use a **normal gate reset** after an initial-stop exit:
|
||
|
||
1. The initial stop always closes the trade. It is never cancelled because the
|
||
ticker still passes the gate.
|
||
2. Re-entry remains locked until a later full-universe daily scan observes the
|
||
ticker **failing** the production activation gate.
|
||
3. The lock remains in place until a subsequent daily scan observes a **fresh
|
||
qualification**.
|
||
4. Only then may the ticker return to the actionable setup list or be opened
|
||
through `create_trade`.
|
||
|
||
Trailing-stop, time, target, and manual exits do not start this state machine.
|
||
Scanner errors do not count as a gate failure. The two transitions are persisted
|
||
on the latest initial-stop `PaperTrade`, so neither a service call nor a restart
|
||
can bypass the rule.
|
||
|
||
Migration 022 applies the policy prospectively. Existing initial-stop rows are
|
||
grandfathered by marking both reset timestamps complete at their historical
|
||
`closed_at`; otherwise their new NULL columns would be mistaken for active
|
||
locks despite no scanner observations having existed. At runtime, only the
|
||
actual latest closed trade per ticker can start a lock, and only when that exit
|
||
was an initial stop. A newer trailing, time, target, or manual exit therefore
|
||
cannot revive an older stop episode.
|
||
|
||
This replaces the previously proposed fixed five-session lockdown. The normal
|
||
reset counts an unqualified stop-day close when that close is observed after the
|
||
stop. The stricter experiment, which required a failed close on a later session,
|
||
was not promoted.
|
||
|
||
## Experiment design
|
||
|
||
Source: [`reports/daily_reentry_matrix.json`](../../reports/daily_reentry_matrix.json),
|
||
generated 2026-07-17.
|
||
|
||
| Input | Value |
|
||
|---|---|
|
||
| Snapshot | Production SQLite snapshot through 2026-07-02 |
|
||
| Period used by the all/5y rows | 2022-06-24 to 2026-07-02 |
|
||
| Tickers | 505 |
|
||
| Point-in-time candidate observations | 1,011,248 (492,850 long; 518,398 short) |
|
||
| Live-universe rank observations | 584,393 |
|
||
| Qualified candidates under `live_universe` ranking | 5,189 |
|
||
| Entry cadence | Daily |
|
||
| Selection and ordering | Production GTL gate; residual/high-vol 80/20 rank; long-only after ranking |
|
||
| Exit | 1.5× ATR initial stop; 3× ATR trailing stop; 30-session maximum hold |
|
||
| Portfolio | 10 positions; 1% risk per trade; $10,000 initial capital |
|
||
| Trading cost | 0.1% per side in the primary matrix; 0.1–0.3% robustness sweep |
|
||
| Holdout split | 2025-01-01 |
|
||
|
||
The expensive daily candidate replay was performed once. Every policy arm then
|
||
used the same candidates, prices, costs, position sizing, capacity, and exit
|
||
logic. `live_universe` ranks all eligible tickers once per session like the live
|
||
scanner. `backtest_legacy` retains the older candidate-only rank approximation as
|
||
a sensitivity check.
|
||
|
||
### Policies tested
|
||
|
||
| Arm | Rule after an initial stop |
|
||
|---|---|
|
||
| `immediate` | No memory; a same-day close re-entry is possible |
|
||
| `next_session` | Block only the stop session |
|
||
| `cooldown_2/3/5` | Re-entry allowed at wait-session N |
|
||
| `gate_reset` | Require a failed gate observation, then a later qualification; the stop-day close may establish the failure |
|
||
| `strict_gate_reset` | Ignore the stop-day failure; require a later failed close and then requalification |
|
||
| `gate_reset_improved` | Gate reset plus a higher new stop and non-weaker production rank |
|
||
| `two_session_confirmation` | Require two consecutive qualified post-stop closes |
|
||
|
||
## Primary result: production-like `live_universe` ranking
|
||
|
||
The available history is shorter than five years, so the report's `5y` and
|
||
`all` rows cover the same period.
|
||
|
||
| Policy | Total return | CAGR | Max DD | Sharpe | Trades | Win rate | Post-stop re-entries |
|
||
|---|---:|---:|---:|---:|---:|---:|---:|
|
||
| Immediate | 348.4% | 45.2% | 24.3% | 1.67 | 489 | 35.6% | 155 |
|
||
| Next session | 388.1% | 48.3% | 21.6% | 1.77 | 472 | 36.2% | 142 |
|
||
| Cooldown 2 | 343.5% | 44.8% | 23.4% | 1.68 | 472 | 35.8% | 146 |
|
||
| Cooldown 3 | 293.4% | 40.6% | 22.7% | 1.56 | 474 | 35.9% | 146 |
|
||
| Cooldown 5 | 250.8% | 36.6% | 22.2% | 1.47 | 473 | 35.9% | 145 |
|
||
| **Gate reset** | **388.1%** | **48.3%** | **21.6%** | **1.77** | **472** | **36.2%** | **142** |
|
||
| Strict gate reset | 342.7% | 44.8% | 23.4% | 1.68 | 471 | 35.9% | 144 |
|
||
| Gate reset + improved setup | 267.4% | 38.2% | 24.9% | 1.60 | 422 | 36.3% | 69 |
|
||
| Two-session confirmation | 296.1% | 40.8% | **17.6%** | 1.65 | 441 | **37.9%** | 96 |
|
||
|
||
At the production capacity, normal gate reset improved all four portfolio
|
||
objectives relative to immediate re-entry: higher total return, CAGR, and
|
||
Sharpe, with lower drawdown. The fixed five-session rule reduced churn but gave
|
||
up too many profitable re-entry opportunities.
|
||
|
||
`gate_reset` and `next_session` produced exactly the same executed portfolio in
|
||
the `live_universe` runs. Their rules are not equivalent. In this sample, the
|
||
portfolio-level candidate path happened to converge to the same trades. This is
|
||
evidence that blocking same-day re-entry helped; it does **not** isolate an
|
||
independent return premium for the reset condition itself.
|
||
|
||
## Disjoint 2025+ test window
|
||
|
||
These are separate books with entries on or after 2025-01-01. They are a useful
|
||
temporal sensitivity check, but not forward evidence: the policy was still
|
||
selected after the historical data existed.
|
||
|
||
| Policy | Total return | CAGR | Max DD | Sharpe | Trades |
|
||
|---|---:|---:|---:|---:|---:|
|
||
| Immediate | 64.1% | 39.3% | 19.6% | 1.55 | 181 |
|
||
| Next session | 68.5% | 41.8% | 19.2% | 1.66 | 183 |
|
||
| **Gate reset** | **68.5%** | **41.8%** | **19.2%** | **1.66** | **183** |
|
||
| Cooldown 5 | 52.7% | 32.7% | 19.8% | 1.43 | 175 |
|
||
| Strict gate reset | 52.9% | 32.9% | 21.0% | 1.38 | 181 |
|
||
| Two-session confirmation | 35.4% | 22.5% | **18.1%** | 1.02 | 183 |
|
||
|
||
The gate-reset result did not depend solely on the earlier training period: it
|
||
also beat immediate and the fixed five-session rule in the disjoint test book.
|
||
|
||
## Cost and capacity sensitivity
|
||
|
||
At the production capacity of 10, gate reset remained ahead of both immediate
|
||
and cooldown 5 as costs increased.
|
||
|
||
| Cost per side | Policy | Total return | CAGR | Max DD | Sharpe |
|
||
|---:|---|---:|---:|---:|---:|
|
||
| 0.1% | Immediate | 348.4% | 45.2% | 24.3% | 1.67 |
|
||
| 0.1% | **Gate reset** | **388.1%** | **48.3%** | **21.6%** | **1.77** |
|
||
| 0.1% | Cooldown 5 | 250.8% | 36.6% | 22.2% | 1.47 |
|
||
| 0.2% | Immediate | 296.3% | 40.8% | 25.2% | 1.54 |
|
||
| 0.2% | **Gate reset** | **333.0%** | **44.0%** | **22.9%** | **1.64** |
|
||
| 0.2% | Cooldown 5 | 209.9% | 32.5% | 23.4% | 1.33 |
|
||
| 0.3% | Immediate | 249.8% | 36.5% | 26.0% | 1.41 |
|
||
| 0.3% | **Gate reset** | **284.0%** | **39.7%** | **24.2%** | **1.51** |
|
||
| 0.3% | Cooldown 5 | 164.0% | 27.3% | 24.7% | 1.16 |
|
||
|
||
The capacity sweep is a real limitation, not a footnote:
|
||
|
||
| Capacity at 0.1% cost | Immediate Sharpe / CAGR / DD | Gate-reset Sharpe / CAGR / DD | Cooldown-5 Sharpe / CAGR / DD |
|
||
|---:|---|---|---|
|
||
| 5 | 1.33 / 31.9% / 16.8% | 1.37 / 32.8% / 17.5% | **1.46 / 35.8% / 18.3%** |
|
||
| **10 (production)** | 1.67 / 45.2% / 24.3% | **1.77 / 48.3% / 21.6%** | 1.47 / 36.6% / 22.2% |
|
||
| 15 | **1.66 / 44.8% / 24.3%** | 1.63 / 43.0% / **21.6%** | 1.33 / 32.8% / 22.2% |
|
||
|
||
The promotion is therefore specific to the actual 10-position production book.
|
||
At capacity 5, cooldown 5 ranked best; at capacity 15, immediate had slightly
|
||
higher return and Sharpe while gate reset retained the shallower drawdown. Do
|
||
not generalize the chosen rule to a differently sized portfolio without rerunning
|
||
the matrix.
|
||
|
||
## Legacy-rank sensitivity
|
||
|
||
The older candidate-only ranking approximation also favored normal gate reset
|
||
over immediate and cooldown 5, although `next_session` was slightly stronger.
|
||
|
||
| Policy | Total return | CAGR | Max DD | Sharpe | Trades |
|
||
|---|---:|---:|---:|---:|---:|
|
||
| Immediate | 357.4% | 45.9% | 17.9% | 1.73 | 480 |
|
||
| Next session | **421.5%** | **50.8%** | 18.5% | **1.86** | 466 |
|
||
| **Gate reset** | 408.3% | 49.8% | 18.3% | 1.84 | 464 |
|
||
| Cooldown 5 | 332.3% | 43.9% | 19.6% | 1.71 | 459 |
|
||
| Strict gate reset | 351.3% | 45.5% | 20.4% | 1.72 | 457 |
|
||
|
||
## Why gate reset was promoted
|
||
|
||
- It is tied to a new signal episode instead of an arbitrary elapsed time.
|
||
- At the production capacity, it beat immediate and five-session cooldown on
|
||
return, CAGR, drawdown, and Sharpe.
|
||
- The advantage survived costs of 0.2% and 0.3% per side and the disjoint 2025+
|
||
test book.
|
||
- It avoids cancelling a valid stop: the loss and transaction costs are always
|
||
realized before any later trade.
|
||
- It avoids the extra filters that weakened strict reset, improved-setup reset,
|
||
and two-close confirmation.
|
||
|
||
The correct interpretation is deliberately modest: **normal gate reset is the
|
||
best production rule among the tested policies for the current 10-position
|
||
book.** It is not proof that gate reset is a universal source of alpha. Forward
|
||
paper-trade monitoring is still the only genuinely new evidence.
|