Add S/R v2 research and validation harness
This commit is contained in:
@@ -13,14 +13,24 @@ net-positive is the open question, tracked below.
|
||||
|
||||
## 1. How the levels are built today
|
||||
|
||||
`app/services/sr_service.py::detect_sr_levels`, over **all stored history**
|
||||
(`query_ohlcv` with no date range — 5 years / ~1260 daily bars per ticker):
|
||||
> **Update (2026-07-12 detector rewrite):** several gaps below were addressed in
|
||||
> `sr_service` / `indicator_service` — close-bin VP, local-peak HVN, POC/VAH/VAL
|
||||
> as candidates, LVN dropped from S/R, pivot prominence + lookbacks, rejection-
|
||||
> weighted recency strength, ATR-adaptive merge, hard cap, round numbers. The
|
||||
> table documents the *pre-rewrite* failure modes measured on the snapshot; keep
|
||||
> it for historical context. Re-measure density on prod after deploy if gate
|
||||
> rates shift.
|
||||
|
||||
1. Candidates = volume-profile **HVN and LVN** bins + **pivot** swing highs/lows.
|
||||
2. Strength = share of bars that "touched" the level, scaled so ~20% of bars → 100.
|
||||
3. Nearby levels merged within 0.5%; tagged `support` if below spot, else `resistance`.
|
||||
`app/services/sr_service.py::detect_sr_levels` (post-rewrite):
|
||||
|
||||
### Where that departs from best practice
|
||||
1. Candidates = VP **POC / VAH / VAL / local HVN peaks** (lookback 252) +
|
||||
**prominent** swing pivots (lookback 504) + nearby **round numbers**.
|
||||
2. Strength = rejection-weighted touches on last 252 bars with recency decay
|
||||
(pass-throughs down-weighted); method base + confluence on merge.
|
||||
3. Nearby levels merged with **ATR-adaptive** tolerance (clamped ~0.4–1.5%);
|
||||
capped (~16, interleaved S/R); tagged `support` if below spot, else `resistance`.
|
||||
|
||||
### Where the pre-rewrite detector departed from best practice
|
||||
|
||||
Measured on `backtest_snapshots/prod.sqlite` (AAPL, 1261 bars, spot $308.63):
|
||||
|
||||
@@ -35,8 +45,8 @@ Measured on `backtest_snapshots/prod.sqlite` (AAPL, 1261 bars, spot $308.63):
|
||||
| **Round-number levels absent** — the mechanism with the best empirical support ([Osler 2000](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=888805)). | not implemented |
|
||||
|
||||
Not a defect: the pivot `window=2` is the standard 5-bar Williams fractal. What it
|
||||
lacks is a **prominence filter** — AAPL yields 338 pivots over 1261 bars, one every
|
||||
~3.7 bars.
|
||||
lacked pre-rewrite is a **prominence filter** — AAPL yielded 338 pivots over 1261
|
||||
bars, one every ~3.7 bars.
|
||||
|
||||
### The structural problem: resistance famine
|
||||
|
||||
@@ -383,6 +393,35 @@ Note `--allow-spawn` is required on Windows: `_mp_context()` has no `fork`/
|
||||
large, consistent across five nested windows — and still didn't survive a holdout.
|
||||
Nested lookbacks are not out-of-sample. Split by entry date before believing anything.
|
||||
|
||||
## 7. S/R v2 research harness (implementation started 2026-07-12)
|
||||
|
||||
The detector rewrite is decomposed into causal, research-only arms. The live
|
||||
scanner does not read `BACKTEST_SR_VARIANT`; these switches exist only in the
|
||||
offline snapshot harness:
|
||||
|
||||
| arm | behavior |
|
||||
|---|---|
|
||||
| `production_control` | deployed detector plus legacy 1.5 primary selection |
|
||||
| `rr_aligned_control` | deployed detector; primary selection uses activation `min_rr` |
|
||||
| `rewrite` | rewritten detector with activation-aligned primary selection |
|
||||
| `soft_zones` | rewrite plus max-strength/confluence zone aggregation |
|
||||
| `confirmed_rounds` | soft zones; standalone rounds need two rejection clusters |
|
||||
| `gate_v2` | confirmed rounds plus uncapped gate evidence |
|
||||
|
||||
Detector evidence (`sources`, rejection count, last rejection age) stays in the
|
||||
pure backtest objects. It is deliberately not migrated into the production DB
|
||||
schema until a variant passes validation.
|
||||
|
||||
Run the training matrix with `--entry-end 2024-06-30 --sr-audit`, choose one arm,
|
||||
and record that lock before running exactly control and the locked arm with
|
||||
`--entry-start 2024-07-01`. Use `scripts/compare_sr_variants.py` to produce the
|
||||
paired cohort CSV and summary JSON.
|
||||
|
||||
The post-2024 interval has informed earlier research, so this is validation rather
|
||||
than a pristine holdout; do not sweep variants on it. No deployment follows
|
||||
automatically. A lower validation Sharpe or higher drawdown remains a no-ship
|
||||
result even when CAGR rises.
|
||||
|
||||
**Next runs, if picked back up:**
|
||||
|
||||
- A **per-name target model** for clear-air setups instead of a constant k×ATR. This
|
||||
|
||||
Reference in New Issue
Block a user