Commit Graph
2 Commits
Author SHA1 Message Date
dennisthiessenandClaude Opus 4.8 906d1db7d1 Docs: state the actual strategy, add an end-to-end diagram, add a research log
The README opened with "find the path of least resistance, key S/R zones, and
asymmetric R:R setups" — a description of a strategy we do not run. What we run
is a long-only cross-sectional momentum book with a trailing exit. The S/R
engine, the composite score, sentiment and fundamentals are screening and
display; none has a measured edge.

- Rewrites the intro/philosophy around the real strategy, and says plainly what
  is NOT the edge.
- Adds a mermaid decision graph, universe -> qualified -> ranked -> opened ->
  closed, with the real exit distribution on the terminal nodes: initial stop 45%,
  trailing stop 31%, max hold 24%, S/R target 0%. Validated against the mermaid
  parser, not eyeballed.
- Documents that the R:R and touch-probability are GATE INPUTS, not forecasts of
  the trade — the single easiest way to misread this app.
- Adds win rate, best/worst R and the exit-reason split to the production
  baseline table.
- New docs/research/README.md: every strategy tested, the result, the decision,
  and why we stay with the current one. 12 rejected ideas (take-profit exits,
  clear-air gate relaxation, EV gate, regime overlay, inverse-vol sizing, shorts,
  standalone vol, FIP, ...), the confirmed tuning knobs, the open leads, and the
  method rules we learned the hard way (nested lookbacks are not out-of-sample; a
  rising win rate is a warning, not a win).
- Documents the research flags and the holdout harness, and warns that the
  portfolio_monitor lookbacks are nested windows, NOT a holdout.
- Notes the snapshot must copy paper_% settings or it silently diverges from prod.

All baseline numbers re-verified against reports/backtest-20260711-prod-baseline.json
(506 tickers, 1,089 qualified, CAGR 50.4%, +413.8% vs SPY +95.7%, DD -21.4%,
Sharpe 2.04, 320 trades, 15.3d avg hold, and all five promotion contenders). No
corrections were needed — the numbers were right, the framing was not.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 15:40:34 +02:00
dennisthiessenandClaude Opus 4.8 85b3ef618f Research: S/R levels, the target exit, and the entry gate
Investigated whether our support/resistance detection follows best practice
and whether we actually use it that way. Three findings, all backed by runs
against the prod snapshot and written up in docs/research/sr-levels-and-exits.md:

- The S/R target must NOT become an exit. Honoring it as a take-profit on top
  of the 3x ATR trail drops Sharpe 2.04 -> 1.47 and halves CAGR. Win rate rises
  (37.5% -> 40.0%), which is the tell: it truncates the right tail where
  momentum's edge lives.
- The clear-air fallback (synthesize a 3xATR target where no resistance exists,
  so 52-week-high breakouts stop being vetoed) looked strictly better in-sample
  (Sharpe 2.04 -> 2.07, CAGR 50.4% -> 62.3%, DD 21.4% -> 20.1%) but FAILED a
  real out-of-sample holdout: on entries after 2024-07-01 it is worse on Sharpe
  (2.78 -> 2.45) and Calmar, better only on raw CAGR. Not shipped.
- The detector itself is weak vs best practice (POC/VAH/VAL computed then
  discarded, HVN = any above-mean bin, 1.48x volume double-counting, "touch"
  counts pass-throughs, no round numbers), but its only causal path to P&L is
  the entry gate. Fix it for the displayed levels, not for returns.

Method note: nested lookback windows are NOT out-of-sample. The in-sample result
was clean, large, and consistent across five windows, and still did not survive
a proper entry-date split.

All research paths are off by default and the default report is unchanged:
  BACKTEST_RESEARCH_EXITS=1        take-profit exit rows
  BACKTEST_ATR_TARGET_FALLBACK=k   synthetic k*ATR target when S/R offers none
  BACKTEST_FALLBACK_CLEAR_AIR_ONLY=1  restrict that to genuinely clear air
  BACKTEST_HOLDOUT_SPLIT=YYYY-MM-DD   train/test split by entry date

Also fixes two reproducibility holes found while reconciling our local baseline
against the live report:

- create_backtest_snapshot.py now copies paper_% settings. The production
  monitor row replays the runtime exit policy via get_exit_policy(); without
  those keys a snapshot silently falls back to code defaults, so a live-tuned
  exit would never be reflected.
- Migration 020 drops activation_min_expected_value and
  activation_min_target_probability. Both are orphans of the June EV-gate
  redesign, read by no code path, but prod carries min_target_probability = 50.0
  which implies a probability floor that is not enforced (the real floor is the
  20% constant in qualification.py).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 15:05:34 +02:00