Honor custom S/R tolerance as a transient detect, refresh levels after OHLCV
mutations without failing committed price writes, report per-ticker S/R
rebuild failures from admin cleanup, and warn in the admin UI when refresh is partial.
min_rr = 2.0 was hand-set in Admin (2026-06-24) and never swept — the gate
ablation only tested the floor on-vs-off, never its level. It was the last
un-swept knob in the live gate.
Swept against portfolio Sharpe under the real exit, with a parity self-check
(reproduces_production_gate: the row at the live floor must rebuild production's
exact 1,089-setup qualified set — it does).
min_rr qualified in-sample Sh/CAGR OOS Sh/CAGR (entries >= 2024-07)
0.0 6636 1.98 / 58.5% 2.02 / 66.2%
1.2 3897 1.34 / 33.9% 1.12 / 28.8%
1.5 3127 1.20 / 29.6% 1.12 / 28.8%
1.75 1974 1.64 / 44.5% 1.15 / 27.4%
2.0 (live) 1089 2.04 / 50.4% 2.78 / 73.3%
2.25 577 1.64 / 31.8% 1.71 / 31.9%
2.5 286 1.67 / 29.0% 0.68 / 8.7%
KEEP 2.0. It is the optimum in both windows, and a peak that reproduces in data
it was never fitted to is real evidence. But treat it as fragile: unlike the ATR
trail (a plateau), this is a spike with a trough beside it — +/-0.25 costs ~0.4
Sharpe in-sample and ~1.6 out-of-sample — and the curve is bimodal (floor-off is
good, 1.2-1.75 is bad, 2.0 is good). The hand-set value landed on the peak by
luck, not by tuning. Do not nudge it.
Worth knowing: turning the floor OFF entirely is the second-best row in both
windows, with substantially higher CAGR (58.5% / 66.2%) and more trades. If CAGR
ever outranks Sharpe here, "no R:R floor" is a live option — and it would sever
the gate's last dependency on the weak S/R detector.
Also fixes a metric artifact in the holdout harness. The train book's equity curve
ran to the end of the data while its entries stopped at the split, so it sat in
flat cash for two years and deflated its own CAGR/Sharpe (reported 0.95 / 14.6%;
actually 1.31 / 29.6%). _simulate_portfolio now truncates the calendar to
hold_days after the last entry when end_date is set — it only triggers on the
holdout train window, so no other number moves. The clear-air OOS verdict is
unaffected: it rests on the test row, whose entries and curve both start at the
split and were always clean. Both holdout reports regenerated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
The baseline table and promotion evidence still carried pre-primary-target-floor
figures. Re-derived every number from the 2026-07-11 run, the first baseline
measured after the 20% probability floor pruned lottery targets (1,428 -> 1,089
qualified).
The promotion evidence table also claimed the promoted book beat legacy on
"CAGR, Sharpe, and drawdown". That no longer holds: legacy residual 80 + hold
now has the shallowest drawdown (-15.8% vs -21.4%). Production still wins on
Sharpe, so the promotion stands, but the text now says so honestly rather than
implying a clean sweep.
Also documents the primary-target reach-probability floor in the gate
description, which shipped in c7a198b/8f41143 but never reached the README.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Record every tested-and-confirmed knob (ATR trail, regime overlay, lookback,
cutoff x book, sizing, FIP tie-breaker) so the sweep is not repeated on the
same snapshot, including the inverse-vol mis-attribution warning and the
universe-level fip_id lead. Prune the done items from the next-experiments
list.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The portfolio monitor's Production row now replays the live qualification
flag and the Admin exit policy (mode/ATR multiplier/hold days) instead of a
frozen research-variant gate, so Admin tuning is reflected in the next run.
Single-source the 80/20 strategy_rank weights in momentum_service and pin
every dual-defined constant with a parity test. Behavior-preserving today:
the production sim reproduces the README baseline exactly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follow-ups from review of the Track Record slim:
- BacktestPanel: drop the stale "tracking check" sentence from the "How this is
measured" explainer — that check moved to the maintenance disclosure last
commit, so it no longer describes anything in this block.
- MyTradesPanel: rename the two identically-labelled "Exit" columns to "Exit Px"
(exit price) and "Reason" (close_reason) so they're not confusable.
- README: add "Reading a local backtest report" under Local Backtest Snapshots —
a section->decision map for reports/backtest-*.json. The strategy-tuning tables
removed from the deployed page (sweep, gate_ablation, time_exit_sweep,
signal_eval, strategy_variants) now live only in the local report, so this
keeps "research lives local" from meaning the decision knowledge evaporates.
tsc -b && vite build pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backtest report now includes research-only hold-to-horizon portfolio variants comparing raw vs residual 12-1 momentum, cutoff 80 vs 90, max 10 vs 15 positions, and SPY-200 risk scaling. A dynamic research recommendation panel flags residual momentum, cutoff 90, or regime scaling only when transparent promotion rules pass.
Adds signal_context_snapshots with migration 016 and captures one point-in-time context row per newly generated TradeSetup: setup fields, composite/dimensions, latest sentiment, latest fundamentals, and strategy_version=momentum_12_1_rr_time_v1. This is forward-only; no historical sentiment/fundamental backfill is attempted.
No live gate, paper-trade exit, or production ranking behavior changes.
Verification: 458 backend tests pass, ruff check app/ clean, frontend npm run build clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Production strategy change based on the July 2026 backtest: paper trades now default to a 30-trading-day hold with the initial stop (classic momentum hold-and-rerank), while target and trailing exits remain available in Admin. The exit policy API/UI now carries hold_days and close_reason can be 'time'.
The activation confidence floor default is now 0/off because the gate ablation showed it added no per-trade edge while filtering out usable setups. Migration 015 clears stored activation_min_confidence and paper_exit_mode so the new defaults take effect; this intentionally resets Track Record comparability from this deploy.
Verification: 451 backend tests pass, ruff check app/ clean, frontend npm run build clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds the validated-vs-not verdict table, the iron rule for strategy
changes, ranked next experiments, a maintainer guide (invariants, file
map, verification, roadmap), and corrects the deploy docs: deploys are
automated by Gitea Actions (push to main = deploy), service is
signalplatform.service at /opt/signalplatform.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Add "How It Works": daily load (ordered pipeline steps), intraday flow,
other jobs, and the score -> activation gate -> top pick chain.
- Add "Key Use Cases" (find today's best long setup; track a paper trade).
- Fix stale facts: user-curated (not auto) watchlist, actual routes/pages,
scheduler description, wrong env defaults (RR 3.0->1.5, fundamentals
daily->weekly).
- Add missing surface: paper trading, activation gate, market regime, Telegram
alerts, backtest; API groups (paper-trades, market/regime, jobs); FRED +
Telegram env vars; note that pipeline timing is admin-cron, not env.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>