Document Gate Target Ladder architecture

This commit is contained in:
2026-07-13 11:47:23 +02:00
parent 3ffd13ce6e
commit dc1570877c
4 changed files with 144 additions and 35 deletions
+13 -9
View File
@@ -9,7 +9,8 @@ was run and the data said no.** Detail lives in the linked docs and in
cross-sectional momentum book** — buy the top quintile by beta-adjusted 12-1
momentum, tilt toward higher volatility, hold ≤ 10 names, cut at 1.5× ATR, then
trail at 3× ATR for up to 30 trading days. Everything else in the app (composite
score, S/R levels, sentiment, fundamentals) is **display or screening**, not edge.
score, Structural S/R, the Gate Target Ladder, sentiment, fundamentals) is
**display or screening**, not edge.
---
@@ -22,6 +23,8 @@ score, S/R levels, sentiment, fundamentals) is **display or screening**, not edg
| 1.5× ATR initial stop | Real exit | Cuts losers fast |
| 3× ATR trailing stop, 30-day max hold | Real exit | Best Sharpe of every exit tested |
| Max 10 concurrent positions, 1% risk per trade | Sizing | Cap never binds in practice |
| Structural S/R | Human-facing product context | Clean, capped zones for charts and alerts; not read by the scanner |
| Gate Target Ladder | Screening machinery | Volume-free transient proposals preserve the production candidate set exactly; never an exit |
---
@@ -29,7 +32,7 @@ score, S/R levels, sentiment, fundamentals) is **display or screening**, not edg
| # | Experiment | Result | Decision | Evidence |
|---|---|---|---|---|
| 1 | **S/R target as a take-profit** (exit at the target, with or without the trail) | Sharpe **2.04 → 1.47**, CAGR halved (50.4% → 28.9%). Win rate *rose* (37.5% → 40.0%) — the tell: it truncates the right tail | **Rejected.** The target must never become an exit | [sr-levels-and-exits.md](sr-levels-and-exits.md) · `backtest-20260712-sr-target-exit.json` |
| 1 | **Gate target as a take-profit** (exit at the target, with or without the trail) | Sharpe **2.04 → 1.47**, CAGR halved (50.4% → 28.9%). Win rate *rose* (37.5% → 40.0%) — the tell: it truncates the right tail | **Rejected.** The target must never become an exit | [sr-levels-and-exits.md](sr-levels-and-exits.md) · `backtest-20260712-sr-target-exit.json` |
| 2 | **Clear-air fallback** — synthesize a 3× ATR target so 52-week-high breakouts stop being vetoed by "no resistance above" | Looked *strictly better* in-sample (Sharpe 2.07, CAGR 62.3%, DD 20.1%) but **failed a real out-of-sample holdout**: Sharpe 2.78 → 2.45, higher drawdown | **Rejected.** Gate stays as-is | [sr-levels-and-exits.md](sr-levels-and-exits.md) · `backtest-20260712-holdout-*.json` |
| 3 | **Blanket S/R fallback** (any missing target, not just clear air) | Sharpe 1.82, per-setup expectancy 0.583 → 0.280 R | **Rejected.** 65% of what it admitted were ATR/R:R filter misses, which are actively bad | [sr-levels-and-exits.md](sr-levels-and-exits.md) |
| 4 | **Expected-value gate** (`min_expected_value` replacing the R:R + probability pair) | Structurally favoured distant lottery targets; selected *worse*-than-random setups | **Removed June 2026.** Settings dropped in migration 020 | migration 009, 020 |
@@ -57,6 +60,7 @@ invites overfitting.
| Selection cutoff {70…90} × book size {10, 15, 20} | **Keep 80 × 10** — monotonically worse in both directions |
| Position sizing (equal-weight, inverse-vol, risk-% sweep) | **Keep 1% fixed-fractional** |
| Primary-target probability floor | **Keep 20%** — pruned lottery targets, 1,428 → 1,089 qualified, lifted Sharpe |
| Primary-target R:R selector | **Keep 1.5** — target choice is intentionally independent of the later 2.0 activation floor |
| Exit policy (hold / SMA50 / 20-day low / technical-40 / ATR trail) | **Keep 3× ATR trail** — best Sharpe (2.04) |
| **Activation R:R floor `min_rr`** (swept 2026-07-12) | **Keep 2.0** — best in-sample *and* out-of-sample. But it is a **spike, not a plateau** — see below |
@@ -105,7 +109,6 @@ and it would also sever the last dependency the *gate* has on the weak S/R detec
| **Broader universe** (`nasdaq_all`) | Strengthens every week's cross-section and the IC t-stat | Also where `fip_id` could become tradeable |
| **Forward paper-trade record** | The only true out-of-sample evidence the snapshot cannot give | Time |
| **Better target model for clear-air names** | The return is demonstrably there (#2 wins on raw CAGR in *both* train and test); it's the *flat* 3× ATR target that makes it too expensive in risk | Needs a per-name model, not a constant k×ATR |
| **S/R detector quality** | POC/VAH/VAL computed then discarded; HVN = "any above-mean bin"; volume double-counted 1.48×; "touch" counts pass-throughs; no round numbers | Worth fixing for the levels users *see* — but it does **not** reach P&L, so don't justify it on returns |
---
@@ -133,11 +136,12 @@ out-of-sample, or turned out to be measuring something other than what it claime
What's left is a boring, well-documented result: **cross-sectional momentum works;
the machinery around it mostly doesn't.**
The S/R engine, the composite score, the sentiment and fundamentals dimensions are
all still in the product — they make the app legible and are useful context for a
human — but none of them has a measured edge, and the platform is honest about
that in the UI (see the exit plan and base-rate panels on every setup card). The
one component that *does* have an edge is the momentum gate, and every knob on it
has been swept and confirmed.
Structural S/R, the composite score, sentiment and fundamentals remain useful
human context but have no measured edge. The Gate Target Ladder is different:
it is internal screening machinery whose broad historical-price-traffic behavior
was preserved explicitly and volume-free, with exact full-period parity. It is
still neither market structure nor an exit. The one component that *does* have
measured predictive edge is the momentum gate, and every knob on it has been
swept and confirmed.
The next real evidence is **forward**, not backward: the live paper-trade record.
+60 -4
View File
@@ -4,10 +4,14 @@
**Question that started it:** are our support/resistance levels built the way best
practice says they should be, and do we actually use them that way?
Short answer: the detector is weak against best practice, but its reach into P&L
runs entirely through the **entry gate** — not the exit. Honoring the target as a
take-profit was tested and is decisively worse. Whether the S/R-derived gate is
net-positive is the open question, tracked below.
Final answer: one level model should not serve two different jobs. The clean
**Structural S/R** detector now supplies persisted chart and alert structure.
The transient **Gate Target Ladder** preserves the broad historical-price
traffic proposals that the setup screen depends on. Its headline target affects
entry qualification only; honoring it as a take-profit is decisively worse.
The final volume-free implementation reproduced the production candidate set
and portfolio exactly. The sections below retain the investigation that led to
that split.
---
@@ -690,6 +694,58 @@ and LVN bins, whose union is the complete 20-bin price-range grid, then adds
unfiltered pivots and touch strength. For the gate this behaves as a broad
target-proposal ladder, not human-facing support/resistance.
**Component name: Gate Target Ladder (GTL).** "Structural S/R" names the
separate, persisted human-facing model. "Gate Target Ladder" names this
transient screening component and avoids implying that its dense proposals are
real support/resistance.
#### Runtime decision flow
```mermaid
flowchart TD
O["Ticker OHLCV history"] --> STRUCT["Structural S/R<br/>clean detector"]
STRUCT --> STORE[("Persist SRLevel")]
STORE --> HUMAN["Charts and alerts"]
O --> LADDER["Gate Target Ladder<br/>20 range centers + 5-bar pivots"]
LADDER --> SCORE["Count historical price traffic<br/>strength + 0.5% merge + side tag"]
SCORE --> SCAN{"Directional proposal<br/>with R:R ≥ 1.5?"}
SCAN -->|no| NOSETUP["No setup for that direction"]
SCAN -->|yes| ZONES["Cluster 2% target zones<br/>use reachable near edge"]
ZONES --> FILTER["ATR-distance filter<br/>retain up to 5 near-to-far candidates"]
FILTER --> PROB["Estimate target-before-stop<br/>reach probability"]
PROB --> PRIMARY["Headline = most likely candidate<br/>clearing R:R ≥ 1.5 and probability ≥ 20%"]
PRIMARY --> ACTIVATE{"Activation gate<br/>headline R:R ≥ 2.0<br/>probability ≥ 20%<br/>momentum/direction pass?"}
ACTIVATE -->|no| OBS["Store as unqualified observation"]
ACTIVATE -->|yes| QUAL["Eligible for production book"]
QUAL --> EXIT["ATR stop/trail or max hold<br/>target is never an exit"]
```
Step by step:
1. `scan_ticker` loads the ticker's OHLCV history and computes the 1.5× ATR
initial stop. It does not query persisted `SRLevel` rows for targets.
2. `detect_gate_target_ladder` creates 20 evenly spaced centers over the
observed low/high range and adds unfiltered five-bar swing highs/lows. The
implementation performs no volume calculation.
3. Each proposal is scored by the share of historical bars whose range crosses
it. Proposals within 0.5% are merged, their traffic strengths combine, and
they are tagged support/resistance relative to the latest close. The scanner
materializes them with negative transient IDs; they are never persisted.
4. A direction exists only when at least one proposal clears the scanner's 1.5
R:R floor. This is setup construction, not the later live activation gate.
5. The recommendation layer clusters proposals into 2% target zones, uses each
zone's reachable near edge, removes unsuitable ATR distances, and keeps up
to five candidates spanning near, moderate and far distances.
6. Each retained candidate gets a target-before-stop reach probability based on
distance, R:R, traffic strength and signal alignment.
7. The headline target is the most likely candidate clearing both R:R ≥ 1.5
and probability ≥ 20%. If none does, the most likely target overall remains
headline so a distant high-R:R lottery target cannot game qualification.
8. The separate live gate then requires headline R:R ≥ 2.0 and probability ≥
20%, plus the residual-momentum and direction rules. A traded setup still
exits only through the ATR stop/trail or maximum hold.
The `explicit_target_ladder` arm therefore replaces only the irrelevant volume
pass with the complete range grid. It retains pivots, touch strength, merge
geometry, primary selection, qualification, ranking, and exit behavior. Grid