news corpus for a local scorer + agent panel v2 + dashboard read-only (2026-09-17); books byte-identical
Agent panel v2: personas return p_win anchored to the book base rates with a code-computed decision context; verdict = equal-weight mean (verdict_source "mean"); only the macro persona runs live (agent_panel.personas ["macro"]); prompt version and exact payloads logged; offline replay harness scripts/panel_replay.py; base-rate table agent_panel_base_rates.json (scripts/build_panel_base_rates.py). Backtester `strategy` column now carries the generator's own stamp (label-only; five reference books re-pinned, all 62 other columns identical). News corpus (after evaluating the owner's ML-NEWS scikit model against DeepSeek: golden set 39/78 vs 78/78, out-of-sample agreement 64% against a 90% self-agreement ceiling; verdict: fallback only, not a replacement): - NewsSentiment.xau_score + archive column xau_score keep DeepSeek's gold score for every headline (930 of the first 1,546 DeepSeek rows had none); an existing newsdata.db gains the column in place on first open - headlines naming no tracked currency are scored and archived (currencies_json []) but never returned to the platform - _apply_llm_sentiment sends every new headline in its cycle, 25 per call; a failed call ends the cycle's sending Dashboard publisher never writes a database: main() calls app_config.set_db_writes_for_process(False), honoured by signal_log_enabled() and news_archive_enabled() (owner decision: the bot is the single writer). Test suite: the hermetic app config now points both writers at a suite-private temp dir — the RSS fixture tests were writing fixture headlines into the real logs/newsdata.db — with a Module 32 test pinning it. 529 tests.
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
# Agent panel v2 — probabilities anchored to base rates — 2026-09-17
|
||||
|
||||
**Why.** The live review of 2026-09-04 → 09-17 (`signal_log_review_2026-09-17.md`, §5 and §7.1)
|
||||
found the panel's verdict was tilted the wrong way: the macro persona's stance was the verdict,
|
||||
its only input was headlines (a one-day-lagging echo of price, `news_sentiment_value_2026-09-04.md`),
|
||||
opposed setups reached their first target more often than agreed ones (54% vs 42%), three of four
|
||||
personas voted the same way on nearly every setup (technical 79% support, risk 79% oppose,
|
||||
contrarian 65% oppose), and the stated confidence was uncalibrated. The chair had already been
|
||||
shown anti-informative on 2026-09-03. Nothing versioned the prompts, so no change could be measured.
|
||||
|
||||
**What shipped (code, all advisory-only; the panel still never runs inside
|
||||
`analyze_from_dataframes` and no gate reads it).**
|
||||
|
||||
| Piece | Where |
|
||||
|---|---|
|
||||
| Every persona returns `p_win` (0-100, the chance the trade closes profitably under its trailing exit) plus one `reason_for` and one `reason_against`; stance is derived symmetrically (≥ 60 support, ≤ 40 oppose) | `agent_panel.py` `_TAKE_CONTRACT`, `derive_stance`, `_validate_take` (v1 stance+confidence replies still accepted and mapped to a pseudo-probability) |
|
||||
| Verdict = equal-weight mean of the personas' `p_win`, quorum 3 of 4, no LLM aggregator (`verdict_source: "mean"`, the new default; `macro` and `chair` kept for comparison) | `mean_verdict`, `run_panel`, `app_config.py` |
|
||||
| A code-computed `context` block in every payload: stop / target in ATR and R, cost-to-risk, the class **base rate** from the validated books, prior move 4 h / 24 h in ATR, distance from the 24 h extreme and its age, `move_started_at`, largest bar of the last 3 in ATR, signal-bar body, event timing against the class's expected hold, penalty tags with the book's verdict on them | `_price_context`, `_base_rate`, `agent_panel_base_rates.json` (built by `scripts/build_panel_base_rates.py` from the MD5-verified books) |
|
||||
| Macro persona: no news doctrine; judges whether news is NEW relative to `move_started_at`; receives the ATR-normalised candles (as does the contrarian) | `_MACRO_SYSTEM`, `_panel_jobs` |
|
||||
| Technical persona: indicator agreement declared uninformative; judges higher-timeframe conflict and key levels. Risk: only setup-specific risks versus the class. Contrarian: the engine's own warnings are not evidence | `_TECH_SYSTEM`, `_RISK_SYSTEM`, `_CONTRARIAN_SYSTEM` |
|
||||
| `PANEL_PROMPT_VERSION` logged with every verdict and folded into the payload hash; per-persona probabilities and reasons, the exact per-persona payloads and the context logged (`panel_prompt_version`, `panel_probability`, `panel_probs_json`, `panel_payloads_json`, `panel_context_json`) | `signal_log.py` additive migration, `update_panel`, `log_panel_update` |
|
||||
| Live frames handed to the add-ons through `report._frames` in `analyze_pair` (never in the core) | `signal_aggregator.py` |
|
||||
| Plain-language "AI estimate" line on Telegram, CLI and dashboard; legacy sources render as before | `telegram_bot._panel_estimate_lines`, `main.py`, `static/dashboard.js` |
|
||||
| Scorecard: Brier, log-loss, calibration bands, discrimination, constant-voter rate, ρ(p, R), counterfactual books, split by prompt version | `analyze_signal_log.probability_scorecard` (printed by `--stored-candles`) |
|
||||
| Offline replay harness: rebuilds each persona's payload for every resolved logged setup (exact payloads when logged, else from the stored blobs, interned news and the kept Oanda cache, events evaluated as of the signal bar), runs the current prompts, scores them against the outcome and against the logged v1 takes and the base-rate predictor | `scripts/panel_replay.py` (`--dry-run`, `--max-calls`) |
|
||||
| Backtester export `strategy` tag fixed to the generator's own stamp (label-only; every gold ATR setup was exported as `GENERIC`) | `backtest/gpu_backtest.py`; books re-pinned, see below |
|
||||
|
||||
Tests: `test_all.py` Module 35 (15 tests) plus the extended Module 23 parity test; suite
|
||||
`RESULTS: 521 passed, 0 failed, 521 total`.
|
||||
|
||||
## Reference books re-pinned (label-only)
|
||||
|
||||
The five books were regenerated with the committed code (stashed) and with the fix, on the same
|
||||
cache. Dropping the `strategy` column, every book is byte-identical to its previous pin; trades, R
|
||||
and PF are unchanged. New labels: M15 W2 174 `XAU_ATR` / 757 `GENERIC`; M5 W2 32 / 411 / 338
|
||||
`XAU_CP`; M15 OOS 1 / 354; H1 W3 57 / 196; H4 W3 53 / 61.
|
||||
|
||||
| Book | old MD5 | new MD5 |
|
||||
|---|---|---|
|
||||
| M5 W2 | `29120a1ee32979431d062f210d41a9d1` | `49f8e602fc6ae769713c94ef7b257810` |
|
||||
| M15 W2 | `d185f099482a07f29502cb5a371a9bbf` | `b4aa07e33e17e23774c486a6900d673b` |
|
||||
| M15 OOS | `6f8f24b49597ced28f50a19e08c3472f` | `9fd624fb387c36052122bd1830cf9c32` |
|
||||
| H1 W3 | `3b45d12bade823178b267c13bc698458` | `7b848c917dcb5c371ecbb9f8f7292278` |
|
||||
| H4 W3 | `e75adae13c839b15736f69c0114e6aa5` | `186e677fbbd53cca735c94094c23ce05` |
|
||||
|
||||
`Backend: NumPy CPU fallback`, `GPU cache fallbacks: 0` on all ten runs.
|
||||
|
||||
## Base-rate table
|
||||
|
||||
`agent_panel_base_rates.json`: 45 classes (34 exact) from the relabelled M5 W2, M15 W2, H1 W3 and
|
||||
H4 W3 books; key `timeframe|strategy|grade|direction`, fallbacks `tf|*|*|direction` and `tf|*|*|*`;
|
||||
the exact class is used only with n ≥ 30. Examples: M15 all 931 trades win 60.5%, median hold 30
|
||||
bars; M15 SELL 296 / 54.4%; M15 `XAU_ATR` A SELL 78 / 50.0%, median hold 6 bars; M5 `XAU_CP` B
|
||||
BUY 321 / 51.7%; H1 all 253 / 64.4%.
|
||||
|
||||
## Pre-registered acceptance (from the approved plan)
|
||||
|
||||
On the resolved logged setups (37 today), a new prompt version ships only if: (1) no persona's
|
||||
modal stance is above 65%; (2) Brier ≤ the logged v1 takes and ≤ the base-rate-only predictor;
|
||||
(3) the skip-OPPOSE counterfactual does not remove a net-positive bucket. Outcome = advisory R > 0
|
||||
at $0.65. Predictors compared on the same events: base-rate only (the class win rate for every
|
||||
trade), the logged v1 takes (stance × confidence → pseudo-probability; 27 events carry them), and
|
||||
the new prompts run live through DeepSeek on the rebuilt payloads (4 calls per event).
|
||||
|
||||
## Replay round 1 (draft prompts)
|
||||
|
||||
| predictor | n | Brier | log-loss | mean p | modal stance | constant % | R skip ≤ 40 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| base-rate only | 37 | 0.263 | 0.719 | 54.8 | neutral | 81 | −7.15 (nothing skipped) |
|
||||
| v1 logged, mean | 27 | 0.270 | 0.738 | 48.2 | neutral | 48 | −4.00 |
|
||||
| v1 logged, macro | 27 | 0.299 | 0.855 | 56.5 | support | 44 | −2.82 |
|
||||
| v1 logged, technical | 27 | 0.371 | 1.011 | 71.7 | support | 78 | −6.47 |
|
||||
| v1 logged, risk | 27 | 0.343 | 0.947 | 25.7 | oppose | 78 | +0.03 |
|
||||
| v2 draft, mean | 37 | 0.257 | 0.707 | 51.3 | neutral | 95 | −7.15 (nothing skipped) |
|
||||
|
||||
Like-for-like on the 27 events with v1 takes: Brier v2 0.257, v1 mean 0.270, v1 macro 0.299,
|
||||
base rate 0.259, coin flip 0.250. Rank correlation of p with R: v2 −0.05, v1 mean +0.14, v1 macro
|
||||
+0.36, base rate +0.16 (n = 27; the ±0.35 confidence band swallows all of them).
|
||||
|
||||
Reading: the draft is calibrated (it sits 3.5 points under the base rate with a spread of 1.7
|
||||
points) and no longer directional, but it carries no rank information: winners averaged p = 50.9,
|
||||
losers 51.7. The old macro verdict had some ordering (+0.36) and terrible calibration (82%
|
||||
confidence on the three losing FOMC shorts); the new one has calibration and no ordering. Criterion
|
||||
(2) passes, (3) is vacuous (no OPPOSE issued), (1) fails **in the opposite sense to the one it was
|
||||
written for**: the personas cluster on neutral around the base rate instead of voting a constant
|
||||
direction. That is hedging, not bias.
|
||||
|
||||
**A flaw in the draft prompts, found from the per-event reasons.** The five lowest probabilities
|
||||
went to the Sep 10 and Sep 14 shorts that won (+1.31, +1.05, +0.70R), because the technical and
|
||||
contrarian prompts told the personas to lower p when "the move has already run far" or "a big
|
||||
candle just printed". That instruction encoded the live fortnight's pattern, which the two-year
|
||||
books contradict (stretched entries are the system's best trades, 2026-08-04; the big-candle gate
|
||||
was re-rejected in the review: those buckets are +32R and +60R). The final prompts remove that
|
||||
instruction, state the book's finding in the context legend and in both personas, and limit
|
||||
downward moves to higher-timeframe conflict, key levels, event timing inside the expected hold,
|
||||
news newer than the move, and a stop far wider than the class norm.
|
||||
|
||||
## Replay round 2 (final prompts, the text that ships)
|
||||
|
||||
Same 37 events, same rebuilt payloads, the final prompt text (the technical and contrarian
|
||||
personas told that a long prior move or a big candle is not a reason by itself; downward moves
|
||||
limited to higher-timeframe conflict, key levels, event timing, news newer than the move, and a
|
||||
stop far wider than the class norm).
|
||||
|
||||
| predictor | n | Brier | log-loss | mean p | modal stance | directional % | R skip ≤ 40 | R ≥ 60 only |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| base-rate only | 37 | 0.263 | 0.719 | 54.8 | neutral | 19 | −7.15 | −3.07 |
|
||||
| v1 logged, mean | 27 | 0.270 | 0.738 | 48.2 | neutral | 52 | −4.00 | −1.66 |
|
||||
| v1 logged, macro | 27 | 0.299 | 0.855 | 56.5 | support | 56 | −2.82 | −2.16 |
|
||||
| **v2 final, mean** | 37 | **0.262** | 0.717 | 53.8 | neutral | 8 | −7.15 | −1.98 |
|
||||
| v2 final, macro | 37 | 0.259 | 0.712 | 53.4 | neutral | 11 | | |
|
||||
| v2 final, technical | 37 | 0.270 | 0.734 | 54.2 | neutral | 16 | | |
|
||||
| v2 final, risk | 37 | 0.258 | 0.709 | 53.3 | neutral | 11 | | |
|
||||
| v2 final, contrarian | 37 | 0.262 | 0.718 | 54.1 | neutral | 11 | | |
|
||||
|
||||
Like-for-like on the 27 events with v1 takes: Brier v2 final 0.260, v1 mean 0.270, v1 macro
|
||||
0.299, base rate 0.259. Rank correlation of p with R: v2 final +0.13 (round 1 −0.05), v1 mean
|
||||
+0.14, v1 macro +0.36. Calibration of the v2 mean: 34 events in the 40–60 band averaged p = 53
|
||||
and won 47%; the 3 events at 60–61 won 1. The final personas sit 1.0 point under the base rate
|
||||
(sd 1.8, no event moved 5 points or more); winners averaged p = 53.1, losers 54.3.
|
||||
|
||||
Acceptance: (2) passes — Brier below the logged v1 takes and equal to the base-rate predictor
|
||||
(0.262 vs 0.263; 0.260 vs 0.259 on the common 27); (3) passes vacuously (no OPPOSE issued); (1)
|
||||
fails as written (92% neutral) and passes as re-specified below (directional share 8%). The
|
||||
correction removed the chase penalty: the winning Sep 10 / Sep 14 shorts moved from 45–47 to
|
||||
49–51, and the reasons against now name what the books do not already price (a release due in 20
|
||||
minutes, price sitting on a support level) instead of "the move already ran far".
|
||||
|
||||
Cost: 2 × 148 DeepSeek calls (both rounds), inside the shared daily cap of 500.
|
||||
|
||||
## Decision and what it means for the alert
|
||||
|
||||
The shipped verdict is a probability anchored to the validated base rate that moves only for
|
||||
facts the books do not already price. On this sample it is calibrated and uninformative: the line
|
||||
will usually read "about a 50% chance … (usual for this kind of setup: 55%)". That is the honest
|
||||
state of the evidence — the 65-feature sizing model was a clean null too — and it is strictly
|
||||
better than the previous line, which asserted 82% confidence in the wrong direction. The
|
||||
information the line adds is the base rate itself, the biggest concrete worry (event inside the
|
||||
hold, news newer than the move), and each persona's reason. It never gates; the user guide says
|
||||
so.
|
||||
|
||||
Re-specified criterion (1) for future prompt versions: the share of *directional* stances
|
||||
(support + oppose) on one side must not exceed 65% — neutral clustering around a calibrated base
|
||||
rate is not the pathology the criterion targets.
|
||||
|
||||
## Persona set (owner decision, same day)
|
||||
|
||||
The owner's rule: a persona that does not give correct guidance is removed, to save confusion,
|
||||
tokens and log space. Evidence per persona:
|
||||
|
||||
| persona | v1 (27 outcomes) | v2 final (37 outcomes) | verdict |
|
||||
|---|---|---|---|
|
||||
| macro | Brier 0.299, rank correlation with R **+0.36**, 88% / 25% win split on 2026-09-03 | Brier 0.259, ρ −0.06 | the only voice that ever showed ordering, and the only one holding facts the engine lacks (news) → **kept** |
|
||||
| technical | support on 79%, Brier 0.371 (worst) | Brier 0.270 (worst), ρ −0.20 | re-reads the indicators the signal was built from → removed |
|
||||
| risk | oppose on 79%, Brier 0.343 | Brier 0.258, ρ −0.02 | its inputs (stop in ATR, cost, event timing) are now computed in the context block → removed |
|
||||
| contrarian | oppose on 65%, Brier 0.322 | Brier 0.262, ρ −0.05 | oppose by construction, no information → removed |
|
||||
|
||||
Shipped as `agent_panel.personas` (default `["macro"]`; `app_config` validates the names, `chair`
|
||||
needs two or more, `macro` source needs the macro persona). One DeepSeek call per panel instead of
|
||||
four (three quarters of the panel's token spend), `panel_payloads_json` about 4 KB instead of about
|
||||
14 KB, `panel_takes_json` one entry, no persona votes line in the alert. The mean verdict with one
|
||||
persona is that persona's probability (quorum = min(3, personas)). The full panel remains one
|
||||
config line away for research replays (`scripts/panel_replay.py --personas macro,technical,risk,contrarian`).
|
||||
|
||||
## Next evaluation
|
||||
|
||||
- Every live v2 verdict logs its exact payloads, so `scripts/panel_replay.py` can re-score any
|
||||
future prompt on identical evidence. At 100 resolved v2 outcomes (about five weeks): the
|
||||
`--stored-candles` probability scorecard by prompt version. At 300: fit a probability-band →
|
||||
observed-win-rate table on the first half by time, verify on the second, ship it as a numpy
|
||||
lookup; only then revisit persona weights (owner rule).
|
||||
- Do not iterate prompts on the current 37 events again: any further gain there is in-sample.
|
||||
- Deployment: the live box needs the new code (both the bot and the dashboard daemon, which has
|
||||
run `2ac7301` since Sep 10); no config change is required (`verdict_source` defaults to
|
||||
`mean`); the additive migration runs on first open.
|
||||
|
||||
Commands: `venv/bin/python scripts/build_panel_base_rates.py --book 5min=<m5_w2.csv> --book
|
||||
15min=<m15_w2.csv> --book 1h=<h1_w3.csv> --book 4h=<h4_w3.csv> --out agent_panel_base_rates.json`;
|
||||
`venv/bin/python scripts/panel_replay.py --db logs/signals.db --dry-run`; `venv/bin/python
|
||||
scripts/panel_replay.py --db logs/signals.db --max-calls 160 --out replay.csv`;
|
||||
`venv/bin/python analyze_signal_log.py --db logs/signals.db --stored-candles`.
|
||||
@@ -0,0 +1,483 @@
|
||||
# Live signal-log review — 2026-09-17
|
||||
|
||||
**Source evidence:** `logs/signals.db` copied from the live server on 2026-09-17 (rows
|
||||
2026-09-04 00:59 → 2026-09-17 13:25 UTC; 5,487 rows, 5,481 `scan` + 6 `failed`, 0 `blocked`;
|
||||
telegram 3,458 / dashboard 2,029). Opened read-only. Cross-checked with
|
||||
`analyze_signal_log.py --parity | --scan-outcomes | --stored-candles` (all read-only), and with a
|
||||
live-vs-backtest parity replay of the same window through `backtest/gpu_backtest.py` at HEAD
|
||||
(`5521998`). No tuned value is proposed; this is a health check and a descriptive scorecard.
|
||||
|
||||
## Headline
|
||||
|
||||
1. **Live equals backtest.** Over 2026-09-06 → 2026-09-17 the validated code produced 29 trades;
|
||||
26 of them appear in the live log on the same bar with the same direction, grade and entry,
|
||||
and the live advisory R agrees with the backtest R to within 0.14 (mean difference −0.006 over
|
||||
23 resolved matches). The 3 backtest-only trades are the Sep 9 bot outage (2) and one M15 bar
|
||||
scanned live on Sep 8 with the pre-RSI-change M15 engine (1). All 20 live-only setups are
|
||||
consecutive-bar re-entries that fall inside the backtester's 5-bar entry cooldown.
|
||||
2. **The raw advisory book reads −7.15R over 37 resolved setups, but that number counts cluster
|
||||
re-entries the validated book never takes.** The like-for-like views are flat: cooldown-equivalent
|
||||
live book −1.62R over 25 resolved (PF 0.84); backtest over the same window +1.09R over 29 trades
|
||||
(M15 −0.32R / 13, M5 +2.43R / 15, H1 −1.01R / 1, H4 0). Against the two-year books, a 12–15 trade
|
||||
fortnight summing between −0.7R and +2.4R sits at the 25th–49th percentile: an ordinary fortnight.
|
||||
The 12 resolved cooldown re-entries alone cost −5.54R.
|
||||
3. **The market was a one-way bear fortnight with an FOMC hike in it:** 4,477 → 4,367 (−2.5%),
|
||||
low 4,235 on Sep 16, daily ranges of 12–30 ATR, then +95$ on Sep 17. Every directional statistic
|
||||
below is drift-adjusted against the same-timeframe mean move; the raw 24 h drift was −4.2 ATR on M5.
|
||||
4. **Direction vs market.** At 1–4 h the composite carried no information this fortnight (Spearman
|
||||
rank correlation of score with the 4 h move ≈ 0 on every timeframe). At 24 h it was *inversely*
|
||||
related to the move on all three timeframes (M5 ρ = −0.11, M15 −0.20, H1 −0.33, bootstrap CIs
|
||||
exclude zero, n = 1,734 / 570 / 150 unique scans): high scores marked bounce tops in the
|
||||
downtrend and deep negative scores marked lows that bounced. This is the same pattern the
|
||||
2026-09-08 review saw in 16 of 18 episodes, now with n. It is a two-week bear-market reading,
|
||||
not a verdict on the two-year edge, and it is the one hypothesis worth a proper in-book test.
|
||||
5. **AI panel.** 34 unique setups carried a panel (27 resolved). Skipping the macro persona's OPPOSE
|
||||
would have avoided 7 resolved trades worth −2.52R (kept book −2.82R vs −5.35R), but the same
|
||||
opposed trades moved *in the trade's favour* at 24 h (drift-adjusted hit 4/5) and 6 further
|
||||
OPPOSE verdicts are on the Sep 17 long cluster the backtester currently marks +1.13R. Technical
|
||||
(79% support), risk (79% oppose) and contrarian (65% oppose) are near-constant voters. Verdict
|
||||
confidence is uncalibrated (62% / 50% / 60% correct across the three bands). No evidence either
|
||||
way at this n; keep logging.
|
||||
6. **Delivery findings** (no book impact): the dashboard daemon has run stale code (`2ac7301`) since
|
||||
Sep 10 13:28 while the bot moved to `2836024` on Sep 14, and it was down from Sep 7 02:20 to
|
||||
Sep 10 13:28; the bot was down Sep 9 00:05 → 19:36 UTC (two validated trades missed, +0.37R);
|
||||
the live pipeline has no entry cooldown, so consecutive-bar setups are logged, scored and (about
|
||||
one in three) re-alerted; the backtester's CSV labels the gold ATR setups `GENERIC` while live
|
||||
stamps them `XAU_ATR` (geometry and R identical).
|
||||
|
||||
## Method
|
||||
|
||||
- Rows deduped to the first row per (timeframe, bar label); `bar_ts` NULL on 365 rows (354 from the
|
||||
pre-Sep-7 logging code) falls back to `indicators_json[tf].timestamp`; 11 rows with no indicators
|
||||
(price 0) dropped; `scan_kind in ('blocked','failed')` skipped. Unique bars: M5 2,289, M15 763,
|
||||
H1 191, H4 53.
|
||||
- Setups: 49 unique (M5 24, M15 24, H1 1, H4 0). Outcome = the DB's own advisory model
|
||||
(`advisory_r_multiple`, net R at $0.65, next-open entry, stop first, close-only trail): 37 RESOLVED
|
||||
(−7.15R, reproduced exactly), 11 PENDING (the Sep 17 long cluster), 1 UNRESOLVABLE.
|
||||
- Forward moves: `scan_outcomes` (`fwd_{1h,4h,24h}_atr`, + = up; 24 h only where `complete = 1`).
|
||||
"Move" = move in the signal's direction; "excess" = the same after subtracting the same-timeframe
|
||||
mean move over all scans (the drift); "adj hit" = share of excess > 0.
|
||||
- Three book views: (1) every unique setup; (2) cooldown-equivalent = after an accepted setup, skip
|
||||
the next 5 primary bars (the backtester's rule); (3) alerted = the bot's dedup replayed on the
|
||||
telegram rows (fingerprint (signal, direction) per timeframe; re-alert after 3,600 s, on a grade
|
||||
upgrade, or when the entry moved ≥ 0.5 × last risk; grade ≥ C; setup required; state reset at
|
||||
each restart = code-version change). View 3 is a reconstruction; `logs/telegram.log` on the live
|
||||
box is the ground truth.
|
||||
- Bootstrap null: the M15 and M5 two-year books regenerated offline from the kept cache with the
|
||||
section-9 harness (`--start 2024-09-05 --end 2026-09-05 --spread 0.65 --workers 12`), MD5s
|
||||
`d185f099482a07f29502cb5a371a9bbf` and `29120a1ee32979431d062f210d41a9d1` (both equal to the
|
||||
pinned values; `Backend: NumPy CPU fallback`, `GPU cache fallbacks: 0`); 20,000 fixed-n resamples
|
||||
of per-trade R plus every 13-calendar-day window of the book.
|
||||
- Parity replay: `venv/bin/python backtest/gpu_backtest.py --pair XAUUSD --spread 0.65 --workers 12
|
||||
--primary-tf {15min,5min,1h,4h} --start 2026-09-06 --export-csv ... --detail` (no `--end`, so the
|
||||
end is the run time; no `--set`). New cache windows, cited here and therefore kept:
|
||||
`oanda_XAU_USD_{5min,15min,1h}_20260706_20260917.parquet`,
|
||||
`oanda_XAU_USD_4h_20260115_20260917.parquet`, `oanda_XAU_USD_1d_20221106_20260917.parquet`.
|
||||
`Backend: NumPy CPU fallback`, `GPU cache fallbacks: 0` on all four runs. The fetch logged two
|
||||
interior gaps: M5/M15 2026-09-07 18:15–22:00 (Labor Day, Oanda published no bars — matches the 46
|
||||
stale-bar rows live logged) and H4 2026-04-02 → 04-05 (Good Friday). Matching key: (timeframe,
|
||||
backtest entry bar − 1 bar) == live bar label.
|
||||
- Nothing was written to `signals.db`; `scripts/backfill_signal_outcomes.py` and
|
||||
`scripts/label_scan_outcomes.py` were run with `--dry-run` only.
|
||||
|
||||
## 1. Integrity and coverage
|
||||
|
||||
| Check | Result |
|
||||
|---|---|
|
||||
| Surface parity (1,953 shared bars) | 0 signal, grade or setup-presence divergences; 8 score differences, none changing a signal or grade: 6 on H1/H4 bars scored by the two code versions (≤ 0.2 pts on H1, up to 7 pts on H4 at Sep 15 00:00: consistent with different confirmation-frame seeding), 2 on the dashboard's Sep 10 13:28 restart catch-up |
|
||||
| Code versions live | telegram: c44813f → de36b10 (Sep 7 15:08) → 3afc62c → 28b591d (Sep 8) → 2ac7301 (Sep 9 21:45) → **2836024 (Sep 14 01:46)**. dashboard: c44813f (26 rows, Sep 7 01:00–02:20), then **2ac7301 from Sep 10 13:28 to now** |
|
||||
| Dashboard daemon | down Sep 7 02:20 → Sep 10 13:28 (3.5 days); since then on stale code. Still logs 11 "Primary timeframe stale" M5 rows every day at 21:xx UTC (the settlement pause; a scheduled closure in 2836024) |
|
||||
| Telegram bot | down Sep 9 00:05 → 19:36 UTC. Cost: M15 BUY B Sep 9 05:45 (+0.23R) and M5 BUY A Sep 9 06:00 (+0.14R) in the backtest, never scanned live |
|
||||
| Labor Day (Sep 7) | Oanda published no bars 18:25–22:00 UTC (confirmed by the fresh fetch); 46 stale-bar rows logged; no holiday awareness (known) |
|
||||
| Failed scans | 6 rows at 06:11–06:17 UTC on Sep 15 and Sep 16, both surfaces, primary frame missing: an Oanda blip longer than the retry ladder's 45 s budget. 11 pre-ladder "data unavailable" rows on Sep 4/7 |
|
||||
| Scan-outcome labelling | 2,467 unique bars complete, 418 labelled but < 72 h old, 408 unlabelled and < 25 h old, 3 unlabelled and older. Last label 13:20 today: the labeler is healthy |
|
||||
| Blocked scans | none logged (`log_blocked_scans` off); the Monday 00:xx UTC hours are therefore empty by design |
|
||||
| Engine fingerprints | M15 `dab4d03725d8` → `536f84340ea0` at Sep 9 21:45 (RSI × 0.5). M5, H1, H4 unchanged all window |
|
||||
| Panel | 35 rows, ≤ 9 per day against the cap of 20, all cache MISS, all `verdict_source = macro` |
|
||||
|
||||
## 2. Market context
|
||||
|
||||
| UTC day | open | high | low | close | change $ | range / ATR |
|
||||
|---|---|---|---|---|---|---|
|
||||
| Sep 4 | 4,480 | 4,491 | 4,366 | 4,431 | −49 | 30 |
|
||||
| Sep 7 (Labor Day) | 4,424 | 4,430 | 4,381 | 4,423 | 0 | 13 |
|
||||
| Sep 8 | 4,423 | 4,443 | 4,345 | 4,350 | −73 | 20 |
|
||||
| Sep 9 (bot down) | 4,350 | 4,418 | 4,347 | 4,394 | +44 | 24 |
|
||||
| Sep 10 | 4,394 | 4,435 | 4,311 | 4,315 | −79 | 25 |
|
||||
| Sep 11 | 4,315 | 4,403 | 4,292 | 4,349 | +33 | 20 |
|
||||
| Sep 14 | 4,333 | 4,355 | 4,254 | 4,288 | −45 | 21 |
|
||||
| Sep 15 | 4,288 | 4,318 | 4,261 | 4,284 | −5 | 14 |
|
||||
| Sep 16 (FOMC hike 18:00) | 4,284 | 4,367 | 4,235 | 4,272 | −12 | 30 |
|
||||
| Sep 17 (to 13:20) | 4,272 | 4,381 | 4,267 | 4,367 | +95 | 23 |
|
||||
|
||||
Drift baseline (mean forward move over **all** unique scans, ATR units, + = up):
|
||||
|
||||
| tf | 1 h | 4 h | 24 h |
|
||||
|---|---|---|---|
|
||||
| M5 | −0.23 (n 1,992) | −0.63 (1,998) | −4.21 (1,734) |
|
||||
| M15 | −0.09 (661) | −0.36 (667) | −2.31 (570) |
|
||||
| H1 | −0.06 (161) | −0.22 (167) | −0.75 (150) |
|
||||
|
||||
## 3. Direction and score against the realised move (all unique scans)
|
||||
|
||||
Move is measured in the signal's direction; excess is after removing the drift above.
|
||||
|
||||
| tf | direction | n | 1 h move / excess | 4 h move / excess / hit | 24 h move / excess / adj hit |
|
||||
|---|---|---|---|---|---|
|
||||
| M5 | LONG | 18 | −1.10 / −0.87 | −1.27 / −0.64 / 39% | −6.83 / −2.62 / 47% |
|
||||
| M5 | SHORT | 66 | +0.35 / +0.12 | +0.14 / −0.49 / 53% | −1.13 / −5.34 / 31% |
|
||||
| M15 | LONG | 7 | −0.81 / −0.72 | −0.31 / +0.05 / 43% | −4.03 / −1.72 / 33% |
|
||||
| M15 | SHORT | 39 | +0.27 / +0.18 | +0.60 / +0.23 / 69% | −0.68 / −2.98 / 30% |
|
||||
| H1 | SHORT | 4 | −0.25 / −0.31 | −0.66 / −0.88 / 50% | −2.05 / −2.80 / 0% |
|
||||
|
||||
Reading: M15 shorts were right for about four hours (69% hit, +0.23 ATR excess) and wrong by the
|
||||
next day (the bear-trend lows they sold bounced). Longs were wrong at every horizon. Nothing here
|
||||
beats drift at 24 h.
|
||||
|
||||
Score buckets (direction = sign of score, includes NEUTRAL scans):
|
||||
|
||||
| tf | bucket | n | 4 h move / excess | 24 h move / excess / adj hit |
|
||||
|---|---|---|---|---|
|
||||
| M5 | ≥ 35 | 22 | −1.83 / −1.19 | −13.06 / −8.85 / 18% |
|
||||
| M5 | 25..35 | 47 | −1.11 / −0.48 | −9.61 / −5.40 / 28% |
|
||||
| M5 | −35..−25 | 101 | −0.95 / −1.58 | +0.11 / −4.10 / 31% |
|
||||
| M5 | ≤ −35 | 41 | −2.06 / −2.69 | −0.15 / −4.36 / 25% |
|
||||
| M15 | 15..25 | 56 | −0.68 / −0.31 | −5.15 / −2.85 / 35% |
|
||||
| M15 | 25..35 | 17 | −0.13 / +0.23 | −3.20 / −0.90 / 44% |
|
||||
| M15 | −35..−25 | 37 | +0.65 / +0.28 | +0.42 / −1.88 / 38% |
|
||||
| M15 | ≤ −35 | 24 | +0.47 / +0.10 | −0.98 / −3.28 / 29% |
|
||||
|
||||
Spearman rank correlation of the composite score with the forward move (+ would mean high score →
|
||||
price up), with bootstrap 95% CI:
|
||||
|
||||
| tf | 1 h | 4 h | 24 h |
|
||||
|---|---|---|---|
|
||||
| M5 (n ≈ 1,990 / 1,734) | −0.05 [−0.09, −0.01] | −0.03 [−0.07, +0.02] | **−0.11 [−0.15, −0.06]** |
|
||||
| M15 (n ≈ 665 / 570) | 0.00 [−0.08, +0.08] | −0.02 [−0.09, +0.06] | **−0.20 [−0.27, −0.12]** |
|
||||
| H1 (n ≈ 165 / 150) | −0.09 [−0.25, +0.06] | −0.08 [−0.24, +0.07] | **−0.33 [−0.47, −0.17]** |
|
||||
|
||||
Grades: M15 grade-A rows (n = 12) had a 24 h excess of −4.8 ATR and an adjusted hit of 17%; M5
|
||||
grade-B rows (n = 15) −1.9 ATR excess at 4 h, hit 20%. Gates: the only gate that removed A/B/C
|
||||
directional rows this fortnight was the spread gate on M5 (n = 10; 24 h excess +0.03 vs −5.33 for
|
||||
the shipped M5 setups): tiny and descriptive. The M15 engine change at Sep 9 21:45 leaves only 10
|
||||
directional rows before it; nothing can be said about it.
|
||||
|
||||
## 4. The trade book
|
||||
|
||||
View 1, every unique setup (advisory R at $0.65; PENDING excluded from R):
|
||||
|
||||
| cut | n | resolved | wins | sum R | mean R | PF |
|
||||
|---|---|---|---|---|---|---|
|
||||
| **all** | 49 | 37 | 17 (46%) | **−7.15** | −0.19 | 0.60 |
|
||||
| M5 | 24 | 14 | 6 | −1.08 | −0.08 | 0.83 |
|
||||
| M15 | 24 | 22 | 11 | −5.06 | −0.23 | 0.51 |
|
||||
| H1 | 1 | 1 | 0 | −1.01 | | |
|
||||
| BUY / SELL | 30 / 19 | 18 / 19 | 8 / 9 | −3.49 / −3.67 | −0.19 / −0.19 | 0.59 / 0.61 |
|
||||
| grade A / B / C | 27 / 19 / 2 | 20 / 15 / 2 | 9 / 7 / 1 | −4.87 / −2.75 / +0.47 | | 0.48 / 0.63 / 1.46 |
|
||||
| XAU_ATR / GENERIC / XAU_CP | 10 / 35 / 4 | 9 / 25 / 3 | 5 / 10 / 2 | −1.29 / −7.03 / +1.17 | | 0.69 / 0.45 / 2.10 |
|
||||
| regime transitioning / trending_down / trending_up | 12 / 15 / 16 | 11 / 15 / 6 | 4 / 8 / 2 | −6.02 / −0.70 / −2.06 | | 0.16 / 0.89 / 0.08 |
|
||||
| volatility extreme / normal | 31 / 9 | 22 / 8 | 10 / 4 | −4.32 / +0.94 | | 0.59 / 1.30 |
|
||||
| watch level none / watch / hot | 10 / 24 / 12 | 10 / 20 / 5 | 6 / 7 / 4 | +0.57 / −7.73 / +2.11 | | 1.18 / 0.38 / 10.5 |
|
||||
| hour 08 UTC | 7 | 7 | 0 | −7.14 | −1.02 | 0.00 |
|
||||
| hour 12 UTC | 13 | 6 | 5 | +4.15 | +0.69 | 19.7 |
|
||||
| day Sep 14 / Sep 15 / Sep 16 | 4 / 6 / 11 | 4 / 6 / 11 | 4 / 1 / 4 | +3.40 / −5.01 / −4.53 | | |
|
||||
|
||||
Exits: 17 SL, 18 TRAIL, 2 GAP_LOCKED. Setup-level forward moves agree with the advisory model:
|
||||
M15 setups −0.60 ATR excess at 4 h (hit 35%), −3.33 at 24 h; M5 −1.49 at 4 h, −5.33 at 24 h.
|
||||
|
||||
View 2, cooldown-equivalent (skip 5 primary bars after an accepted setup): 28 setups, 25 resolved,
|
||||
14 wins (56%), **−1.62R**, PF 0.84; M5 +0.11R (12), M15 −0.71R (12), H1 −1.01R; SELL +1.11R over 10
|
||||
(70% win), BUY −2.73R over 15.
|
||||
|
||||
View 3, reconstructed Telegram alerts: 36 alerts in 9 trading days (about 4 a day), 29 resolved, 14
|
||||
wins (48%), **−4.88R**, PF 0.64; M15 −3.97R (16), M5 +0.11R (12), H1 −1.01R. The re-alert rules let
|
||||
through 2 of the 6 Sep 15 shorts and all 3 FOMC-evening shorts.
|
||||
|
||||
Backtest over the same window (HEAD): **29 trades, +1.09R**. Matched-resolved 23: live +0.47R vs
|
||||
backtest +0.62R (the difference is the Sep 8 07:30 M15 short, GAP_LOCKED live at +1.13 vs +1.28
|
||||
on the raw path). Matched but live still pending 3: backtest +1.13R. Backtest-only 3: −0.66R.
|
||||
Live-only cooldown re-entries 20 (8 pending): the 12 resolved ones sum to **−5.54R**.
|
||||
|
||||
Bootstrap against the two-year books (per-trade R resampled; P = share of draws at or below the
|
||||
observed sum):
|
||||
|
||||
| view | tf | n | observed | book median | 5–95% | P(≤ obs) |
|
||||
|---|---|---|---|---|---|---|
|
||||
| view 1 (raw advisory) | M15 | 22 | −5.06R | +3.2 | −4.8..+12.0 | 4.6% |
|
||||
| view 1 | M5 | 14 | −1.08R | +2.4 | −4.2..+10.3 | 20% |
|
||||
| view 2 (cooldown) | M15 | 12 | −0.71R | +1.8 | −4.1..+8.3 | 25% |
|
||||
| view 2 | M5 | 12 | +0.11R | +2.0 | −4.0..+9.3 | 31% |
|
||||
| backtest over window | M15 | 13 | −0.32R | +1.9 | −4.2..+8.7 | 28% |
|
||||
| backtest over window | M5 | 15 | +2.43R | +2.6 | −4.3..+10.7 | 49% |
|
||||
|
||||
Calendar check: 36% of the M15 book's 13-day windows and 35% of the M5 book's are negative; among
|
||||
M5 windows where price fell 3% or more the median is +0.2R with 46% negative, median BUY −1.2R and
|
||||
median SELL +1.5R. This fortnight behaved the way the book says a falling fortnight behaves. The
|
||||
view-1 M15 figure looks extreme only because its 22 "trades" are 12 independent entries plus 10
|
||||
correlated re-entries.
|
||||
|
||||
Special buckets:
|
||||
|
||||
- **M15 grade-A/A+ SELL** (the parked cycle-2 candidate): live 11 setups, 5 wins, −2.77R (PF 0.55),
|
||||
but 6 of the 11 are Sep 15 cluster re-entries; the cooldown-equivalent five are +1.13, +0.36, +1.05,
|
||||
+0.09, −1.02 = +1.61R. Two-year book: 176 trades, −3.4R, mean −0.02R. The live sample does not
|
||||
move the candidate either way; it stays parked.
|
||||
- **FOMC evening** (Sep 16 18:45, 19:00, 19:15 UTC): three M15 shorts, all −1R, 45–75 minutes after
|
||||
the 18:00 decision, all `watch_level = watch` (reading `extreme`), none `hot` because the hot rule
|
||||
needs a high-impact USD release within ±30 min. The macro persona AGREED on all three at 82%
|
||||
confidence ("the Fed raised rates, which pushes gold down"); gold rose 95$ the next day. The
|
||||
backtester took the 18:45 trade too (−1.02R), so it is validated behaviour; 19:00 and 19:15 are
|
||||
cooldown re-entries.
|
||||
- **Sep 15 07:45–08:45 M15 STRONG_SELL cluster**: six setups on consecutive bars, one +0.09R and
|
||||
five −1.02R (−5.01R). The backtester took the first (+0.09R) and skipped the rest.
|
||||
- **XAU_CP**: 4 setups (2 inverse head-and-shoulders, 2 double bottoms), 3 resolved, +1.17R; both
|
||||
in-window ones matched the backtester exactly.
|
||||
- **Exhaustion count at entry**: 0 → +2.57R (4 resolved), 1 → −4.85R (10), 3 → +0.26R (8),
|
||||
4 → −3.24R (11). Descriptive only; the 2026-09-06 campaign already closed exhaustion sizing.
|
||||
|
||||
## 5. The AI panel
|
||||
|
||||
Unique setups with a panel 34 (27 resolved); macro persona is the verdict.
|
||||
|
||||
| verdict | n | resolved | wins | sum R | PF | 4 h excess / adj hit | 24 h excess / adj hit |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| AGREE | 12 | 12 | 6 (50%) | −2.16 | 0.59 | −2.51 / 22% (n 9) | −7.13 / 22% (n 9) |
|
||||
| NEUTRAL | 9 | 8 | 5 (62%) | −0.67 | 0.79 | +1.48 / 75% (n 8) | −2.31 / 29% (n 7) |
|
||||
| OPPOSE | 13 | 7 | 2 (29%) | −2.52 | 0.39 | −0.72 / 20% (n 5) | +0.69 / 80% (n 5) |
|
||||
| skip OPPOSE (counterfactual) | 21 | 20 | 11 (55%) | −2.82 | 0.66 | | |
|
||||
| AGREE only | 12 | 12 | 6 (50%) | −2.16 | 0.59 | | |
|
||||
|
||||
By realised R the OPPOSE verdict was mildly useful (it flagged the two worst-PF groups: opposed
|
||||
BUYs −1.61R over 4, opposed SELLs −0.91R over 3). By forward move the same opposed trades went the
|
||||
trade's way at 24 h (4 of 5 after drift). Six pending OPPOSE verdicts sit on the Sep 17 long
|
||||
cluster, which the backtester currently marks +0.90, +0.38, −0.15R. Nothing here is decidable at
|
||||
n = 7; it is consistent with the 2026-09-03 finding that only the macro persona carries information.
|
||||
|
||||
Personas (stance share / mean R when they held it): macro support 35% (−0.18R) / neutral 26%
|
||||
(−0.08R) / oppose 38% (−0.36R); technical support **79%** / oppose 12%; risk oppose **79%** /
|
||||
support 3%; contrarian oppose **65%**. Three of four personas vote almost the same way on every
|
||||
setup, so they add little beyond their prior. "Take only setups the risk persona did not oppose"
|
||||
leaves 7 setups (+0.03R): a curiosity, not a rule. Number of opposing personas (1 / 2 / 3) gives
|
||||
PF 0.57 / 0.57 / 0.57. Verdict confidence bands < 40 / 40–59 / ≥ 60 were 62% / 50% / 60% correct
|
||||
(n 8 / 4 / 15): no calibration.
|
||||
|
||||
## 6. Findings, tagged
|
||||
|
||||
**Observations (small sample, descriptive):**
|
||||
- The system is doing what was validated: bar-for-bar parity with the backtester, and the
|
||||
backtester itself made +1.1R on this window, a 30th-percentile fortnight for the book.
|
||||
- The live loss is concentrated in cluster re-entries (−5.5R), the Sep 15 08:xx short run and the
|
||||
FOMC-evening shorts, and in the `transitioning` regime (PF 0.16 over 11) and `watch` level
|
||||
(−7.7R over 20). Two weeks; no action.
|
||||
- The composite score was inversely related to the 24 h move on all three timeframes with CIs
|
||||
excluding zero, and uninformative at 1–4 h. Two weeks of a single bear regime cannot overturn the
|
||||
two-year book, but it is the strongest live pattern seen twice now (2026-09-08 and here).
|
||||
- Panel: OPPOSE mildly helpful by R, anti-informative by 24 h move; three personas near-constant.
|
||||
|
||||
**Delivery-side fix candidates (no book impact):**
|
||||
1. Redeploy the dashboard daemon to `2836024` (or later) and install the systemd unit; it has run
|
||||
`2ac7301` since Sep 10 and was dead for 3.5 days before that. After redeploy, re-check the 8 score
|
||||
divergences between surfaces on H1/H4 bars.
|
||||
2. Decide whether the live pipeline should mirror the backtester's 5-bar entry cooldown for
|
||||
alerts and for the advisory scorecard. Today every consecutive-bar setup is logged as its own
|
||||
trade and about one in three is re-alerted, so the live book systematically over-counts
|
||||
correlated entries relative to every validated number. A cooldown view could be added to
|
||||
`analyze_signal_log.py` (the existing `one_position_view` is close), and an alert cooldown is
|
||||
the owner's call.
|
||||
3. Backtester CSV `strategy` column: the gold ATR setups appear as `GENERIC` while live stamps
|
||||
`XAU_ATR`; entries, stops and R are identical, so this is a labelling gap only. Cause: the
|
||||
backtester derives its tag from the text of the first bullish/bearish reason (`"XAU STRATEGY"`
|
||||
in the first bullish reason → `XAU`) instead of reading `trade_setup.strategy`, so SELL ATR
|
||||
setups and any ATR setup whose first reason is another indicator fall through to `GENERIC`.
|
||||
The same tag feeds the research-only `--strategies` filter. Book-neutral; a one-line fix plus
|
||||
a test when convenient.
|
||||
4. Bot uptime: the 19.5 h Sep 9 outage cost two validated trades; the daily 21:xx stale rows and
|
||||
the Labor Day stale run are known and harmless.
|
||||
|
||||
**Needs a rule-1 backtest (nothing proposed to ship):**
|
||||
- Score-vs-24 h inversion: test in-book with the replay recorder (`--record --record-bars` writes
|
||||
forward 1 h / 4 h / 24 h moves for every analysed bar over the two-year window). If the rank
|
||||
correlation is also negative across the book, the gate chain's thresholds, not the weights, are
|
||||
the place to look; if it is positive, this fortnight was regime-specific.
|
||||
- M15 grade-A SELL block stays parked (cycle-2 candidate; live adds n = 5 cooldown-equivalent
|
||||
trades at +1.6R and n = 11 raw at −2.8R).
|
||||
|
||||
## Caveats
|
||||
|
||||
Section 7 adds four scratchpad research runs of gate 6h on the two-year cache (no new cache
|
||||
windows; `Backend: NumPy CPU fallback`, `GPU cache fallbacks: 0` on all four).
|
||||
|
||||
Nine trading days, one regime (bear trend with an FOMC hike), 37 resolved advisory outcomes of
|
||||
which 12 are correlated re-entries, the advisory model is cleaned-mid evidence and not execution,
|
||||
the 24 h horizon is drift-dominated (drift-adjusted numbers are shown but a single trend cannot be
|
||||
fully removed), the M15 engine changed mid-sample (Sep 9 21:45), the dashboard and the bot ran
|
||||
different code from Sep 14, and the alerted view is a reconstruction. The `--stored-candles`
|
||||
replay closes only 26 of the 37 DB-resolved setups because the stored candle streams have the
|
||||
Labor Day and Sep 9 gaps; where both resolve they agree to the cent.
|
||||
|
||||
## Appendix: the 49 unique setups
|
||||
|
||||
R at $0.65 (advisory model); ex24 = 24 h move in the trade direction minus the same-timeframe drift,
|
||||
ATR units; BT = backtester over the same window (M = matched, C = live-only inside the cooldown,
|
||||
– = before the parity window).
|
||||
|
||||
| bar (UTC) | tf | signal | g | score | dir | strategy | regime | R | exit | ex24 | panel | BT |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| 09-04 05:35 | M5 | BUY | B | +8.7 | BUY | XAU_CP | ranging | −1.06 | SL | −7.4 | NEUTRAL | – |
|
||||
| 09-04 07:45 | M15 | STRONG_BUY | A | +37.3 | BUY | XAU_ATR | transitioning | −1.04 | SL | −5.1 | NEUTRAL | – |
|
||||
| 09-04 15:10 | M5 | BUY | B | +8.8 | BUY | XAU_CP | ranging | unres. | | +3.1 | OPPOSE | – |
|
||||
| 09-07 08:00 | M15 | BUY | C | +26.7 | BUY | GENERIC | ranging | −1.02 | SL | | | M (bt grade B, pre-RSI engine) |
|
||||
| 09-07 12:15 | M5 | BUY | B | +22.2 | BUY | XAU_CP | trending | +2.04 | TRAIL | | NEUTRAL | M |
|
||||
| 09-08 07:30 | M15 | SELL | A | −34.2 | SELL | GENERIC | trending_down | +1.13 | GAP_LOCKED | +3.0 | OPPOSE | M (bt +1.28) |
|
||||
| 09-08 07:45 | M15 | SELL | B | −31.7 | SELL | GENERIC | trending_down | +0.84 | GAP_LOCKED | +2.7 | | C |
|
||||
| 09-08 08:05 | M5 | SELL | B | −35.4 | SELL | GENERIC | trending_down | −1.03 | SL | +3.7 | OPPOSE | M |
|
||||
| 09-10 05:10 | M5 | BUY | B | +20.5 | BUY | XAU_CP | ranging | +0.18 | TRAIL | −18.3 | AGREE | M |
|
||||
| 09-10 05:40 | M5 | BUY | A | +33.4 | BUY | GENERIC | trending_up | −1.03 | SL | −15.7 | AGREE | M |
|
||||
| 09-10 05:55 | M5 | BUY | B | +29.8 | BUY | GENERIC | trending_up | −1.02 | SL | −15.2 | | C |
|
||||
| 09-10 09:15 | M15 | SELL | B | −29.1 | SELL | GENERIC | transitioning | +0.07 | TRAIL | +4.2 | NEUTRAL | M |
|
||||
| 09-10 12:05 | M5 | SELL | B | −30.3 | SELL | GENERIC | trending_down | +1.31 | TRAIL | +3.6 | AGREE | M |
|
||||
| 09-10 12:15 | M15 | SELL | A | −34.3 | SELL | GENERIC | trending_down | +0.36 | TRAIL | +0.3 | AGREE | M |
|
||||
| 09-10 12:30 | M15 | SELL | B | −32.6 | SELL | GENERIC | trending_down | −0.22 | TRAIL | −3.4 | AGREE | C |
|
||||
| 09-14 09:15 | M15 | STRONG_SELL | A | −42.7 | SELL | XAU_ATR | trending_down | +1.05 | TRAIL | −0.1 | AGREE | M |
|
||||
| 09-14 09:30 | M15 | STRONG_SELL | A | −42.6 | SELL | XAU_ATR | trending_down | +0.70 | TRAIL | −1.0 | | C |
|
||||
| 09-14 12:45 | M5 | SELL | B | −36.5 | SELL | GENERIC | trending_down | +0.16 | TRAIL | −6.1 | AGREE | M |
|
||||
| 09-14 15:25 | M5 | BUY | C | +25.1 | BUY | GENERIC | ranging | +1.49 | TRAIL | +4.3 | | M |
|
||||
| 09-15 07:45 | M15 | STRONG_SELL | A | −37.5 | SELL | GENERIC | trending_down | +0.09 | TRAIL | −8.7 | AGREE | M |
|
||||
| 09-15 08:00 | M15 | STRONG_SELL | A | −42.0 | SELL | GENERIC | trending_down | −1.02 | SL | −9.5 | OPPOSE | C |
|
||||
| 09-15 08:10 | M5 | SELL | B | −30.3 | SELL | GENERIC | trending_down | −1.02 | SL | −15.6 | AGREE | M |
|
||||
| 09-15 08:15 | M15 | STRONG_SELL | A | −36.7 | SELL | GENERIC | trending_down | −1.02 | SL | −9.6 | | C |
|
||||
| 09-15 08:30 | M15 | STRONG_SELL | A | −41.6 | SELL | GENERIC | trending_down | −1.02 | SL | −9.7 | | C |
|
||||
| 09-15 08:45 | M15 | STRONG_SELL | A | −45.1 | SELL | GENERIC | trending_down | −1.02 | SL | −10.5 | | C |
|
||||
| 09-16 03:00 | M5 | STRONG_BUY | A | +36.0 | BUY | GENERIC | trending_up | +0.14 | TRAIL | −4.2 | NEUTRAL | M |
|
||||
| 09-16 03:00 | M15 | BUY | A | +34.0 | BUY | XAU_ATR | transitioning | +0.14 | TRAIL | −3.5 | NEUTRAL | M |
|
||||
| 09-16 03:10 | M5 | STRONG_BUY | A | +38.6 | BUY | GENERIC | trending_up | −0.16 | TRAIL | −4.6 | | C |
|
||||
| 09-16 03:15 | M15 | BUY | A | +30.9 | BUY | XAU_ATR | transitioning | +0.43 | TRAIL | −2.8 | | C |
|
||||
| 09-16 06:00 | H1 | BUY | B | +28.0 | BUY | GENERIC | transitioning | −1.01 | SL | −0.7 | NEUTRAL | M |
|
||||
| 09-16 07:00 | M15 | BUY | B | +29.1 | BUY | GENERIC | trending_up | +0.05 | TRAIL | +0.5 | NEUTRAL | M |
|
||||
| 09-16 07:35 | M5 | STRONG_BUY | A | +37.3 | BUY | GENERIC | trending_up | −0.04 | TRAIL | +3.2 | OPPOSE | M |
|
||||
| 09-16 15:05 | M5 | BUY | B | +29.7 | BUY | GENERIC | transitioning | −1.04 | SL | | OPPOSE | M |
|
||||
| 09-16 18:45 | M15 | SELL | A | −34.6 | SELL | XAU_ATR | transitioning | −1.02 | SL | | AGREE | M |
|
||||
| 09-16 19:00 | M15 | STRONG_SELL | A | −35.4 | SELL | XAU_ATR | transitioning | −1.02 | SL | | AGREE | C |
|
||||
| 09-16 19:15 | M15 | SELL | B | −26.6 | SELL | GENERIC | transitioning | −1.01 | SL | | AGREE | C |
|
||||
| 09-17 07:15 | M15 | BUY | A | +31.5 | BUY | XAU_ATR | transitioning | −1.03 | SL | | OPPOSE | M |
|
||||
| 09-17 07:25 | M5 | STRONG_BUY | A | +35.9 | BUY | GENERIC | trending_up | pending | | | OPPOSE | M (bt +0.90) |
|
||||
| 09-17 07:30 | M5 | STRONG_BUY | A | +36.2 | BUY | GENERIC | trending_up | pending | | | | C |
|
||||
| 09-17 07:30 | M15 | BUY | B | +28.7 | BUY | GENERIC | transitioning | pending | | | | C |
|
||||
| 09-17 07:35 | M5 | STRONG_BUY | A | +35.5 | BUY | GENERIC | trending_up | pending | | | | C |
|
||||
| 09-17 12:00 | M5 | BUY | B | +34.3 | BUY | GENERIC | trending_up | pending | | | NEUTRAL | M (bt +0.38) |
|
||||
| 09-17 12:00 | M15 | STRONG_BUY | A | +35.9 | BUY | XAU_ATR | transitioning | +0.50 | TRAIL | | OPPOSE | M |
|
||||
| 09-17 12:05 | M5 | STRONG_BUY | A | +37.2 | BUY | GENERIC | trending_up | pending | | | OPPOSE | C |
|
||||
| 09-17 12:10 | M5 | BUY | B | +34.4 | BUY | GENERIC | trending_up | pending | | | OPPOSE | C |
|
||||
| 09-17 12:15 | M5 | STRONG_BUY | A | +38.9 | BUY | GENERIC | trending_up | pending | | | OPPOSE | C |
|
||||
| 09-17 12:15 | M15 | STRONG_BUY | A+ | +43.7 | BUY | XAU_ATR | trending_up | pending | | | OPPOSE | C |
|
||||
| 09-17 12:20 | M5 | STRONG_BUY | A | +39.1 | BUY | GENERIC | trending_up | pending | | | | C |
|
||||
| 09-17 12:25 | M5 | STRONG_BUY | A | +40.0 | BUY | GENERIC | trending_up | pending | | | | M (bt −0.15) |
|
||||
|
||||
Backtest-only trades: M15 BUY B 09-08 04:00 (−1.03R; live scored the bar +24.7 NEUTRAL D on the
|
||||
pre-RSI-change engine), M15 BUY B 09-09 05:45 (+0.23R) and M5 BUY A 09-09 06:00 (+0.14R), both
|
||||
during the bot outage.
|
||||
|
||||
## 7. The owner's four suspicions, checked
|
||||
|
||||
The owner's objective for this review (2026-09-17): is anything functioning poorly in one of four
|
||||
specific ways. Each is checked on the 49 unique live setups (37 resolved) and compared with the
|
||||
two-year books where the books carry the same measure. "Reached TP1" means the trade's best
|
||||
excursion (MFE) reached the planned first target; the advisory model itself exits on the trail, so
|
||||
TP1 is advisory.
|
||||
|
||||
### 7.1 Does the AI panel OPPOSE trades that go on to hit their targets? — yes, as often as not
|
||||
|
||||
| macro verdict | setups | reached TP1 | reached TP2 | resolved wins | mean MFE |
|
||||
|---|---|---|---|---|---|
|
||||
| AGREE | 12 | 5 (42%) | 4 | 6 / 12 | 0.87R |
|
||||
| NEUTRAL | 9 | 5 (56%) | 3 | 5 / 8 | 0.96R |
|
||||
| OPPOSE | 13 | **7 (54%)** | 5 | 2 / 7 | 0.64R |
|
||||
|
||||
Opposed trades reached their first target more often than agreed ones. Concrete cases: OPPOSE at
|
||||
60% on the Sep 8 07:30 M15 short ("most news points to gold rising") that made +1.13R and hit TP2;
|
||||
OPPOSE at 62–65% on five of the Sep 17 longs that ran +0.7R to +1.3R (four still open); AGREE at 82%
|
||||
on all three FOMC-evening shorts ("the Fed raised rates, which pushes gold down"), all −1R, gold
|
||||
+95$ the next day. The macro persona's notes quote the news narrative of the moment, and the
|
||||
2026-09-04 study showed that narrative trails price by about a day. The realised-R view (opposed
|
||||
trades 2/7 wins) looks better for the panel only because the opposed winners are mostly the
|
||||
pending Sep 17 longs. Structure: technical supports 79% of setups, risk opposes 79%, contrarian
|
||||
65% — three near-constant voters. **Verdict: OPPOSE has no value as a veto and must never gate;
|
||||
it is presented as "news context" at best.** (observation; the panel is already advisory-only)
|
||||
|
||||
### 7.2 Wrong direction, or entering late after the move is exhausted? — late by design; this fortnight the continuation failed
|
||||
|
||||
- 11 of 37 resolved setups never reached +0.3R (wrong from the first bar); 17 of 37 were stopped.
|
||||
Book norm: 20–22% never reach 0.3R; live 30%.
|
||||
- **30 of 37 entries came after price had already moved ≥ 2 ATR in the trade direction over the
|
||||
previous 4 h**: PF 0.47, −7.8R. The 7 entries after a smaller prior move: PF 1.21, +0.7R.
|
||||
- The engine's own exhaustion tags do **not** separate the losers: trades carrying
|
||||
`rsi_extended` / `bb_overextended` at entry (21) had PF 0.68 and −2.8R; the 16 without had PF
|
||||
0.53 and −4.4R. The 2026-08-04 stretch verdict (stretched entries are the best book trades) and
|
||||
the 2026-09-06 sizing campaign already closed exhaustion-based sizing; the live fortnight adds
|
||||
nothing that would reopen it.
|
||||
- Three recurring shapes: (a) M15 shorts fire after a 4–6 ATR down leg, are right for four hours
|
||||
(69% hit) and wrong by the next day (the low bounces); (b) longs in the downtrend fired at bounce
|
||||
tops — Sep 10 05:40 and 05:55 at the 24 h high, followed by a 20 ATR fall; (c) the FOMC shorts
|
||||
entered 45–75 min after the decision, 0.2–0.9 ATR above the day's low, after a 4–5 ATR drop: they
|
||||
sold the bottom. Every one of these is the momentum design working as validated; the two-year
|
||||
book earns its edge on exactly these entries and this fortnight they failed.
|
||||
(observation)
|
||||
|
||||
### 7.3 Do signals fire on big volatile candles? — yes, and that is where the whole loss sits
|
||||
|
||||
| entry context (last 3 primary bars) | resolved | wins | reached TP1 | sum R | PF |
|
||||
|---|---|---|---|---|---|
|
||||
| a bar ≥ 2 ATR among the last 3 | 15 | 4 (27%) | 5 | **−7.18** | 0.25 |
|
||||
| the signal bar itself ≥ 2 ATR | 7 | 1 (14%) | 2 | −3.44 | 0.23 |
|
||||
| signal-bar body ≥ 1 ATR in the trade direction | 12 | 5 (42%) | 7 | −3.63 | 0.34 |
|
||||
| no bar ≥ 2 ATR among the last 3 | 22 | 13 (59%) | 13 | **+0.02** | 1.00 |
|
||||
|
||||
The 15 setups fired within three bars of a ≥ 2 ATR candle carry the entire fortnight's loss; the
|
||||
other 22 broke even at the book's win rate. Largest cases: Sep 10 12:30 M15 short on a 4.2 ATR bar
|
||||
(−0.22R), the FOMC 18:45 / 19:00 shorts on 2.5–2.7 ATR bars (−1R each), Sep 14 09:15 short on a
|
||||
2.7 ATR bar (+1.05R). A gate for exactly this exists (`big_candle_atr_multiple`, gate 6h) and ships
|
||||
off because the 2026-07-30 test found the removed trades net-positive at every multiple on the long
|
||||
books. The live fortnight contradicts that book verdict, so the gate was re-run on the two-year
|
||||
M15 and M5 books (below).
|
||||
|
||||
Re-test of gate 6h on the two-year books (`--big-candle 2.0 --big-candle-hours {1,24}`, same
|
||||
harness as the reference books, control = the MD5-verified W2 books; "removed" = control trades
|
||||
absent from the candidate, approximate because the cooldown displaces entries):
|
||||
|
||||
| book | trades | R | PF | win | max DD | H1 / H2 | ΔR vs control | removed trades |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| M15 control | 931 | +146.1 | 1.43 | 60.5% | 16.1 | +67.7 / +78.4 | | |
|
||||
| M15 gate 2 ATR, 1 h lookback | 643 | +117.6 | 1.51 | 61.9% | 14.4 | +58.4 / +59.2 | **−28.5** | 347 trades, **+32.5R**, 58% win |
|
||||
| M15 gate 2 ATR, 24 h lookback | 3 | +0.5 | | | | | −145.6 | 929 trades, +147.0R |
|
||||
| M5 control | 781 | +146.1 | 1.52 | 52.9% | 10.1 | +41.0 / +105.1 | | |
|
||||
| M5 gate 2 ATR, 1 h lookback | 434 | +86.5 | 1.56 | 53.5% | 10.4 | +31.2 / +55.3 | **−59.6** | 368 trades, **+60.2R**, 52% win |
|
||||
| M5 gate 2 ATR, 24 h lookback | 0 | | | | | | −146.1 | all |
|
||||
|
||||
Same verdict as 2026-07-30: over two years the trades entered within an hour of a ≥ 2 ATR candle
|
||||
are a net-positive bucket on both timeframes (+32R and +60R at the book's own win rates), and the
|
||||
gate buys a few points of profit factor by giving up a fifth to two fifths of the R. The live
|
||||
fortnight's −7.2R in that bucket is a bad draw from a positive population, not a malfunction.
|
||||
**Gate stays off; not a rule-1 candidate.** (needs-a-rule-1-backtest: done here, fails)
|
||||
|
||||
### 7.4 Are take-profit targets too far, with the market reversing first? — targets are normal in R; the stops are what is big
|
||||
|
||||
Planned geometry by generator (live): M15 GENERIC TP1 = 1.0R with stops of 3.6–4.4 ATR ($21–62,
|
||||
one of $121 on the FOMC 19:15 short); M15 XAU_ATR TP1 = 0.69R with a 2 ATR stop ($16 target, $23
|
||||
stop); M5 GENERIC TP1 = 0.5R with stops of 4.7–7.3 ATR ($13–32 target, $26–65 stop); XAU_CP TP1 =
|
||||
0.88R. As a share of price the live GENERIC stops (medians 0.6–1.0%) sit above the book medians
|
||||
(0.58–0.73%) but inside the book's 90th percentiles (0.97–1.66%); only the $121 FOMC stop (2.85%)
|
||||
is outside. Capping the stop in ATR was tested and refuted in the 2026-09 campaign.
|
||||
|
||||
| measure | live (37 resolved) | M15 book | M5 book |
|
||||
|---|---|---|---|
|
||||
| reached TP1 | 49% | 52% | 56% |
|
||||
| never reached 0.3R | 30% | 20% | 22% |
|
||||
| gave back (MFE ≥ 0.5R, closed ≤ 0) | 16% | 11% | 18% |
|
||||
| MFE 0.6–1.0R and closed ≤ 0 | 4 of 8 | | |
|
||||
|
||||
So the targets were reached about as often as in the books; what was worse was the share of trades
|
||||
that never moved in favour at all. Trades that did reach 0.6–1.0R often ended flat or negative
|
||||
because the trail arms at 0.6R (M5) / 0.7R (M15) and gives back to the arm level. A fixed exit at TP1
|
||||
would have made this fortnight −3.55R instead of −7.15R, which is the same direction as the
|
||||
2026-08-05 fixed-target study (better in 2024+ trend windows, worse in 2021 and 2023, drawdown
|
||||
doubled), so nothing changes there. (observation; `--fixed-rr-tp` remains research-only)
|
||||
Reference in New Issue
Block a user