From 37ff5b383dc2bfb75ac604c2718604f3644b1af8 Mon Sep 17 00:00:00 2001 From: Harwinder Sekhon Date: Fri, 14 Aug 2026 20:41:54 -0400 Subject: [PATCH] signal_log: persist agent panel verdict + per-persona takes to SQLite Add panel_verdict, panel_confidence, panel_rationale, panel_takes_json columns to the signals table (additive, idempotent ALTER TABLE migration for existing DBs). _report_row now reads the panel fields attach_panel writes onto the SignalReport, so LLM panel verdicts stop evaporating on process exit. Also documents the Oanda re-pin (round_trip_cost stays $0.30 for cross-book comparability and the live TP gate; $0.65 is the measured headline) and adds the feed-divergence / parity / shadow-scan study tooling referenced by CLAUDE.md. --- CLAUDE.md | 11 +- config.py | 11 +- docs/user_guide.html | 18 +-- providers/tiingo.py | 2 + scripts/compare_oanda_tiingo.py | 116 ++++++++++++++ scripts/feed_divergence_study.py | 259 +++++++++++++++++++++++++++++++ scripts/shadow_scan.py | 194 +++++++++++++++++++++++ scripts/signal_parity_study.py | 246 +++++++++++++++++++++++++++++ signal_log.py | 36 ++++- 9 files changed, 874 insertions(+), 19 deletions(-) create mode 100644 scripts/compare_oanda_tiingo.py create mode 100644 scripts/feed_divergence_study.py create mode 100644 scripts/shadow_scan.py create mode 100644 scripts/signal_parity_study.py diff --git a/CLAUDE.md b/CLAUDE.md index eeb74bd..d0ff9c2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -69,7 +69,7 @@ Signal currency everywhere is `SignalStrength` (−2..+2). DataFrames are UTC tz ## Rules for making changes (read before editing signal logic) -1. **Never change a tuned value without re-validation.** Acceptance rule: positive total R in BOTH train and validation halves of a ≥12-month window, PF ≥ 1.3, at realistic cost (XAU $0.30 round trip), trailing exits, next-open fills. Marginal edges must additionally pass the 2024-06→2025-03 out-of-sample window — within-year splits alone have approved configs that later failed OOS. +1. **Never change a tuned value without re-validation.** Acceptance rule: positive total R in BOTH train and validation halves of a ≥12-month window, PF ≥ 1.3, at realistic cost (XAU $0.65 round trip headline; retain $0.30 for TD-era cross-book comparability), trailing exits, next-open fills. `round_trip_cost` stays $0.30 because it also drives the live TP spread gate; changing it is a separate rule-1 event. Marginal edges must additionally pass the 2024-06→2025-03 out-of-sample window — within-year splits alone have approved configs that later failed OOS. 2. **Per-timeframe overrides live in the pair factory**, never in global defaults — the same knob has opposite effects on different TFs (proven repeatedly: `tp_floor_rr`, hour-9 block, trail params). Document validation evidence in the factory docstring. 3. **Pair isolation is a hard invariant.** XAU gates in the aggregator are display-name-gated so a future pair port cannot inherit gold-calibrated logic by accident. 4. **Live == backtest parity.** If you add a live gate, add it to the replay path in the same commit; all time filters evaluate bar-close time in both paths. @@ -81,12 +81,15 @@ Signal currency everywhere is `SignalStrength` (−2..+2). DataFrames are UTC tz ## 2026-08-04 QA audit — owner decisions ledger -- **Weekend calendar: FIXED (owner-approved 2026-08-04).** All three `_is_forex_weekend` copies are NY-anchored (Fri 17:00 → Sun 18:00 ET; during US DST that is Fri 21:00 UTC — measured on 5yr of Oanda bars). Kills the weekly false-"STALE DATA/feed lagging" hours. Book impact, fully accounted: M15 byte-identical; M5 12mo dropped exactly ONE trade — a phantom whose signal fired on the final summer-Friday bar (close 21:00 UTC) and "filled" at Sunday's reopen 49 h later (−1.08R, live-impossible). M5 12mo reference at HEAD: 555 trades, +98.64R PF≈1.50 @ $0.65 (was 556/+97.56/1.48). A Module 21 test sweeps all three copies hourly across both DST transitions. +- **Weekend calendar: FIXED (owner-approved 2026-08-04).** All three `_is_forex_weekend` copies are NY-anchored (Fri 17:00 → Sun 18:00 ET; during US DST that is Fri 21:00 UTC — measured on 5yr of Oanda bars). Kills the weekly false-"STALE DATA/feed lagging" hours. Book impact at the audit HEAD: M15 byte-identical; M5 12mo dropped exactly ONE trade — a phantom whose signal fired on the final summer-Friday bar (close 21:00 UTC) and "filled" at Sunday's reopen 49 h later (−1.08R, live-impossible), leaving 555 trades / +98.64R / PF≈1.50 @ $0.65 (was 556/+97.56/1.48). The current-HEAD canonical reference is recorded below. A Module 21 test sweeps all three copies hourly across both DST transitions. - **Spread in exit-trigger detection (rule 6): owner DECLINED 2026-08-04.** Backtest stop triggers stay on raw mid High/Low; the measured optimism (~4–6% of total R: −3.55R @ $0.30, −4.24R @ $0.65 on the M15 12mo book) is accepted and books stay comparable. Re-open only as a conscious re-pin campaign. - **`FB2_EMA_LO`: HARDENED 2026-08-04 (delegated).** Research override for the EMA200-proximity band, default = tuned 0.5; an unparseable value now degrades to the default with a warning instead of crashing every scan. Documented here — it is a knob that exists. - **H4 seeding divergence: parked.** Live H4 fetches only 380 bars vs the backtest's unbounded history — ~2% of sampled H4 bars flip an indicator signal (composite Δ up to 12.3). M5/M15/H1 clean at their real fetch depths. Fold into any future H4 campaign; H4 remains "unproven for auto-execution". -## Current state notes (2026-07-30) +## Current state notes (2026-08-14) -- Oanda v20 is the live feed (`data_providers.active: "oanda"`), but the pinned backtest books are still Twelve-Data-pinned and the backtest cost assumption is $0.30 while measured real spreads are ~$0.65–0.72 — re-pin books on Oanda bars before treating feed-switch comparisons as valid (see Oanda/TD divergence study in memory). +- Oanda v20 is the live feed (`data_providers.active: "oanda"`). The 2026-08-04 re-pin made the 27 `backtest/oanda_*.csv` books the baseline; all TD-era books are superseded. Current-HEAD M5 canonical book: `backtest/oanda_m5_12mo_065_nopb_20260814.csv`, +106.82R PF 1.51 at $0.65 (both halves positive; PF 1.46 / 1.55). M15 reference: +73.93R PF 1.53. See `backtest/research/repin_verification_2026-08-14.md`. +- Cost reporting is dual: $0.65 is the measured-Oanda realistic headline ($0.65-$0.72 round trip), while $0.30 remains for cross-book comparability and as the live TP spread-gate input. Raising `round_trip_cost` from $0.30 would move the TP floor from about $9 to $19.50 and requires full rule-1 revalidation. +- Twelve Data is signal-incompatible with Oanda (Phase 1: about 19% M5 bar-direction disagreement and a systematic ~$1 high bias; see `backtest/research/feed_divergence_2026-08-14.md`). On an Oanda candle outage, halt auto-execution rather than switching to TD candles. +- Tiingo is streaming-only (`data_providers.streaming: "tiingo"`), not a designated candle fallback. Oanda-Tiingo signal parity is documented in `backtest/research/signal_parity_2026-08-14.md`; Phase 4's two-week live shadow scan remains a manual operational step. - Human-facing docs in `docs/` (`user_guide.html`, `beginner_guide.html` + PDF builds) must be kept in sync when signal behavior changes. diff --git a/config.py b/config.py index c62b369..335026b 100755 --- a/config.py +++ b/config.py @@ -31,8 +31,10 @@ class SignalStrength(Enum): XAUUSD = "XAU/USD" # price_precision: decimals for SL/TP rounding and display. -# default_spread: round-trip cost per trade in price units, charged by -# the backtester when --spread is not given. +# default_spread: $0.30 round-trip cost retained for TD-era cross-book +# comparability and used when the backtester receives no --spread override. +# Oanda's measured round trip is $0.65-$0.72; research reports headline it +# separately with --spread 0.65. PAIR_INFO = { XAUUSD: {"display": "XAU/USD", "pip_value": 0.10, "price_precision": 2, "default_spread": 0.30}, @@ -110,7 +112,10 @@ class SignalConfig: tp_tightening_factor: float = 1.0 # ── Trade geometry ──────────────────────────────────────────── - # Round-trip transaction cost estimate in price units (XAU ~$0.30). + # Deliberately $0.30 for TD-era cross-book comparability. Oanda's measured + # round trip is $0.65-$0.72, reported separately in re-pin campaigns. + # This is also a LIVE gate input: increasing it to $0.65 raises the TP1 + # floor from about $9 to $19.50, so it requires rule-1 revalidation. round_trip_cost: float = 0.30 # Spread gate: reject setups whose TP1 distance is below # round_trip_cost × this multiple (caps cost at ~3% of target). diff --git a/docs/user_guide.html b/docs/user_guide.html index 8cb4e74..ddc7078 100644 --- a/docs/user_guide.html +++ b/docs/user_guide.html @@ -84,16 +84,16 @@

4 · Choosing your timeframe

-

Twelve-month backtest (Jul 2025 – Jul 2026, real spreads, entry at next candle open):

+

Twelve-month Oanda-candle backtest (Aug 2025 – Aug 2026, $0.65 round-trip cost, entry at next candle open):

- - - - - - - + + + + + + +
M5M15H1
Trades / week~10~9.5~3
Total result (12 mo)+135.6R+67.2R+49.9R
Win rate / profit factor59.7% / 1.8155.8% / 1.4059.4% / 1.94
Typical (median) hold2.4 h6 h12.5 h
90% of trades close within16 h40 h3.7 days
Typical stop distance~$19~$29~$44
Worst drawdown11.2R9.4R9.5R
Trades / week~11.3~7.6~2.7
Total result (12 mo)+106.8R+73.9R+24.0R
Win rate / profit factor52.9% / 1.5162.2% / 1.5360.9% / 1.55
Typical (median) hold2.4 h7 h15.5 h
90% of trades close within10.5 h29.8 h3.2 days
Typical stop distance~$21~$32~$52
Worst drawdown10.7R10.8R8.0R