Daily-trend veto on M15 + lot-size / already-open lines (campaign 2026-09-30), and the 2026-10-01 whole-codebase bug review

Two bodies of work that touch the same files, so one commit.

Direction and setup-size campaign (2026-09-30 → 10-01, owner's RISK-FIRST rule,
written before the runs):
- SIGNAL: M15 daily-trend veto (factory override 7, xau_strategy.daily_trend_veto
  "both"). A finished setup against a clear daily trend (closed D1 bars, Sunday
  stubs dropped; close vs its 50-bar EMA AND vs the close 60 kept days earlier)
  is removed as the last step of the core. One definition
  (signal_aggregator.daily_trend_series) for live, the bar replay and the twin's
  host side; D1 is a required frame of the M15 scan; mirrored in
  cuda_signal_kernels.py K2. W3 824 / +205.12R / PF 1.73 / max DD 12.4R vs
  1105 / +195.79R / 1.49 / 20.9R; 2019 → 2026 1473 / +223.33R / 1.42 / 41.5R vs
  2091 / +192.53R / 1.24 / 64.8R; unseen holdout −4.62R vs −6.63R.
- FAILED, not shipped: the veto on M5 (W3 drawdown 10.1R → 15.2R) and on H1
  (−9.7R), buy-only and sell-only on M15, the wide-stop cap
  (xau_strategy.wide_stop_cap_atr stays 0.0, a research knob).
- New M15 pins: W2 dfc647ee…, OOS e87b6de1…, W3 ad3b0dbd…. M5 / H1 / H4 pins
  unchanged. --set xau_strategy.daily_trend_veto=off reproduces the previous M15
  pins byte for byte. Twin and reference script MD5-equal on every window;
  recorder and feature-export parity re-proved; base-rate table rebuilt.
- DISPLAY (books byte-identical): exposure.py — the lot size for
  trade_size.risk_per_trade (new config.json block, off by default, private to
  the owner) and the count of alerted same-direction plans still open
  (signals.alerted_at, read-only open_alerted_setups); the daily trend in words
  on Telegram, the CLI and the dashboard; signals.daily_trend logged.
- providers/oanda: a date window with no bars is an empty page, not an error
  (a D1 pad starting on a Saturday could not be fetched).
- Reports only, nothing shipped: seven context screens (no state nominated) and
  eight outside data sources (none adds a forecast to gold's own daily trend).
- Independent verification (report section 5.13): every figure reproduced on
  both scripts, scoring identical to the previous commit on all four
  timeframes, no look-ahead. Caveats recorded there: this is a risk filter, not
  a more accurate direction call; nine tenths of the 2019 → 2026 gain is 2022;
  the neighbour clause is thin (a simple 100-day average misses the R line by
  1.2R); "never adds a trade" is an observation, not a guarantee.

Bug review of the whole codebase (2026-10-01). Signal path clean. 17 defects
elsewhere, plus 4 found by an independent review of the fixes; all fixed, each
with a test; no trade book changed:
- telegram_bot: one _deliver_alert for the candle scan and the level break. The
  row is stamped alerted_at BEFORE the send, on a one-worker alert-db pool, and
  un-stamped when no chat received it or the task is cancelled mid-stamp, so
  two alerts at one candle close count each other and no SQLite write runs on
  the event loop. The 5-bar cooldown counts bars of the scan's own frame
  (== gpu_backtest._apply_cooldown; clock time released the 22:00 UTC bar after
  the settlement pause) and is restored from signals.db at start-up. The
  lot-size line goes to the owner's own chat only (a group the owner ran
  /autoscan in used to receive it). /status gains a news-model line and escapes
  failure details.
- signal_log: mark_alerted returns the stamp it wrote; unmark_alerted;
  last_alerted_bars (read-only).
- advisory_outcome: candle continuity is judged bar by bar inside the walk; a
  hole after a trade's exit no longer voids it. The stored-candle replay
  resolves 108 of 111 logged setups instead of 99, all equal to the live
  resolver's R.
- providers/oanda: an empty date window is accepted only when it is 5 days or
  shorter and no malformed candle was skipped; a longer one is retried, then
  refused, instead of being cached as history with a hole.
- news_engine: blank RSS titles skipped; one unreadable headline no longer
  costs the local model its whole batch (checked on the real bundle); model
  health recorded; no DeepSeek audit call in a process that does not archive;
  event-direction cache keyed per release; peek_week_events never fetches.
- llm_client: chat_json never raises and never logs the API key (requests
  quotes the Authorization value in InvalidHeader; error bodies are redacted).
- signal_aggregator: the scan's news block is guarded; the replay path
  (use_news=False) assigns exactly the values it did before.
- agent_panel: PANEL_PROMPT_VERSION v2.2 — same prompt text, corrected input
  (event timing over the cached calendar week, headlines newest first).
  scripts/panel_replay.py replays the logged payload per persona;
  scripts/label_scan_outcomes.py counts with an ISO cutoff.
- test_all.py: no ALTER TABLE … DROP COLUMN (the live box has SQLite 3.34);
  tests that write Parquet print a notice and return without pyarrow.

Verification after the last code change: suite 632 passed, 0 failed (also with
both Parquet engines blocked and FB2_BACKEND=cpu, the live box's view); the
five reference MD5s reproduce on both backtesters, 0 cache fallbacks; Module 37
green; static Python 3.9 / SQLite 3.34 check clean on every touched file.

Evidence: backtest/research/daily_trend_campaign_2026-09-30.md,
context_screens_2026-10.md, new_inputs_2026-10.md; CLAUDE.md sections 2, 4, 6,
8, 9, 10 and 11; pair_signals/xauusd.py docstring (M15 override 7).
This commit is contained in:
Harwinder Sekhon
2026-10-01 10:28:28 -04:00
parent 42025da0b0
commit 2cc5915b00
31 changed files with 6021 additions and 286 deletions
@@ -0,0 +1,235 @@
# Context screens after the daily-trend veto — declared before looking, 2026-10-01
Follow-up to `daily_trend_campaign_2026-09-30.md` (owner decision 2026-09-30: "more context
screens"). The daily chart was information the engine had never seen, and it paid on M15. This
file asks the same question of seven more pieces of context. Sections 1 to 3 were written before
any number in section 4 existed.
## 1. Books and slices
The books as shipped on 2026-09-30, `--spread 0.65`, CUDA twin (byte-identical to
`gpu_backtest.py` on the paired runs of the campaign report):
| Book | Window | Trades / R | MD5 |
|---|---|---|---|
| M15 LONG (veto on) | 2019-01-01 → 2026-08-07 | 1473 / +223.33 | `aa5253aa…` |
| M15 W3 (veto on) | 2023-09-05 → 2026-09-05 | 824 / +205.12 | `ad3b0dbd…` |
| M5 LONG | 2019-01-01 → 2026-08-07 | 1052 / +128.10 | `3f0c091c…` |
| M5 W3 | 2023-09-05 → 2026-09-05 | 870 / +153.64 | `d20ec8a3…` |
Four slices per timeframe: LONG era A (entries 2019–2023), LONG era B (2024 → 2026-08-07), W3
first half (before 2025-03-05), W3 second half. W3 overlaps era B, so the four slices are not
independent; that is known and accepted for a screen.
## 2. The seven features (closed bars only, as of the trade's decision time)
Decision time = the trade's entry time (the entry is the open of the bar after the signal bar, so
it equals the signal bar's close). A bar counts only when it had closed by then.
Daily bars: provider D1 candles (UTC days), Sunday stub bars dropped, usable from label + 1 day.
1. **Weekly trend.** Weekly bars = the kept daily bars grouped into weeks ending Friday; a week is
usable once its Friday bar is. State +1 when the weekly close is above its 20-week EMA
(`ewm(span=20, adjust=False)`) AND above the close 12 weeks earlier; −1 when below both; else 0.
Trade state: `with` / `against` / `unclear`.
2. **Four-hour trend.** Provider H4 candles (UTC-aligned), usable from label + 4 h. State +1 when
the close is above its 50-bar EMA AND above the close 30 bars earlier; −1 when below both; else
0. Trade state: `with` / `against` / `unclear`.
3. **Daily-trend strength.** `(Close − Close 60 kept days earlier) / ATR14`, ATR14 = the simple
14-day mean of the true range, taken in the trade's direction (multiplied by −1 for a SELL).
Trade state by fixed cut-offs: `counter` (< 0), `weak` (0 to 5), `medium` (5 to 12),
`strong` (> 12 daily ATRs).
4. **Daily volatility state.** ATR14 / Close, ranked within its own trailing 250 kept days
(percentile, the current day included). Trade state: `quiet` (< 33%), `normal`, `wild` (> 67%).
5. **Place in the 20-day range.** `(Close − lowest Low of 20 kept days) / (highest High − lowest
Low)`, mirrored for a SELL (1 − value). Trade state: `near the far edge` (< 1/3: buying near
the 20-day low or selling near the high), `middle`, `near the chasing edge` (> 2/3: buying near
the 20-day high or selling near the low).
6. **Tick-volume surge.** Volume of the signal bar divided by the median volume of the same clock
slot (same hour and minute, UTC) over that slot's previous 20 bars. Trade state: `thin`
(< 0.8), `usual` (0.8 to 1.5), `surge` (> 1.5).
7. **Time to a high-impact US release** (`backtest/cache/calendar.parquet`, currency USD, impact
high, time not masked; the file starts 2023-09-01, so W3 only). Minutes from the decision time
to the nearest such release. Trade state: `0–30 min before`, `0–30 min after`,
`30–120 min before`, `30–120 min after`, `clear` (more than 2 hours either side).
Rows whose feature cannot be computed (not enough history) are counted as `n/a` and never flagged.
## 3. Rule
A screen is an in-book statistic: it cannot see the trades a change would add and it ignores the
5-bar cooldown. It can only nominate a hypothesis.
- A state is **nominated** only if, on one timeframe, it holds at least 8% of the trades of BOTH
books (LONG and W3) and its total R is negative in ALL FOUR slices.
- For each nominated state the mechanism is written down before its replay.
- At most **three** replays in total, on the final-veto research harness of the campaign (K1 + K2
of the twin, a mask on the final candidates before the cooldown, the shared resolver), judged by
the same risk-first rule T against the shipped book: W3 R ≥ 97% of control, W3 PF ≥ control +
0.10, W3 max drawdown ≤ control, LONG R ≥ control, LONG max drawdown ≤ control, 2021 + 2022
better, HOLDOUT R ≥ control − 0.5R, the same at $0.30, at least 20 trades differ. (No
neighbour-definition clause here: a pass only earns a full Stage-1/Stage-2 build, where the
neighbours are tested.)
- No nomination, no replay. No second cut-off, no other bins, no "best of seven" story afterwards.
With 7 features, about 25 states and 2 timeframes, a state that is negative in four overlapping
slices by luck alone is not rare; that is why a nomination is only a ticket to a replay.
## 4. Results
Run 2026-10-01 on the four books of section 1 (read from the campaign's exported CSVs; the feature
frames are the kept Oanda cache windows: daily `1d_20150303_20260807` / `1d_20191105_20260905`,
four-hour `4h_20181031_20260807` / `4h_20230114_20260905`, the books' own primary frames for
volume, `calendar.parquet` for releases). Every trade's decision time equals its entry time in
all four books (no entry sat behind a market closure). Cells are total R (trades); "mean" is R per
trade.
### 4.1 M15 (daily-trend veto on): LONG 1473 trades / +223.33R, W3 824 trades / +205.12R
**M15 — 1. weekly trend**
| State | LONG trades (share) | LONG R / mean | W3 trades (share) | W3 R / mean | LONG era A (2019–2023) | LONG era B (2024–2026) | W3 first half | W3 second half | Nominated |
|---|---|---|---|---|---|---|---|---|---|
| against | 78 (5%) | -15.0 / -0.193 | 25 (3%) | +3.9 / +0.157 | -18.3 (58) | +3.2 (20) | +3.8 (7) | +0.1 (18) | |
| unclear | 176 (12%) | +28.1 / +0.160 | 101 (12%) | +37.8 / +0.375 | +1.9 (102) | +26.2 (74) | +25.4 (61) | +12.5 (40) | |
| with | 1219 (83%) | +210.3 / +0.173 | 698 (85%) | +163.4 / +0.234 | +53.1 (568) | +157.2 (651) | +47.6 (316) | +115.8 (382) | |
**M15 — 2. four-hour trend**
| State | LONG trades (share) | LONG R / mean | W3 trades (share) | W3 R / mean | LONG era A (2019–2023) | LONG era B (2024–2026) | W3 first half | W3 second half | Nominated |
|---|---|---|---|---|---|---|---|---|---|
| against | 260 (18%) | +23.3 / +0.090 | 134 (16%) | +14.8 / +0.111 | +12.4 (137) | +10.9 (123) | +3.4 (59) | +11.4 (75) | |
| unclear | 167 (11%) | +16.8 / +0.100 | 84 (10%) | +16.7 / +0.199 | +0.3 (90) | +16.5 (77) | +1.8 (41) | +14.9 (43) | |
| with | 1046 (71%) | +183.3 / +0.175 | 606 (74%) | +173.6 / +0.286 | +24.1 (501) | +159.2 (545) | +71.5 (284) | +102.1 (322) | |
**M15 — 3. daily-trend strength**
| State | LONG trades (share) | LONG R / mean | W3 trades (share) | W3 R / mean | LONG era A (2019–2023) | LONG era B (2024–2026) | W3 first half | W3 second half | Nominated |
|---|---|---|---|---|---|---|---|---|---|
| counter | 145 (10%) | -4.8 / -0.033 | 72 (9%) | +16.9 / +0.234 | -13.1 (92) | +8.3 (53) | +15.2 (39) | +1.7 (33) | |
| medium | 586 (40%) | +106.6 / +0.182 | 393 (48%) | +94.6 / +0.241 | +16.7 (199) | +89.9 (387) | +9.5 (162) | +85.1 (231) | |
| strong | 17 (1%) | +4.6 / +0.268 | 10 (1%) | +4.8 / +0.483 | -0.3 (7) | +4.8 (10) | -1.1 (1) | +5.9 (9) | |
| weak | 725 (49%) | +117.0 / +0.161 | 349 (42%) | +88.8 / +0.254 | +33.5 (430) | +83.5 (295) | +53.1 (182) | +35.7 (167) | |
**M15 — 4. daily volatility state**
| State | LONG trades (share) | LONG R / mean | W3 trades (share) | W3 R / mean | LONG era A (2019–2023) | LONG era B (2024–2026) | W3 first half | W3 second half | Nominated |
|---|---|---|---|---|---|---|---|---|---|
| normal | 445 (30%) | +54.8 / +0.123 | 299 (36%) | +77.6 / +0.259 | -11.8 (194) | +66.6 (251) | +6.7 (118) | +70.8 (181) | |
| quiet | 373 (25%) | +64.1 / +0.172 | 152 (18%) | +51.7 / +0.340 | +24.2 (235) | +39.9 (138) | +38.9 (109) | +12.8 (43) | |
| wild | 655 (44%) | +104.4 / +0.159 | 373 (45%) | +75.9 / +0.203 | +24.3 (299) | +80.1 (356) | +31.1 (157) | +44.8 (216) | |
**M15 — 5. place in the 20-day range**
| State | LONG trades (share) | LONG R / mean | W3 trades (share) | W3 R / mean | LONG era A (2019–2023) | LONG era B (2024–2026) | W3 first half | W3 second half | Nominated |
|---|---|---|---|---|---|---|---|---|---|
| middle | 420 (29%) | +54.9 / +0.131 | 230 (28%) | +32.3 / +0.140 | +25.3 (217) | +29.7 (203) | +30.9 (107) | +1.4 (123) | |
| near the chasing edge | 835 (57%) | +143.5 / +0.172 | 483 (59%) | +147.1 / +0.305 | +8.8 (400) | +134.7 (435) | +40.6 (227) | +106.5 (256) | |
| near the far edge | 218 (15%) | +24.8 / +0.114 | 111 (13%) | +25.7 / +0.231 | +2.6 (111) | +22.2 (107) | +5.3 (50) | +20.4 (61) | |
**M15 — 6. tick-volume surge**
| State | LONG trades (share) | LONG R / mean | W3 trades (share) | W3 R / mean | LONG era A (2019–2023) | LONG era B (2024–2026) | W3 first half | W3 second half | Nominated |
|---|---|---|---|---|---|---|---|---|---|
| surge | 556 (38%) | +83.1 / +0.149 | 226 (27%) | +45.7 / +0.202 | +45.8 (355) | +37.3 (201) | +22.5 (110) | +23.1 (116) | |
| thin | 220 (15%) | +15.6 / +0.071 | 125 (15%) | +28.5 / +0.228 | -10.4 (99) | +26.0 (121) | +11.5 (48) | +17.0 (77) | |
| usual | 697 (47%) | +124.7 / +0.179 | 473 (57%) | +130.9 / +0.277 | +1.4 (274) | +123.2 (423) | +42.7 (226) | +88.3 (247) | |
**M15 — 7. time to a high-impact US release (W3 only)**
| State | LONG trades (share) | LONG R / mean | W3 trades (share) | W3 R / mean | LONG era A (2019–2023) | LONG era B (2024–2026) | W3 first half | W3 second half | Nominated |
|---|---|---|---|---|---|---|---|---|---|
| 0–30 min after | | | 42 (5%) | +8.9 / +0.212 | | | +4.7 (27) | +4.2 (15) | |
| 0–30 min before | | | 26 (3%) | +8.7 / +0.336 | | | +7.8 (18) | +0.9 (8) | |
| 30–120 min after | | | 75 (9%) | +28.4 / +0.378 | | | +11.7 (51) | +16.6 (24) | |
| 30–120 min before | | | 22 (3%) | +16.1 / +0.732 | | | +12.9 (18) | +3.2 (4) | |
| clear | | | 659 (80%) | +143.0 / +0.217 | | | +39.6 (270) | +103.5 (389) | |
### 4.2 M5: LONG 1052 trades / +128.10R, W3 870 trades / +153.64R
**M5 — 1. weekly trend**
| State | LONG trades (share) | LONG R / mean | W3 trades (share) | W3 R / mean | LONG era A (2019–2023) | LONG era B (2024–2026) | W3 first half | W3 second half | Nominated |
|---|---|---|---|---|---|---|---|---|---|
| against | 258 (25%) | +11.0 / +0.043 | 202 (23%) | +6.6 / +0.033 | +9.4 (69) | +1.6 (189) | +3.8 (10) | +2.8 (192) | |
| unclear | 84 (8%) | +6.3 / +0.075 | 88 (10%) | +24.6 / +0.279 | -7.5 (30) | +13.8 (54) | +8.2 (12) | +16.4 (76) | |
| with | 710 (67%) | +110.8 / +0.156 | 580 (67%) | +122.5 / +0.211 | -12.3 (159) | +123.1 (551) | +4.7 (114) | +117.8 (466) | |
**M5 — 2. four-hour trend**
| State | LONG trades (share) | LONG R / mean | W3 trades (share) | W3 R / mean | LONG era A (2019–2023) | LONG era B (2024–2026) | W3 first half | W3 second half | Nominated |
|---|---|---|---|---|---|---|---|---|---|
| against | 332 (32%) | +3.0 / +0.009 | 255 (29%) | +11.2 / +0.044 | -5.5 (98) | +8.4 (234) | -0.9 (35) | +12.2 (220) | |
| unclear | 126 (12%) | +13.7 / +0.109 | 105 (12%) | +17.8 / +0.170 | +0.6 (28) | +13.1 (98) | +0.8 (13) | +17.0 (92) | |
| with | 594 (56%) | +111.4 / +0.188 | 510 (59%) | +124.6 / +0.244 | -5.5 (132) | +116.9 (462) | +16.9 (88) | +107.7 (422) | |
**M5 — 3. daily-trend strength**
| State | LONG trades (share) | LONG R / mean | W3 trades (share) | W3 R / mean | LONG era A (2019–2023) | LONG era B (2024–2026) | W3 first half | W3 second half | Nominated |
|---|---|---|---|---|---|---|---|---|---|
| counter | 296 (28%) | +0.7 / +0.003 | 241 (28%) | -2.6 / -0.011 | +8.8 (87) | -8.0 (209) | +3.7 (18) | -6.3 (223) | |
| medium | 367 (35%) | +77.3 / +0.211 | 318 (37%) | +78.4 / +0.247 | -1.2 (49) | +78.4 (318) | +6.9 (53) | +71.6 (265) | |
| strong | 14 (1%) | +16.6 / +1.186 | 13 (1%) | +15.6 / +1.199 | +1.0 (1) | +15.6 (13) | +0.0 (0) | +15.6 (13) | |
| weak | 375 (36%) | +33.5 / +0.089 | 298 (34%) | +62.2 / +0.209 | -19.0 (121) | +52.5 (254) | +6.2 (65) | +56.1 (233) | |
**M5 — 4. daily volatility state**
| State | LONG trades (share) | LONG R / mean | W3 trades (share) | W3 R / mean | LONG era A (2019–2023) | LONG era B (2024–2026) | W3 first half | W3 second half | Nominated |
|---|---|---|---|---|---|---|---|---|---|
| normal | 302 (29%) | +33.2 / +0.110 | 305 (35%) | +45.6 / +0.150 | -0.8 (63) | +34.0 (239) | -3.0 (42) | +48.6 (263) | |
| quiet | 114 (11%) | +18.8 / +0.165 | 72 (8%) | +17.9 / +0.249 | +3.0 (45) | +15.8 (69) | +10.9 (37) | +7.0 (35) | |
| wild | 636 (60%) | +76.1 / +0.120 | 493 (57%) | +90.1 / +0.183 | -12.6 (150) | +88.8 (486) | +8.8 (57) | +81.3 (436) | |
**M5 — 5. place in the 20-day range**
| State | LONG trades (share) | LONG R / mean | W3 trades (share) | W3 R / mean | LONG era A (2019–2023) | LONG era B (2024–2026) | W3 first half | W3 second half | Nominated |
|---|---|---|---|---|---|---|---|---|---|
| middle | 323 (31%) | +11.8 / +0.037 | 271 (31%) | +18.8 / +0.069 | -6.8 (76) | +18.6 (247) | -1.8 (34) | +20.6 (237) | |
| near the chasing edge | 439 (42%) | +101.5 / +0.231 | 380 (44%) | +115.0 / +0.303 | -2.6 (103) | +104.1 (336) | +17.2 (77) | +97.8 (303) | |
| near the far edge | 290 (28%) | +14.8 / +0.051 | 219 (25%) | +19.9 / +0.091 | -1.0 (79) | +15.9 (211) | +1.4 (25) | +18.5 (194) | |
**M5 — 6. tick-volume surge**
| State | LONG trades (share) | LONG R / mean | W3 trades (share) | W3 R / mean | LONG era A (2019–2023) | LONG era B (2024–2026) | W3 first half | W3 second half | Nominated |
|---|---|---|---|---|---|---|---|---|---|
| surge | 479 (46%) | +46.2 / +0.097 | 334 (38%) | +65.3 / +0.195 | -5.9 (176) | +52.1 (303) | +13.2 (64) | +52.1 (270) | |
| thin | 152 (14%) | +9.3 / +0.061 | 134 (15%) | +18.1 / +0.135 | -8.0 (22) | +17.3 (130) | -0.7 (7) | +18.8 (127) | |
| usual | 421 (40%) | +72.6 / +0.172 | 402 (46%) | +70.3 / +0.175 | +3.4 (60) | +69.2 (361) | +4.2 (65) | +66.1 (337) | |
**M5 — 7. time to a high-impact US release (W3 only)**
| State | LONG trades (share) | LONG R / mean | W3 trades (share) | W3 R / mean | LONG era A (2019–2023) | LONG era B (2024–2026) | W3 first half | W3 second half | Nominated |
|---|---|---|---|---|---|---|---|---|---|
| 0–30 min after | | | 46 (5%) | -3.8 / -0.082 | | | -0.6 (15) | -3.2 (31) | |
| 0–30 min before | | | 18 (2%) | +1.8 / +0.098 | | | +0.7 (5) | +1.1 (13) | |
| 30–120 min after | | | 87 (10%) | +32.8 / +0.377 | | | +8.3 (31) | +24.4 (56) | |
| 30–120 min before | | | 18 (2%) | +3.4 / +0.187 | | | +2.7 (7) | +0.7 (11) | |
| clear | | | 701 (81%) | +119.5 / +0.171 | | | +5.6 (78) | +114.0 (623) | |
### 4.3 Verdict
**Nominated states: none.** No state on either timeframe holds 8% of both books and loses in all
four slices. By the rule of section 3 there is no replay and nothing ships.
What the tables do say (in-book description, not a decision):
- **M15, after the daily-trend veto, has no losing pocket left in these seven views.** The only
clearly negative cell is trades against the weekly trend in 2019–2023 (−18.3R over 58 trades),
5% of the book and positive since 2024. Trades with the four-hour trend earn +0.18R to +0.29R
each against +0.09R to +0.11R against it: weaker, still positive.
- **M5 earns its R where everything already agrees.** With the weekly trend +0.16R to +0.21R per
trade, against it +0.03R to +0.04R; with the four-hour trend +0.19R to +0.24R, against it
+0.01R to +0.04R; when the 60-day move runs against the trade, 0.00R (about 28% of the book).
Those against-the-tide M5 trades are flat, not losing, which is the same picture the formal
daily-trend test gave on M5: removing them removes no loss, and it made the worst losing run
deeper. They stay.
- **M5's profit sits near the 20-day extreme in the trade's direction** (+0.23R to +0.30R per
trade against +0.04R to +0.09R elsewhere). This repeats the 2026-08-04 finding that the best
trades are the stretched runs: a "do not chase" filter would cut the part of the book that pays.
- **Volume and news timing separate nothing reliably.** A volume surge is the best state in
2019–2023 on M15 and the middle state since; trades 30 to 120 minutes after a major US release
look good on both timeframes (+0.38R each) on 75 and 87 trades, and trades in the half hour
after a release are slightly negative on M5 (−3.8R over 46 trades, 5% of the book, below the
8% bar). Neither is a rule.
So the daily chart was the one piece of missing context that paid, on M15. Weekly and four-hour
context add nothing on top of it there, and nothing on M5 that survives the rule.
@@ -0,0 +1,639 @@
# Daily-trend veto and wide-stop cap — pre-registered campaign, 2026-09-30
Owner request (2026-09-30): improve the direction call and the trade setup size; anything may
change if the evidence supports it. This file holds the rules first, then the results. Sections 1
to 4 were written before any formal run. Section 2 records what was already looked at while
planning, so the reader knows which numbers are a confirmation and which are a first look.
## 1. What is tested
**Candidate T — daily-trend veto.** The engine sees at most the H1 chart (M5 confirms on M15 and
H1, M15 on M5 and H1). None of the 65 decision-time features of the earlier campaigns reads the
daily chart. The candidate drops a finished trade setup that goes against a clear daily trend.
Definition (fixed; `signal_aggregator.daily_trend_series`):
- daily candles from the provider (UTC-aligned, label = 00:00 UTC of the day), closed bars only:
a bar labelled D is used once D + 1 day ≤ the close of the primary bar;
- bars labelled Sunday are dropped first (Oanda's 1 to 2 hour reopening stub);
- `ema = Close.ewm(span=50, adjust=False).mean()`, `change = Close / Close.shift(60) − 1`;
- state +1 when `Close > ema` and `change > 0`; −1 when `Close < ema` and `change < 0`; else 0;
- after every setup archetype has run (gold ATR, swing, pullback, chart pattern) a setup against a
non-zero state is removed: grade D, no setup, warning `DAILY TREND FILTER: …`.
Switch `xau_strategy.daily_trend_veto`: `off` (default, books byte-identical), `both`, `buy`
(only buys against a falling daily trend are removed), `sell`.
**Candidate C — wide-stop cap.** `xau_strategy.wide_stop_cap_atr = K` caps the stop distance of
the swing (GENERIC) and chart-pattern setups at `max(K × ATR, the existing floor)`, applied after
the min-RR and spread gates so the set of trades cannot change. K = 6, with 5, 7 and 8 declared
as neighbours. M15 only (the exit-only screen was negative on M5).
## 2. What was already seen (planning phase, 2026-09-30, read-only, in memory)
Prototype: K1 and K2 of the CUDA twin, then a host-side mask on the final candidates before the
5-bar cooldown, then the shared resolver. The control rows of the prototype reproduce the pinned
books (M15 W3 1105 / +195.79R, M5 W3 870 / +153.64R, H1 W3 253 / +70.02R).
| Book ($0.65) | Control | Veto, both directions |
|---|---|---|
| M15 W3 2023-09-05 → 2026-09-05 | 1105 / +195.8R / PF 1.49 / DD 20.9 | 824 / +205.1R / PF 1.73 / DD 12.4 |
| M15 LONG 2019-01-01 → 2026-08-07 | 2091 / +192.5R / PF 1.24 / DD 64.8 | 1473 / +223.3R / PF 1.42 / DD 41.5 |
| M15 rising window 2024-06-01 → 2025-03-30 | 313 / +68.5R / PF 1.67 | 258 / +63.8R / PF 1.80 |
| M5 W3 | 870 / +153.6R / PF 1.50 / DD 10.1 | 668 / +159.1R / PF 1.70 / DD 15.2 |
| M5 W3, buy side only | | 741 / +156.5R / PF 1.60 / DD 9.6 |
| M5 LONG | 1052 / +128.1R / PF 1.34 / DD 18.4 | 790 / +127.5R / PF 1.45 / DD 25.2 |
| H1 W3 | 253 / +70.0R / PF 1.98 / DD 4.4 | 231 / +60.3R / PF 1.90 / DD 4.4 |
Also seen: neighbouring definitions on M15 (60-day change alone +188.3R W3 / +228.1R LONG;
90-day +196.1 / +228.8; 120-day +199.4 / +233.2; 100-day average +201.2 / +227.3); the share of
M15 W3 trades reaching +1R before −1R (58.6% → 61.4%); the live September 2026 setups with the
veto applied after the fact (cooldown view −11.6R → −6.0R to −8.8R); an exit-only re-simulation
of 25 stop and exit variants (cap 6 × ATR on M15 W3 +14.0R, LONG +11.8R; cap 5 negative on LONG);
two variants dropped at this stage and NOT tested formally: lifting the SELL gates when the daily
trend is down (worse on LONG on both timeframes), and removing the existing M15 short blocks
under the veto (costs 4 to 22R).
So the windows W3, W2, the rising window and LONG are a CONFIRMATION through the real code path.
First looks are: the HOLDOUT window through the backtester, the $0.30 numbers on LONG, and every
number produced by the shipped code rather than the prototype.
## 3. Harness
`venv/bin/python backtest/cudaBasedBacktesting.py --pair XAUUSD --primary-tf <tf> --start <s>
--end <e> --spread <0.65|0.30> [--set xau_strategy.daily_trend_veto=<mode>]
[--set xau_strategy.wide_stop_cap_atr=<K>] --export-csv <out>`; factory configuration otherwise.
Twin numbers count only with the paired `backtest/gpu_backtest.py` MD5 (same flags plus
`--workers 12`). Neighbouring trend definitions are not shipped code: they run on the research
harness (the prototype), after the harness book for the shipped definition is shown identical to
the twin's.
Windows: **W3** 2023-09-05 → 2026-09-05 (halves at 2025-03-05); **W2** 2024-09-05 → 2026-09-05
(halves at 2025-09-05); **RISING** 2024-06-01 → 2025-03-30 (the old out-of-sample window; a
rising market throughout); **LONG** 2019-01-01 → 2026-08-07; **HOLDOUT** 2026-09-05 → 2026-10-01
(fetched for this campaign, never seen by any tuning or by the prototype).
## 4. Acceptance rules (written before the runs)
**Rule T (risk-first; owner decision 2026-09-30).** Candidate T on a timeframe PASSES only if,
against the same-harness control:
- (a) W3 total R ≥ 97% of the control's at $0.65;
- (b) W3 profit factor ≥ control + 0.10;
- (c) W3 max drawdown ≤ the control's;
- (d) LONG: total R ≥ control, max drawdown ≤ control, and 2021 + 2022 combined R better;
- (e) HOLDOUT total R ≥ control − 0.5R;
- (f) clauses (a) to (c) also hold at $0.30;
- (g) at least 3 of the 4 neighbouring definitions (60-day change alone, 90-day, 120-day,
100-day average alone) satisfy (a) and (c): a plateau, not a spike;
- (h) at least 20 trades differ on W3.
Reported, NOT clauses (the owner accepted this cost on 2026-09-30): the W2 halves and the RISING
window, where the veto is expected to give up some R. The 2026-09-26 template (every half and the
old out-of-sample window must not lose) would reject this candidate by construction; that is the
difference between the two rules and it is deliberate.
Decision per timeframe: `both` if it passes; else `buy` if that passes; else no veto (the daily
trend is then shown on the alert as information only). H1 is run for the record.
**Rule C (standard).** K = 6 on M15 against the post-T control PASSES only if: W3 ΔR ≥ +5R; both
W3 halves ≥ control − 1R; PF ≥ control − 0.02; W3 max drawdown ≤ control + 10%; LONG total R ≥
control; the same sign of ΔR at $0.30; at least 20 trades differ; and the neighbours K = 5 and
K = 7 are not negative on W3 or on LONG.
No rescue for either rule: no second definition, no other K, no window shopping after the result.
## 5. Results
All runs 2026-09-30 on the dev box, branch `sql-integration`, working tree = HEAD `0c56b4e` plus
this campaign's code. Every twin log reads
`Backend: CuPy GPU (NVIDIA GeForce RTX 4070 SUPER, cupy 14.0.1)` and
`GPU cache fallbacks: 0 (no per-bar recompute path in cudaBasedBacktesting)`; every reference log
reads the same `Backend:` line and `GPU cache fallbacks: 0`. 86 formal twin books (5 windows × 2
costs × the variants below, plus the fixed-1R-target books). R is per trade in units of the
initial risk; "DD" is the largest peak-to-trough fall of the running total, in R.
### 5.1 Proofs before any formal number
- **Baseline.** Before any code change the five reference MD5s of CLAUDE.md §9 were reproduced on
both scripts (ten books).
- **Default-off neutrality.** With the new code and both knobs at their defaults the same ten
books are byte-identical to the pins (`e599c8a8…` M5 W2, `5b65ecf6…` M15 W2, `09b8a8e7…` M15
OOS, `a44fd19b…` H1 W3, `f3587bae…` H4 W3).
- **Twin = reference on every new path** (`--spread 0.65`, W3 2023-09-05 → 2026-09-05, equal MD5
from `backtest/gpu_backtest.py --workers 12` and `backtest/cudaBasedBacktesting.py`):
| Flags | Trades / R / DD | MD5 (both scripts) |
|---|---|---|
| M15 `--set xau_strategy.daily_trend_veto=both` | 824 / +205.12 / 12.39 | `ad3b0dbda0bf77b659caea1c53be6a50` |
| M15 `…=buy` | 999 / +188.21 / 20.87 | `6e0f3b742d9690f78c97319d1b1c8a43` |
| M15 `…=sell` | 930 / +212.70 / 13.72 | `31aa5762964d846f15d111cd4a718adc` |
| M15 `--set xau_strategy.wide_stop_cap_atr=6` | 1105 / +209.78 / 19.32 | `4ec0e4450d5dab143a4ed37e80545626` |
| M5 `--set xau_strategy.daily_trend_veto=both` | 668 / +159.07 / 15.20 | `39cc0f198d38b532720dce4f98d99452` |
| M5 `--set xau_strategy.wide_stop_cap_atr=6` | 870 / +141.57 / 13.95 | `4da0997256b272ffcd11a90bf9658eef` |
The M15 `both` book equals the planning prototype trade for trade (824 / +205.1R / PF 1.73 /
DD 12.4), so the shipped definition is the one that was screened.
- **Suite.** 595 passed / 0 failed after Stage 1 (Module 39 new, Module 37 extended).
### 5.2 Candidate T — every window, both costs
Command per row: `venv/bin/python backtest/cudaBasedBacktesting.py --pair XAUUSD --primary-tf
<15min|5min> --start <s> --end <e> --spread <0.65|0.30> [--set xau_strategy.daily_trend_veto=<mode>]
--export-csv <out>`. "control" = no `--set`.
**M15**
| Window | Cost | Variant | Trades | Total R | Win rate | PF | Max DD | First half | Second half | MD5 (8) |
|---|---|---|---|---|---|---|---|---|---|---|
| W3 | $0.65 | control | 1105 | +195.79 | 61.1% | 1.49 | 20.9 | +76.87 | +118.92 | 70195fb0 |
| W3 | $0.65 | both | 824 | +205.12 | 63.1% | 1.73 | 12.4 | +76.72 | +128.40 | ad3b0dbd |
| W3 | $0.65 | buy | 999 | +188.21 | 61.3% | 1.52 | 20.9 | +60.40 | +127.81 | 6e0f3b74 |
| W3 | $0.65 | sell | 930 | +212.70 | 62.7% | 1.66 | 13.7 | +93.19 | +119.52 | 31aa5762 |
| W3 | $0.30 | control | 1105 | +216.53 | 61.4% | 1.55 | 19.6 | +88.86 | +127.67 | ce074a1b |
| W3 | $0.30 | both | 824 | +221.18 | 63.6% | 1.81 | 11.4 | +86.41 | +134.77 | 96a87454 |
| W3 | $0.30 | buy | 999 | +207.23 | 61.7% | 1.59 | 19.6 | +71.83 | +135.41 | 2ada14e4 |
| W3 | $0.30 | sell | 930 | +230.48 | 63.1% | 1.73 | 12.8 | +103.45 | +127.03 | 49665c41 |
| W2 | $0.65 | control | 813 | +154.15 | 62.2% | 1.53 | 15.6 | +70.10 | +84.04 | 5b65ecf6 |
| W2 | $0.65 | both | 597 | +155.89 | 64.3% | 1.78 | 11.4 | +61.83 | +94.06 | dfc647ee |
| W2 | $0.65 | buy | 718 | +154.67 | 63.0% | 1.62 | 14.4 | +65.03 | +89.65 | f23bfda4 |
| W2 | $0.65 | sell | 692 | +155.36 | 63.3% | 1.65 | 13.7 | +66.91 | +88.46 | 1a071ac7 |
| W2 | $0.30 | control | 813 | +167.53 | 62.6% | 1.59 | 14.5 | +78.61 | +88.91 | 15486607 |
| W2 | $0.30 | both | 597 | +166.22 | 64.8% | 1.85 | 11.0 | +68.82 | +97.39 | d2f678bf |
| W2 | $0.30 | buy | 718 | +166.64 | 63.4% | 1.68 | 14.0 | +73.12 | +93.52 | f3abc1e8 |
| W2 | $0.30 | sell | 692 | +167.10 | 63.7% | 1.71 | 12.8 | +74.31 | +92.79 | d7d038fd |
| RISING | $0.65 | control | 313 | +68.50 | 63.6% | 1.67 | 12.4 | +18.87 | +49.63 | 09b8a8e7 |
| RISING | $0.65 | both | 258 | +63.78 | 64.3% | 1.80 | 9.1 | +23.97 | +39.81 | e87b6de1 |
| RISING | $0.65 | buy | 303 | +60.15 | 63.0% | 1.60 | 12.4 | +18.87 | +41.28 | f001a0a6 |
| RISING | $0.65 | sell | 268 | +72.13 | 64.9% | 1.89 | 9.1 | +23.97 | +48.16 | cbe4cb24 |
| RISING | $0.30 | control | 313 | +76.21 | 64.5% | 1.77 | 11.1 | +22.92 | +53.29 | 5fc34cef |
| RISING | $0.30 | both | 258 | +70.24 | 65.5% | 1.91 | 7.9 | +27.31 | +42.92 | 5de32f51 |
| RISING | $0.30 | buy | 303 | +67.59 | 64.0% | 1.70 | 11.1 | +22.92 | +44.67 | 69b41026 |
| RISING | $0.30 | sell | 268 | +78.86 | 66.0% | 2.00 | 7.9 | +27.31 | +51.54 | 3631466e |
| LONG | $0.65 | control | 2091 | +192.53 | 57.8% | 1.24 | 64.8 | | | c2228398 |
| LONG | $0.65 | both | 1473 | +223.33 | 59.7% | 1.42 | 41.5 | | | aa5253aa |
| LONG | $0.65 | buy | 1762 | +214.62 | 58.9% | 1.33 | 34.5 | | | 952d64d8 |
| LONG | $0.65 | sell | 1802 | +201.23 | 58.3% | 1.30 | 76.4 | | | d3965ab8 |
| LONG | $0.30 | control | 2091 | +240.00 | 58.8% | 1.31 | 49.6 | | | 0c58b300 |
| LONG | $0.30 | both | 1473 | +257.25 | 60.8% | 1.50 | 37.2 | | | 1835b341 |
| LONG | $0.30 | buy | 1762 | +254.33 | 59.9% | 1.40 | 29.5 | | | a2b519bd |
| LONG | $0.30 | sell | 1802 | +242.92 | 59.4% | 1.37 | 62.3 | | | f6edb469 |
| HOLDOUT | $0.65 | control | 24 | −6.63 | 50.0% | 0.42 | 7.0 | | | c42470a0 |
| HOLDOUT | $0.65 | both | 18 | −4.62 | 50.0% | 0.50 | 4.8 | | | fa50bcd0 |
| HOLDOUT | $0.65 | buy | 22 | −6.81 | 45.5% | 0.41 | 7.0 | | | 548a4bf4 |
| HOLDOUT | $0.65 | sell | 20 | −4.44 | 55.0% | 0.52 | 4.8 | | | 1459ef5f |
| HOLDOUT | $0.30 | control | 24 | −6.29 | 50.0% | 0.44 | 6.7 | | | d7fbee9d |
| HOLDOUT | $0.30 | both | 18 | −4.35 | 50.0% | 0.52 | 4.5 | | | 2179c08c |
| HOLDOUT | $0.30 | buy | 22 | −6.49 | 45.5% | 0.43 | 6.7 | | | 0b90faeb |
| HOLDOUT | $0.30 | sell | 20 | −4.15 | 55.0% | 0.54 | 4.5 | | | 70932b7e |
**M5**
| Window | Cost | Variant | Trades | Total R | Win rate | PF | Max DD | First half | Second half | MD5 (8) |
|---|---|---|---|---|---|---|---|---|---|---|
| W3 | $0.65 | control | 870 | +153.64 | 53.3% | 1.50 | 10.1 | +16.73 | +136.91 | d20ec8a3 |
| W3 | $0.65 | both | 668 | +159.07 | 53.9% | 1.70 | 15.2 | +14.01 | +145.06 | 39cc0f19 |
| W3 | $0.65 | buy | 741 | +156.53 | 53.4% | 1.60 | 9.6 | +15.68 | +140.85 | 631f25ac |
| W3 | $0.30 | control | 870 | +172.40 | 54.3% | 1.57 | 8.9 | +21.08 | +151.32 | 5acafcba |
| W3 | $0.30 | both | 668 | +174.43 | 54.8% | 1.79 | 14.3 | +18.09 | +156.34 | 34f2e282 |
| W3 | $0.30 | buy | 741 | +172.72 | 54.3% | 1.69 | 8.9 | +19.87 | +152.86 | c8bdc9e2 |
| W2 | $0.65 | control | 781 | +146.07 | 52.9% | 1.52 | 10.1 | +26.42 | +119.65 | e599c8a8 |
| W2 | $0.65 | both | 585 | +153.82 | 53.7% | 1.78 | 15.2 | +33.16 | +120.66 | b9fa356c |
| W2 | $0.65 | buy | 656 | +151.09 | 53.0% | 1.66 | 9.6 | +27.42 | +123.66 | 30e243b0 |
| W2 | $0.30 | control | 781 | +162.09 | 53.9% | 1.60 | 8.9 | +31.71 | +130.37 | 7ab48db9 |
| W2 | $0.30 | both | 585 | +166.59 | 54.7% | 1.87 | 14.3 | +38.05 | +128.54 | 3427b933 |
| W2 | $0.30 | buy | 656 | +164.66 | 54.0% | 1.74 | 8.9 | +32.58 | +132.08 | 7dd9e2a2 |
| RISING | $0.65 | control | 86 | +9.47 | 53.5% | 1.33 | 8.2 | +0.01 | +9.46 | 65c46e62 |
| RISING | $0.65 | both | 81 | +9.07 | 54.3% | 1.34 | 7.5 | +0.67 | +8.40 | e20fdef2 |
| RISING | $0.65 | buy | 85 | +10.55 | 54.1% | 1.39 | 7.2 | +0.01 | +10.54 | de24b2e8 |
| RISING | $0.30 | control | 86 | +12.42 | 54.7% | 1.46 | 6.7 | +1.65 | +10.77 | 5c154360 |
| RISING | $0.30 | both | 81 | +11.91 | 55.6% | 1.47 | 6.1 | +2.28 | +9.63 | 3b1a8f9e |
| RISING | $0.30 | buy | 85 | +13.46 | 55.3% | 1.52 | 5.7 | +1.65 | +11.81 | 21ffab88 |
| LONG | $0.65 | control | 1052 | +128.10 | 50.5% | 1.34 | 18.4 | | | 3f0c091c |
| LONG | $0.65 | both | 790 | +127.47 | 50.4% | 1.45 | 25.2 | | | 9872c068 |
| LONG | $0.65 | buy | 871 | +123.37 | 49.9% | 1.39 | 27.1 | | | 613dcf0e |
| LONG | $0.30 | control | 1052 | +153.02 | 51.7% | 1.41 | 13.0 | | | 6708d8cc |
| LONG | $0.30 | both | 790 | +147.13 | 51.5% | 1.54 | 19.6 | | | 201d968f |
| LONG | $0.30 | buy | 871 | +144.02 | 51.1% | 1.47 | 22.3 | | | d9cba459 |
| HOLDOUT | $0.65 | control | 33 | −2.45 | 51.5% | 0.82 | 6.1 | | | 351f7149 |
| HOLDOUT | $0.65 | both | 26 | −2.04 | 50.0% | 0.81 | 5.4 | | | b9c8cb82 |
| HOLDOUT | $0.65 | buy | 33 | −2.45 | 51.5% | 0.82 | 6.1 | | | 351f7149 |
| HOLDOUT | $0.30 | control | 33 | −1.85 | 51.5% | 0.86 | 5.6 | | | 5a6aea9c |
| HOLDOUT | $0.30 | both | 26 | −1.56 | 50.0% | 0.85 | 5.0 | | | ddd29068 |
| HOLDOUT | $0.30 | buy | 33 | −1.85 | 51.5% | 0.86 | 5.6 | | | 5a6aea9c |
**H1, for the record** ($0.65): W3 control 253 / +70.02R / PF 1.98 / DD 4.4 (`a44fd19b`), `both`
231 / +60.28R / PF 1.90 / DD 4.4 (`cdac563b`); HOLDOUT 3 / −3.04R in both (no trade removed).
Fails (a) (60.28 < 67.92) and (b). H4 was not run: it confirms on the daily chart already.
### 5.3 Per calendar year ($0.65), total R / trades
M15, LONG 2019-01-01 → 2026-08-07:
| Variant | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | 2026 |
|---|---|---|---|---|---|---|---|---|
| control | +9.0 / 117 | +48.8 / 283 | −25.6 / 210 | −24.6 / 267 | +11.7 / 211 | +53.3 / 343 | +81.2 / 425 | +38.7 / 235 |
| both | +14.0 / 88 | +45.1 / 207 | −27.3 / 121 | +3.2 / 149 | +1.8 / 163 | +53.5 / 275 | +92.5 / 341 | +40.6 / 129 |
| buy | +7.6 / 111 | +44.2 / 253 | −21.4 / 135 | +7.4 / 166 | +1.6 / 189 | +46.4 / 335 | +83.1 / 416 | +45.9 / 157 |
| sell | +15.4 / 94 | +49.7 / 237 | −31.5 / 196 | −28.8 / 250 | +11.9 / 185 | +60.4 / 283 | +90.6 / 350 | +33.4 / 207 |
M5, LONG:
| Variant | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | 2026 |
|---|---|---|---|---|---|---|---|---|
| control | −1.0 / 20 | −2.8 / 95 | −1.7 / 32 | −2.2 / 50 | −2.8 / 61 | +1.0 / 102 | +40.5 / 332 | +97.0 / 360 |
| both | +0.2 / 17 | −6.9 / 76 | −3.4 / 14 | −4.7 / 28 | −3.5 / 54 | +1.5 / 96 | +43.2 / 297 | +101.0 / 208 |
| buy | +0.2 / 17 | −6.7 / 83 | −3.2 / 16 | −6.0 / 30 | −4.6 / 56 | +2.1 / 101 | +40.5 / 329 | +101.0 / 239 |
M15, W3 per calendar year (total R / trades / max DD inside the year):
| Variant | 2023 (from 09-05) | 2024 | 2025 | 2026 (to 09-05) |
|---|---|---|---|---|
| control | +10.8 / 66 / 9.0 | +53.3 / 343 / 16.3 | +81.2 / 425 / 15.6 | +50.5 / 271 / 10.3 |
| both | +9.3 / 47 / 6.9 | +53.5 / 275 / 11.0 | +92.5 / 341 / 11.4 | +49.9 / 161 / 8.3 |
M15, R per month from 2025-09 (W3):
| Variant | 2025-09 | 10 | 11 | 12 | 2026-01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 (to 09-05) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| control | +14.7 | −1.4 | +3.7 | +19.4 | +29.1 | −2.2 | +9.5 | +4.4 | +0.0 | +1.7 | −4.6 | +12.4 | +0.2 |
| both | +19.4 | +0.6 | +8.4 | +18.7 | +32.4 | −2.4 | +1.5 | +7.2 | −2.4 | +5.1 | +2.3 | +5.9 | +0.2 |
Losing runs on M15: longest run of losing trades 9 → 8 (W3 and LONG); worst calendar month
−10.1R → −6.1R (W3, 2024-01) and −11.7R → −10.0R (LONG); losing months 11 → 8 of 37 on W3,
39 of 92 → 37 of 91 on LONG.
### 5.4 Rule T, clause by clause
**M15 `both` — PASS**
| Clause | Result | Numbers (candidate vs control) |
|---|---|---|
| (a) W3 R ≥ 97% of control | PASS | +205.12 vs +195.79 (97% = +189.92) |
| (b) W3 PF ≥ control + 0.10 | PASS | 1.734 vs 1.488 |
| (c) W3 max DD ≤ control | PASS | 12.39 vs 20.87 |
| (d) LONG R ≥ control | PASS | +223.33 vs +192.53 |
| (d) LONG max DD ≤ control | PASS | 41.54 vs 64.77 |
| (d) 2021 + 2022 better | PASS | −24.12 vs −50.21 |
| (e) HOLDOUT R ≥ control − 0.5 | PASS | −4.62 (18 trades) vs −6.63 (24) |
| (f) (a) at $0.30 | PASS | +221.18 vs +216.53 (97% = +210.04) |
| (f) (b) at $0.30 | PASS | 1.809 vs 1.551 |
| (f) (c) at $0.30 | PASS | 11.44 vs 19.56 |
| (g) ≥ 3 of 4 neighbours pass (a) and (c) | PASS | 3 of 4 (table 5.5) |
| (h) ≥ 20 trades differ on W3 | PASS | 281 removed, 0 added |
**M15 `buy` — FAIL**: (a) +188.21 < +189.92; (b) 1.523 < 1.588; the same two at $0.30.
**M15 `sell` — FAIL**: (d) LONG max DD 76.39 > 64.77 and 2021 + 2022 −60.29 < −50.21. It has the
best W3 total (+212.70R) and that is exactly the trap the long window was there to catch: in the
falling years the buys against the daily trend are the losers, and `sell` keeps them.
**M5 `both` — FAIL**: (c) W3 DD 15.20 > 10.11 (also at $0.30: 14.30 > 8.88); (d) LONG R
+127.47 < +128.10, LONG DD 25.25 > 18.39, 2021 + 2022 −8.02 < −3.91; (g) 0 of 4.
**M5 `buy` — FAIL**: (d) LONG R +123.37 < +128.10, LONG DD 27.14 > 18.39, 2021 + 2022 −9.13 <
−3.91; (g) 1 of 4.
**H1 `both` — FAIL** (a), (b).
### 5.5 Clause (g): neighbouring definitions (research harness)
The harness (K1 + K2 of the twin with the veto OFF, a host-side mask on the final candidates
before the cooldown, the shared resolver) reproduces the twin's `--set` books byte for byte for
the shipped definition, so it is the same thing as the shipped path for a final veto:
| Book ($0.65) | Harness CSV MD5 | Twin CSV MD5 |
|---|---|---|
| M15 W3 control | `70195fb0e6865b3a46ee8a9aa8844e51` | same |
| M15 W3 `both` | `ad3b0dbda0bf77b659caea1c53be6a50` | same |
| M15 LONG control | `c222839878f791e980b2dbc99fb6dfbd` | same |
| M15 LONG `both` | `aa5253aab206fd21fa6a8d5ba25b75b5` | same |
| M5 W3 control / `both` / `buy` | `d20ec8a3…` / `39cc0f19…` / `631f25ac…` | same |
| M5 LONG control / `both` / `buy` | `3f0c091c…` / `9872c068…` / `613dcf0e…` | same |
M15, veto in both directions, each neighbour replacing the definition of "clear daily trend":
| Definition | W3 trades | W3 R | W3 PF | W3 DD | (a) | (c) | LONG trades | LONG R | LONG PF | LONG DD |
|---|---|---|---|---|---|---|---|---|---|---|
| control | 1105 | +195.79 | 1.49 | 20.87 | (97% = +189.92) | | 2091 | +192.53 | 1.24 | 64.77 |
| **shipped: 50-day average AND 60-day change** | 824 | +205.12 | 1.73 | 12.39 | PASS | PASS | 1473 | +223.33 | 1.42 | 41.54 |
| 60-day change alone | 752 | +188.25 | 1.73 | 11.89 | FAIL | PASS | 1328 | +228.11 | 1.49 | 27.30 |
| 90-day change alone | 782 | +196.14 | 1.72 | 12.46 | PASS | PASS | 1412 | +228.75 | 1.46 | 37.36 |
| 120-day change alone | 781 | +199.36 | 1.75 | 12.26 | PASS | PASS | 1397 | +233.19 | 1.47 | 34.79 |
| 100-day average alone | 796 | +201.23 | 1.74 | 12.26 | PASS | PASS | 1375 | +227.30 | 1.47 | 32.56 |
3 of 4 pass. Every neighbour beats the control on PF and on drawdown in both windows; the one
miss is 1.7R under the 97% line. It is a plateau. (Each neighbour has a lower LONG drawdown than
the shipped definition; switching to one now would be the rescue the rule forbids.)
M5: `both` 0 of 4 (every neighbour keeps the 15.2R drawdown), `buy` 1 of 4 (90-day, 120-day and
100-day average all fall under the 97% line). No plateau on M5.
### 5.6 What the veto removes (M15, $0.65)
Zero trades are added in any window (W3 and LONG, every variant, both timeframes): the setups
inside a vetoed setup's 5-bar cooldown point the same way under the same daily state and are
vetoed with it, so the cooldown displaces nothing.
| Slice | W3 trades | W3 R | W3 mean R | LONG trades | LONG R | LONG mean R |
|---|---|---|---|---|---|---|
| all removed | 281 | −9.32 | −0.033 | 618 | −30.80 | −0.050 |
| BUY against a falling daily trend | 106 | +7.59 | +0.072 | 329 | −22.10 | −0.067 |
| SELL against a rising daily trend | 175 | −16.91 | −0.097 | 289 | −8.70 | −0.030 |
| removed, grade B | 210 | −11.53 | −0.055 | 408 | −25.69 | −0.063 |
| removed, grade A | 46 | +1.28 | +0.028 | 164 | −1.12 | −0.007 |
| removed, grade A+ | 14 | +4.26 | +0.304 | 26 | +1.81 | +0.069 |
| removed, grade C | 11 | −3.34 | −0.304 | 20 | −5.80 | −0.290 |
| kept (the new book) | 824 | +205.12 | +0.249 | 1473 | +223.33 | +0.152 |
| kept BUY | 763 | +194.20 | +0.255 | 1302 | +222.50 | +0.171 |
| kept SELL | 61 | +10.91 | +0.179 | 171 | +0.83 | +0.005 |
Reading: the removed trades are close to break-even after costs (−0.03 to −0.05R each) while the
kept trades earn +0.15 to +0.25R each. The veto does not find big losers; it drops about a quarter
of the trades, the ones with no edge, and with them the long flat-to-down stretches. The two
halves of the veto are carried by different windows: the SELL half by the rising 3-year window,
the BUY half by the falling years of the long window. Only the symmetric rule holds on both.
Share of trades that reach +1R before −1R (same entries, fixed 1R target, `--fixed-rr-tp 1.0`,
$0.65): M15 W3 58.6% → 61.4% (1105 → 824 trades), M15 LONG 55.9% → 58.2%; M5 W3 56.8% → 58.2%,
M5 LONG 55.3% → 56.1%.
Checklist breakdowns, M15 W3 → with the veto (trades / R), $0.65:
| Slice | Control | Veto | Change in R |
|---|---|---|---|
| regime ranging | 140 / +46.75 | 106 / +49.23 | +2.48 |
| regime transitioning | 264 / +47.05 | 199 / +49.47 | +2.42 |
| regime trending_down | 165 / −4.39 | 43 / +9.71 | +14.10 |
| regime trending_up | 536 / +106.38 | 476 / +96.70 | −9.68 |
| volatility extreme | 508 / +103.91 | 361 / +95.86 | −8.05 |
| volatility high | 228 / +4.00 | 135 / +18.32 | +14.32 |
| volatility normal | 202 / +58.96 | 177 / +57.01 | −1.96 |
| volatility low | 167 / +28.92 | 151 / +33.94 | +5.01 |
| BUY | 869 / +201.79 | 763 / +194.20 | −7.59 |
| SELL | 236 / −6.00 | 61 / +10.91 | +16.91 |
| setup GENERIC | 1004 / +184.73 | 757 / +192.15 | +7.42 |
| setup XAU_ATR | 101 / +11.07 | 67 / +12.97 | +1.90 |
| Monday | 188 / +36.54 | 145 / +52.46 | +15.92 |
| Tuesday | 240 / +44.89 | 186 / +41.82 | −3.07 |
| Wednesday | 234 / +12.08 | 165 / +13.36 | +1.28 |
| Thursday | 216 / +63.84 | 157 / +70.36 | +6.51 |
| Friday | 214 / +33.51 | 162 / +21.04 | −12.47 |
| Sunday evening | 13 / +4.94 | 9 / +6.08 | +1.14 |
By entry hour (UTC), change in R on W3 / on LONG: 03 +0.3 / +1.5; 04 −2.1 / −0.1; 05 −0.2 / +2.6;
06 +1.9 / −1.5; 07 +2.9 / +0.9; 08 −5.3 / −0.3; 09 −6.6 / −4.0; 12 −2.9 / +2.7; 14 +11.8 / +12.9;
15 −4.0 / +1.8; 17 −0.5 / −2.4; 18 +11.4 / +11.3; 19 +0.9 / +2.7; 20 +0.8 / +2.9; 22 +0.8 / −0.1.
The weekday and hour changes are not stable in sign between the two windows except hours 14 and 18
(positive in both) and hour 9 (negative in both); none of it is a reason to act.
### 5.7 Verdict T
- **M15: `both` PASSES every clause and SHIPS** (`pair_signals/xauusd.py`, M15 override 7).
- **M5: no veto.** `both` deepens the worst losing run (10.1R → 15.2R) and loses the long window;
`buy` passes the 3-year window and fails the long one, with no plateau. The M5 book earns
almost all of its R in 2025–2026 and the daily trend adds nothing reliable to it.
- **H1 / H4: no veto.** H1 loses 10R of 70R; H4 already confirms on the daily chart.
- On the timeframes without the veto the daily trend is shown on the alert as information only.
What the owner gives up, as agreed: in the purely rising stretch the veto costs R. W2 first half
(2024-09 → 2025-09) +61.83R vs +70.10R; the RISING window +63.78R vs +68.50R; W2 at $0.30
+166.22R vs +167.53R. What it buys: the worst losing run on the 3-year window falls from 20.9R to
12.4R, on the 7.6-year window from 64.8R to 41.5R, 2022 turns from −24.6R to +3.2R, and the three
weeks after the test window (HOLDOUT, never seen by any tuning) lose 4.6R instead of 6.6R. 2021
does not improve (−27.3R vs −25.6R) and 2023 is worse (+1.8R vs +11.7R): in a year that chops
sideways the daily trend flips late and the veto cannot help.
### 5.8 Candidate C — wide-stop cap on M15 (post-T control)
Control = the factory configuration after the M15 flip (daily-trend veto on). Command per row:
`venv/bin/python backtest/cudaBasedBacktesting.py --pair XAUUSD --primary-tf 15min --start <s>
--end <e> --spread <0.65|0.30> [--set xau_strategy.wide_stop_cap_atr=<K>] --export-csv <out>`.
Paired proof on this control: W3, K = 6, `gpu_backtest.py --workers 12` and the twin both give
`f94f1429fb4c9172427ea34c2f4d92a1` (824 / +216.87R / DD 11.37).
| Window | Cost | K | Trades | Total R | Win rate | PF | Max DD | First half | Second half | MD5 (8) |
|---|---|---|---|---|---|---|---|---|---|---|
| W3 | $0.65 | off | 824 | +205.12 | 63.1% | 1.73 | 12.4 | +76.72 | +128.40 | ad3b0dbd |
| W3 | $0.65 | 5 | 824 | +211.26 | 61.4% | 1.74 | 15.0 | +81.77 | +129.48 | 055d72a4 |
| W3 | $0.65 | **6** | 824 | +216.87 | 62.9% | 1.78 | 11.4 | +80.67 | +136.20 | f94f1429 |
| W3 | $0.65 | 7 | 824 | +213.15 | 63.1% | 1.76 | 11.8 | +79.08 | +134.07 | 5ea4ab4b |
| W3 | $0.65 | 8 | 824 | +208.01 | 62.9% | 1.74 | 12.3 | +77.18 | +130.84 | 372ac298 |
| W3 | $0.30 | off | 824 | +221.18 | 63.6% | 1.81 | 11.4 | +86.41 | +134.77 | 96a87454 |
| W3 | $0.30 | 5 | 824 | +228.46 | 62.1% | 1.82 | 14.0 | +92.27 | +136.18 | 7453b5f7 |
| W3 | $0.30 | **6** | 824 | +233.37 | 63.6% | 1.86 | 11.0 | +90.67 | +142.70 | bf7e4157 |
| W3 | $0.30 | 7 | 824 | +229.37 | 63.7% | 1.84 | 11.0 | +88.88 | +140.48 | e44cb5b5 |
| W3 | $0.30 | 8 | 824 | +224.12 | 63.5% | 1.82 | 11.3 | +86.91 | +137.22 | c214455b |
| W2 | $0.65 | off | 597 | +155.89 | 64.3% | 1.78 | 11.4 | +61.83 | +94.06 | dfc647ee |
| W2 | $0.65 | 5 | 597 | +156.59 | 63.3% | 1.79 | 11.4 | +62.63 | +93.96 | 5e5c0207 |
| W2 | $0.65 | **6** | 597 | +160.79 | 64.0% | 1.81 | 11.4 | +61.31 | +99.48 | 3614c98a |
| W2 | $0.65 | 7 | 597 | +158.70 | 64.3% | 1.79 | 11.4 | +60.19 | +98.51 | afa7eb01 |
| W2 | $0.65 | 8 | 597 | +156.58 | 64.2% | 1.78 | 11.4 | +60.54 | +96.04 | ba29cc41 |
| RISING | $0.65 | off | 258 | +63.78 | 64.3% | 1.80 | 9.1 | +23.97 | +39.81 | e87b6de1 |
| RISING | $0.65 | 5 | 258 | +57.68 | 61.6% | 1.71 | 8.0 | +22.85 | +34.83 | 295731a3 |
| RISING | $0.65 | **6** | 258 | +58.03 | 64.0% | 1.72 | 8.6 | +23.84 | +34.19 | 8dba71d7 |
| RISING | $0.65 | 7 | 258 | +62.18 | 64.3% | 1.78 | 8.8 | +26.44 | +35.74 | c461380f |
| RISING | $0.65 | 8 | 258 | +62.12 | 63.6% | 1.77 | 9.1 | +24.06 | +38.07 | fce21577 |
| LONG | $0.65 | off | 1473 | +223.33 | 59.7% | 1.42 | 41.5 | | | aa5253aa |
| LONG | $0.65 | 5 | 1473 | +204.76 | 58.4% | 1.38 | 53.1 | | | b365f28f |
| LONG | $0.65 | **6** | 1473 | +233.56 | 59.7% | 1.44 | 47.2 | | | 4aa12918 |
| LONG | $0.65 | 7 | 1473 | +228.83 | 59.8% | 1.43 | 46.5 | | | 6e91e0dd |
| LONG | $0.65 | 8 | 1473 | +223.79 | 59.7% | 1.42 | 43.2 | | | 36267a43 |
| LONG | $0.30 | off | 1473 | +257.25 | 60.8% | 1.50 | 37.2 | | | 1835b341 |
| LONG | $0.30 | 5 | 1473 | +241.64 | 59.8% | 1.46 | 44.9 | | | 6a346020 |
| LONG | $0.30 | **6** | 1473 | +268.63 | 60.8% | 1.52 | 41.6 | | | 526ffa4a |
| LONG | $0.30 | 7 | 1473 | +263.16 | 60.9% | 1.51 | 42.1 | | | 3f42a60e |
| LONG | $0.30 | 8 | 1473 | +257.84 | 60.8% | 1.50 | 38.9 | | | ffbba3e4 |
| HOLDOUT | $0.65 | off, 6, 7, 8 | 18 | −4.62 | 50.0% | 0.50 | 4.8 | | | fa50bcd0 |
| HOLDOUT | $0.65 | 5 | 18 | −4.62 | 50.0% | 0.50 | 4.8 | | | 3ff32a0d |
(W2 and RISING at $0.30 and the HOLDOUT at $0.30 are in the same direction as the $0.65 rows:
W2 +171.35 vs +166.22 for K = 6; RISING +64.66 vs +70.24; HOLDOUT unchanged.)
LONG per calendar year ($0.65), total R (trades are identical: 88 / 207 / 121 / 149 / 163 / 275 /
341 / 129):
| K | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | 2026 |
|---|---|---|---|---|---|---|---|---|
| off | +14.0 | +45.1 | −27.3 | +3.2 | +1.8 | +53.5 | +92.5 | +40.6 |
| 5 | +19.0 | +27.9 | −32.4 | −1.0 | +2.5 | +63.1 | +89.2 | +36.6 |
| 6 | +19.5 | +46.7 | −31.8 | +1.8 | +4.7 | +59.8 | +88.1 | +44.8 |
| 7 | +16.5 | +45.4 | −32.2 | +4.3 | +1.8 | +59.2 | +91.1 | +42.7 |
| 8 | +14.5 | +43.9 | −29.0 | +3.4 | +2.9 | +54.4 | +92.3 | +41.4 |
Trades the cap touches (the trade set is identical by construction; only stops, and through them
results, move). All of them are swing (GENERIC) setups; the gold ATR setup is never capped:
| Window | K | Stops changed | R of those trades: control → capped |
|---|---|---|---|
| W3 | 5 / 6 / 7 / 8 | 281 / 168 / 89 / 44 | +66.4 → +72.5 / +49.2 → +60.9 / +25.6 → +33.6 / +12.2 → +15.1 |
| LONG | 5 / 6 / 7 / 8 | 597 / 350 / 170 / 83 | +97.5 → +78.9 / +56.7 → +66.9 / +37.0 → +42.5 / +12.5 → +13.0 |
| RISING | 5 / 6 / 7 / 8 | 97 / 58 / 25 / 12 | +28.1 → +22.0 / +21.0 → +15.3 / +13.1 → +11.5 / +5.7 → +4.0 |
| HOLDOUT | 5 / 6 / 7 / 8 | 3 / 0 / 0 / 0 | −3.03 → −3.04 |
**Rule C, K = 6**
| Clause | Result | Numbers |
|---|---|---|
| W3 change in R ≥ +5R | PASS | +11.75 (+216.87 vs +205.12) |
| W3 first half ≥ control − 1R | PASS | +80.67 vs +76.72 |
| W3 second half ≥ control − 1R | PASS | +136.20 vs +128.40 |
| W3 PF ≥ control − 0.02 | PASS | 1.777 vs 1.734 |
| W3 max DD ≤ control + 10% | PASS | 11.37 vs 12.39 |
| LONG total R ≥ control | PASS | +233.56 vs +223.33 (but max DD 47.19 vs 41.54) |
| same sign at $0.30 | PASS | +12.19 (+233.37 vs +221.18) |
| ≥ 20 trades differ | PASS | 168 stops and results changed |
| neighbour K = 5 not negative on W3 | PASS | +6.14 |
| **neighbour K = 5 not negative on LONG** | **FAIL** | **−18.57** |
| neighbour K = 7 not negative on W3 | PASS | +8.04 |
| neighbour K = 7 not negative on LONG | PASS | +5.50 |
**Verdict C: FAIL. Nothing ships; `wide_stop_cap_atr` stays 0.0 (research knob only).** K = 6 is a
narrow peak, not a plateau: one step tighter loses 18.6R over the long window (2020 alone −17R),
one step wider keeps half the gain, two steps wider keeps none. The cap also costs R in the rising
window at every K (−1.6R to −6.1R), deepens the long-window drawdown at every K (41.5R → 43.2R to
53.1R) and changes nothing in the unseen three weeks. This agrees with the planning-phase screen
of 25 stop and exit variants: the stop geometry is at a plateau, and tightening it is the one
direction that reliably loses. No second K is tried (the rule's no-rescue clause).
### 5.9 What shipped, and the re-pinned books
Shipped: `pair_signals/xauusd.py` M15 override 7, `config.xau_strategy.daily_trend_veto = "both"`
on M15 only. Not shipped: any veto on M5 / H1 / H4; the wide-stop cap (knob kept at 0.0).
Reference books after the flip, factory configuration, `--spread 0.65`, regenerated with BOTH
scripts (`gpu_backtest.py --workers 12` and `cudaBasedBacktesting.py`), `Backend: CuPy GPU
(NVIDIA GeForce RTX 4070 SUPER, cupy 14.0.1)`, `GPU cache fallbacks: 0`:
| Book | Window | Trades / R / PF / DD | MD5 (reference = twin) | |
|---|---|---|---|---|
| M5 W2 | 2024-09-05 → 2026-09-05 | 781 / +146.07 / 1.52 / 10.1 | `e599c8a8652f95b7fcdf5a7ef2b564f5` | unchanged |
| M15 W2 | 2024-09-05 → 2026-09-05 | 597 / +155.89 / 1.78 / 11.4 | `dfc647ee02afd179dd9e031f344ed380` | re-pinned (was `5b65ecf6…`, 813 / +154.15 / 1.53) |
| M15 OOS | 2024-06-01 → 2025-03-30 | 258 / +63.78 / 1.80 / 9.1 | `e87b6de12f90f3b5a5d41a953ee9ff7a` | re-pinned (was `09b8a8e7…`, 313 / +68.50 / 1.67) |
| H1 W3 | 2023-09-05 → 2026-09-05 | 253 / +70.02 / 1.98 / 4.4 | `a44fd19b4067f46e5bd98d50cc3eff92` | unchanged |
| H4 W3 | 2023-09-05 → 2026-09-05 | 114 / +21.7 / 1.59 | `f3587bae3c5dc3eda468ea3588b17dcb` | unchanged |
| M15 W3 | 2023-09-05 → 2026-09-05 | 824 / +205.12 / 1.73 / 12.4 | `ad3b0dbda0bf77b659caea1c53be6a50` | was `70195fb0…`, 1105 / +195.79 / 1.49 |
The factory books are byte-identical to the `--set xau_strategy.daily_trend_veto=both` books of
section 5.2, as they must be.
### 5.10 A fetch bug found on the way (fixed, not a signal change)
The first HOLDOUT and RISING runs with the daily frame failed with `OandaDataError: XAU/USD 1d:
3 consecutive failures fetching window 2020-08-01–2020-08-01 … (Empty candle response)`. Since
2026-09-13 `fetch_range` retries a failing page and aborts after three tries, while the Oanda
provider raised on an EMPTY date window. A padded window that starts on a closed day (the daily
pad is 1,400 days = exactly 200 weeks, so a window starting on a Saturday pads to a Saturday)
begins with a page nothing traded in, and the whole fetch aborted. Fix in `providers/oanda.py`:
a DATE-WINDOW request with no candles returns an empty frame (a `count` request, the live path,
still raises); two Module 15 tests. Books are unaffected (every pinned window was already cached;
the ten MD5s reproduce). New cache files fetched for this campaign: the daily frames
`oanda_XAU_USD_1d_20201105_20260905`, `_20150303_20260807`, `_20200801_20250330`,
`_20221105_20261001`, and the HOLDOUT window `5min` / `15min` / `1h` `_20260705_20261001` and
`4h_20260114_20261001`. The two interior gaps the HOLDOUT fetch logged are market closures
(Labor Day 2026-09-07, Good Friday 2026-04-02), not dropped pages.
### 5.11 Setup size: what the evidence supports, and the display lines that shipped
"Trade setup size" was tested two ways.
**The stop itself.** Candidate C (section 5.8) fails its rule, and the planning-phase screen of
25 stop and exit variants found nothing better than the shipped geometry (a flat 2 × ATR stop on
M15 turns +196R into +3R). The stops stay as they are.
**How much is at risk at once.** If every alert is taken, the plans pile up. Shipped books, W3,
$0.65 (`M15` = veto on):
| Books taken together | Trades | Same-direction plans already open at an entry: mean | median | max | Entries with ≥ 1 open | with ≥ 3 open | Open at once while anything is open: mean | max | Share of the time something is open |
|---|---|---|---|---|---|---|---|---|---|
| M15 alone | 824 | 1.17 | 1 | 6 | 62% | 15% | 1.70 | 7 | 41% |
| M5 alone | 870 | 0.69 | 0 | 6 | 40% | 7% | 1.36 | 7 | 23% |
| M5 + M15 | 1694 | 1.70 | 1 | 12 | 66% | 26% | 1.97 | 13 | 51% |
| M5 + M15 + H1 | 1947 | 2.75 | 2 | 15 | 78% | 43% | 2.60 | 16 | 65% |
The stacked entries are not worse trades (M5 + M15, by the number of same-direction plans already
open at the entry: 0 → +0.154R per trade over 577; 1 → +0.218R over 410; 2 → +0.241R over 271;
3–4 → +0.282R over 267; 5 or more → +0.236R over 169). So there is no evidence for skipping them,
and the 2026-09-06 sizing campaign already showed that varying the stake by signal features does
not pay. What the numbers do say is that "1% per alert" is in practice several percent on one move
of gold. That is a sizing fact for the reader, so it ships as information, not as a gate:
- **Size line** (`exposure.py`, off until `config.json` `trade_size.risk_per_trade` is set): the
number of lots that keeps the loss at the printed stop inside the owner's risk limit, rounded
DOWN to the lot step. Private by default (owner chats and the CLI); the channel and the public
dashboard get it only with `trade_size.telegram_channel` / `trade_size.dashboard`.
- **Already-open line**: how many ALERTED plans in the same direction are still open in the
advisory outcome model (`signal_log.open_alerted_setups`, a read-only query; the bot stamps
`alerted_at` on a row once its alert reached a chat).
- **Daily-trend line** on every surface (`main.daily_trend_words`): on M15 the veto has already
removed a plan against a clear daily trend; on M5 / H1 / H4, where the veto failed its rule, the
line is context ("Daily trend: falling — this buy goes against it"). The live wrapper stamps the
trend on every logged scan row (`signals.daily_trend`), so the live record can answer the M5
question again after a few months.
None of the three is read by a gate, the backtester or the twin.
### 5.12 Final verification (2026-10-01)
- `venv/bin/python test_all.py`: **607 passed, 0 failed** (40 modules: Module 39 daily-trend veto
and wide-stop cap, Module 40 the display lines, Module 37 extended, two Module 15 tests for the
empty-window fetch).
- The five reference books regenerated with both scripts after the last code change: ten MD5s
equal the table in section 5.9.
- Recorder and feature export with the veto on, M15 2024-06-01 → 2025-03-30, `--export-features
--record DIR --record-bars` on both scripts: feature CSV `732f396bb3ee6036b62750a8c755194e` on
both; `trades` 258 × 137, `indicators` 5900 × 15, `events` 5098 × 14 and `bars` 12315 × 172
identical; both manifests carry book MD5 `e87b6de12f90f3b5a5d41a953ee9ff7a` and differ only in
`cli`, `created_at`, `replay_seconds`, `workers`; `replay_scorecard.py DIR --check`: all
invariants held.
- `agent_panel_base_rates.json` rebuilt from the re-pinned books (M15 timeframe row 597 trades,
64.3% winners, +0.261R; was 813 / 62.2% / +0.190R).
### 5.13 Independent verification (2026-10-01)
An agent that had not done the work re-derived the change list from `git diff HEAD` and
re-ran the books itself (24 on the twin, 9 on the reference script, all offline, 0 cache
fallbacks). Every figure of sections 5.2 to 5.9 it was given matched to the cent, on both
scripts where it ran both: the M15 books with the veto on and off (W3, W2, the 2024-06-01 →
2025-03-30 window, LONG with its per-year R, the holdout), the unchanged M5 / H1 / H4 pins, the
failed M5, H1, `buy` and `sell` variants, and the removed-trade tables (281 removed on W3, 0
added, all 63 columns of the 824 kept trades identical). Its own implementation of the rule
from closed daily bars predicts the removed trades exactly (281 / 281, 618 / 618, 55 / 55); the
same rule fed the still-forming day mis-predicts 52, 129 and 14 of them, so there is no
look-ahead. The scoring configuration is identical to HEAD on all four timeframes; the only
decision-side difference is the M15 veto.
It also raised four points this report did not make clearly enough. They change no verdict;
they are recorded so the size of the claim is not overstated.
1. **Clause (g) is thinner than "3 of 4" reads.** The "100-day average alone" neighbour of
table 5.5 is an EXPONENTIAL average, the same kind as the shipped 50-day one (harness key
`e100`). With a SIMPLE 100-day average the M15 W3 book is 781 / +188.68R / PF 1.70 /
drawdown 12.27R: it beats the control on profit factor and drawdown like the others, but
sits 1.2R under the 97% line (+189.92R), so with that reading the count would be 2 of 4.
The four definitions were fixed before the runs in the harness's own form and the clause
passes as written; the honest summary is "five alternative definitions, all better than the
control on profit factor and drawdown, two of them 1.2R and 1.7R short on total R".
2. **"The veto never adds a trade" is an observation, not a guarantee.** The rule itself only
removes a plan. In a book, removing an entry also moves the 5-bar cooldown, which could
free a later entry; that happened 0 times in every control / candidate pair compared (13).
3. **It is a risk filter, not a better direction call.** Nothing in how direction is scored
changed, and a vetoed bar still shows its buy or sell reading. The removed plans were close
to break-even (−0.03R each on W3, −0.05R on LONG; 55% winners against 63% for the kept
ones), so total R barely moves while profit factor and the losing runs improve.
4. **The help is concentrated.** Effect of the rule by year on LONG (shipped minus off):
2019 +4.9R, 2020 −3.7R, 2021 −1.8R, 2022 **+27.8R**, 2023 **−10.0R**, 2024 +0.1R, 2025
+11.4R, 2026 +1.9R; total +30.8R, of which 2022 (buys against a falling daily trend) is
nine tenths. On W3 the whole gain in R comes from sells removed in 2025, and the drawdown
cut from 20.9R to 12.4R is one episode: 13 sells between 2023-12-01 and 2024-02-23
(−8.5R). In a year where the daily trend flips often (2023) the rule costs. The multi-year
windows had been looked at with the prototype before rule T was written (section 2), and
the only period nobody had seen is four weeks long and differs by six trades.
Cross-checked here from the formal books (a filter on the control book reproduces the shipped
book and the exponential neighbour exactly, and gives the simple-average figure above).
## 6. Summary of decisions
| Item | Verdict |
|---|---|
| Daily-trend veto, M15, both directions | **PASSED rule T on every clause, SHIPPED** (factory M15 override 7) |
| Daily-trend veto, M15, buy-only / sell-only | FAILED (W3 R and PF / LONG drawdown and 2021–22) |
| Daily-trend veto, M5 (both, buy-only) | FAILED (W3 drawdown; LONG R, drawdown, 2021–22; no plateau) |
| Daily-trend veto, H1 | FAILED (W3 −9.7R); H4 not run |
| Wide-stop cap K = 6 on M15 | FAILED rule C (neighbour K = 5 loses 18.6R on LONG); knob kept at 0.0, research-only |
| Lot-size, already-open and daily-trend lines | SHIPPED, display only (books byte-identical) |
| Oanda empty date window | FIXED (fetch_range no longer aborts on a closed-day page) |
| Seven further context screens | no state nominated, nothing shipped (`context_screens_2026-10.md`) |
| Eight outside data sources (dollar, silver, bonds, real yield, fund flows, futures and Oanda client positioning) | none adds a forecast to gold's own daily trend; broad dollar index on M5 = WATCH; nothing shipped, no feed added (`new_inputs_2026-10.md`) |
+304
View File
@@ -0,0 +1,304 @@
# New data sources for the direction call — a report-only study, 2026-10-01
Owner decision 2026-09-30: after the daily-trend work, study new data sources and report; nothing
ships from this file. The engine reads gold's own price and nothing else. The question here is
whether anything OUTSIDE gold's own chart tells the direction better than gold's chart already
does. Sections 1 to 3 were written before any data was fetched.
## 1. Sources
| # | Source | What it is | Where from | When a value is usable |
|---|---|---|---|---|
| 1 | Dollar | EUR/USD daily candles, read upside down (a falling EUR/USD is a rising dollar) | Oanda v20 candles, the live feed's own token | daily close + 0 (same rule as gold's daily bars) |
| 2 | Silver | XAG/USD daily candles | Oanda v20 | daily close |
| 3 | US 10-year note | USB10Y_USD daily candles (price up = yields down), if Oanda offers it | Oanda v20 | daily close |
| 4 | Real yield | US 10-year inflation-indexed yield, `DFII10` | FRED (public CSV) | the day's value from two days later (it is published the next US afternoon) |
| 5 | Broad dollar index | `DTWEXBGS` | FRED | same two-day rule |
| 6 | Gold fund holdings | SPDR Gold Shares, shares outstanding (each share is a fixed slice of the vault, so creations and redemptions are the fund's gold flow) | the fund manager's public history file (`navhist-us-en-gld.xlsx`); the older tonnes archive now serves a PDF | the day's value from two days later |
| 7 | Futures positioning | CFTC disaggregated report, gold (code 088691), managed-money net long | CFTC public reporting site | a Tuesday report from the following Monday |
| 8 | Oanda client positioning | position book for XAU_USD: the share of Oanda clients' open gold positions that are long (by count) | Oanda v20 `/v3/instruments/XAU_USD/positionBook`, one snapshot per day at 00:00 UTC | at once (the snapshot is taken at the daily close) |
Everything fetched stays in the session scratchpad. Nothing is added to the repository's cache.
Amendment before any analysis (2026-10-01, after the access probes and nothing else): the plan
expected source 8 to be gone. It is not: on the practice API the position book answers for every
date probed back to 2017, so it joins the study with the definition below. The probe printed ten
long-share readings (between 60% and 75% long, higher at higher gold prices) and no forward
returns; that is everything that was seen before the definition was fixed. Source 6 uses shares
outstanding instead of tonnes because that is the file that can still be downloaded.
## 2. One state per source
The same shape as the shipped daily trend, so the comparison is like for like. For a daily series
`x` (Sunday stub bars dropped for the Oanda candles): `up` when `x` is above its 50-day EMA AND
above its value 60 days earlier, `down` when below both, else `unclear`. Read for gold:
| Source | Gold-friendly state | Gold-hostile state |
|---|---|---|
| Dollar (EUR/USD) | EUR/USD up (dollar falling) | EUR/USD down |
| Silver | up | down |
| 10-year note price | up (yields falling) | down |
| Real yield | down | up |
| Broad dollar index | down | up |
| Fund holdings | shares outstanding above the level 20 trading days earlier | below |
| Futures positioning | managed-money net long above its level 4 reports earlier | below |
| Oanda client positioning | long share `down` (the crowd is cutting longs or adding shorts) | long share `up` (the crowd is adding longs) |
The positioning state is read the contrarian way on purpose and before looking: small traders
tend to buy dips and sell rallies, so a growing long share is expected to go with a falling price.
Test A is two-sided, so if the truth is the other way round it will show as a real spread with the
opposite sign and is reported as such; Test B is judged on the declared reading only.
## 3. Two tests and the verdict rule
**Test A — forward move of gold.** Every closed gold daily bar from 2019-01-01 to 2026-08-07.
Forward move = gold's close 5 days later minus today's close, in units of gold's own 14-day ATR
(and the same for 20 days). For each source: mean forward move on gold-friendly days minus mean
on gold-hostile days, (i) over all days and (ii) inside each of gold's own three daily-trend
states (rising / falling / unclear), in two eras (2019–2023, 2024–2026). The spread is called real
only if it has the same sign in both eras and its t-value, computed on every fifth day so the
5-day windows do not overlap, is at least 2 in each era.
**Test B — the shipped books.** M15 LONG (daily-trend veto on, 1473 trades) and M5 LONG (1052
trades), $0.65. Each trade is labelled `friendly` / `hostile` / `unclear` from the source state at
its decision time, mirrored for a SELL. A source is interesting on a timeframe only if its
`hostile` trades are at least 8% of the book and lose (total R < 0) in BOTH eras.
**Verdict per source.**
- `GO` (worth a pre-registered campaign and the feed work it needs) only if Test A calls the
spread real INSIDE gold's own trend states (that is the "beyond gold's own chart" part) AND
Test B finds the hostile trades losing in both eras on at least one timeframe.
- `WATCH` if exactly one of the two holds.
- `NO-GO` otherwise, or when the source cannot be fetched reliably.
A `GO` is a ticket to a campaign, never a shipping decision: a live feed for a second instrument
needs its own provider path, cache, staleness rule and live == backtest proof.
Two points of method were fixed while the analysis script was written, before it produced any
output. (1) The broad dollar index is published weekly (the H.10 release, on Monday, for the week
before), not daily, so the "two-day rule" of the table would have looked ahead: each week's final
state is used from the Tuesday after that week. (2) "Inside gold's own trend states" is computed
as one stratified number per era: the forward move minus the mean forward move of that day's gold
trend state (rising / unclear / falling), friendly days against hostile days, t-value on every
fifth day. That is the column the verdict reads; the unstratified spread is printed beside it.
## 4. Results
Run 2026-10-01. Fetched into the session scratchpad: Oanda daily candles for EUR_USD, XAG_USD,
USB10Y_USD and XAU_USD (2015-01-01 → 2026-09-30, about 3,650 bars each, about 600 Sunday stubs
dropped); the Oanda XAU_USD position book, one snapshot per day at 00:00 UTC from 2018-06-01
(2,609 days asked, 97.7% answered at exactly 00:00, the rest from the last snapshot up to six
hours earlier, 45 days with none, all before mid-2022); FRED `DFII10` and `DTWEXBGS`; the gold
fund's history file (5,540 days since 2004); 1,059 weekly CFTC reports since 2006.
### 4.1 What was fetched
| Source | Days with a state, 2019-01-01 → 2026-08-07 | friendly / unclear / hostile | Same side as gold's own daily trend (days where both are clear) |
|---|---|---|---|
| 1 dollar (EUR/USD) | 1973 | 37% / 18% / 44% | 67% of 1363 |
| 2 silver | 1973 | 49% / 21% / 31% | 88% of 1387 |
| 3 10-year note price | 1973 | 39% / 16% / 46% | 73% of 1398 |
| 4 real yield (DFII10) | 1973 | 42% / 20% / 39% | 73% of 1353 |
| 5 broad dollar index | 1973 | 39% / 19% / 42% | 62% of 1362 |
| 6 gold fund shares | 1973 | 51% / 0% / 49% | 77% of 1639 |
| 7 futures positioning | 1973 | 51% / 0% / 49% | 59% of 1644 |
| 8 Oanda client positioning | 1973 | 37% / 15% / 48% | 36% of 1414 |
Gold itself, same days: rising 58%, unclear 17%, falling 25%; mean 5-day forward move +0.27 ATR (rising +0.32, unclear +0.30, falling +0.14).
### 4.2 Test A — gold's forward move, friendly days minus hostile days (in daily ATRs)
| Source | Era | Days friendly / hostile | 5-day spread, all days (t) | 5-day spread inside gold's trend states (t) | 20-day spread inside gold's trend states (t) | Real? |
|---|---|---|---|---|---|---|
| 1 dollar (EUR/USD) | 2019–2023 | 443 / 623 | -0.04 (-0.3) | -0.05 (-0.4) | +0.35 (+0.7) | |
| 1 dollar (EUR/USD) | 2024–2026 | 296 / 249 | +0.21 (+0.7) | +0.20 (+0.7) | +0.80 (+0.5) | |
| 1 dollar (EUR/USD) | verdict | | | same sign in both eras: no; |t| ≥ 2 in both: no | | not real |
| 2 silver | 2019–2023 | 548 / 449 | -0.21 (-0.9) | -0.25 (-1.0) | -1.00 (-1.2) | |
| 2 silver | 2024–2026 | 411 / 160 | -0.10 (-0.7) | -0.20 (-0.7) | -0.64 (-0.2) | |
| 2 silver | verdict | | | same sign in both eras: yes; |t| ≥ 2 in both: no | | not real |
| 3 10-year note price | 2019–2023 | 515 / 603 | +0.08 (+0.3) | +0.04 (+0.1) | +0.46 (+0.5) | |
| 3 10-year note price | 2024–2026 | 253 / 295 | +0.23 (+0.4) | +0.17 (+0.4) | +1.02 (-0.2) | |
| 3 10-year note price | verdict | | | same sign in both eras: yes; |t| ≥ 2 in both: no | | not real |
| 4 real yield (DFII10) | 2019–2023 | 583 / 468 | +0.04 (+0.4) | +0.01 (+0.2) | -0.20 (-0.5) | |
| 4 real yield (DFII10) | 2024–2026 | 242 / 294 | +0.20 (+0.7) | +0.14 (+0.6) | +1.22 (+0.5) | |
| 4 real yield (DFII10) | verdict | | | same sign in both eras: yes; |t| ≥ 2 in both: no | | not real |
| 5 broad dollar index | 2019–2023 | 497 / 536 | +0.03 (-0.1) | +0.02 (-0.1) | -0.12 (-0.5) | |
| 5 broad dollar index | 2024–2026 | 269 / 293 | +0.02 (-0.2) | +0.04 (-0.0) | +0.71 (+0.1) | |
| 5 broad dollar index | verdict | | | same sign in both eras: yes; |t| ≥ 2 in both: no | | not real |
| 6 gold fund shares | 2019–2023 | 609 / 681 | +0.20 (+1.4) | +0.17 (+1.2) | +0.37 (+1.0) | |
| 6 gold fund shares | 2024–2026 | 393 / 281 | +0.40 (+1.7) | +0.36 (+1.8) | +1.09 (-0.1) | |
| 6 gold fund shares | verdict | | | same sign in both eras: yes; |t| ≥ 2 in both: no | | not real |
| 7 futures positioning | 2019–2023 | 640 / 656 | +0.06 (+0.0) | +0.04 (-0.1) | +1.03 (+0.6) | |
| 7 futures positioning | 2024–2026 | 369 / 308 | -0.01 (+0.3) | +0.11 (+0.8) | +1.23 (+1.7) | |
| 7 futures positioning | verdict | | | same sign in both eras: yes; |t| ≥ 2 in both: no | | not real |
| 8 Oanda client positioning | 2019–2023 | 636 / 428 | +0.20 (+1.2) | +0.19 (+1.1) | +0.53 (+0.1) | |
| 8 Oanda client positioning | 2024–2026 | 97 / 516 | -0.01 (-0.6) | +0.33 (+0.3) | n/a (too few friendly days) | |
| 8 Oanda client positioning | verdict | | | same sign in both eras: yes; |t| ≥ 2 in both: no | | not real |
### 4.3 Test B — the shipped books, by the source's state at the trade's decision time
**M15 LONG (daily-trend veto on): 1473 trades, +223.3R** (era A = 2019–2023: 728 trades, +36.8R; era B = 2024–2026: 745 trades, +186.6R)
| Source | Trade state | Trades (share) | Total R / mean | Era A R (trades) | Era B R (trades) | Hostile ≥ 8% and losing in both eras |
|---|---|---|---|---|---|---|
| 1 dollar (EUR/USD) | friendly | 725 (49%) | +127.3 / +0.176 | +32.0 (345) | +95.4 (380) | |
| 1 dollar (EUR/USD) | unclear | 252 (17%) | +13.0 / +0.052 | -15.3 (127) | +28.3 (125) | |
| 1 dollar (EUR/USD) | hostile | 496 (34%) | +83.0 / +0.167 | +20.1 (256) | +62.9 (240) | no |
| 2 silver | friendly | 937 (64%) | +154.9 / +0.165 | +26.8 (406) | +128.0 (531) | |
| 2 silver | unclear | 304 (21%) | +1.3 / +0.004 | -18.2 (196) | +19.5 (108) | |
| 2 silver | hostile | 232 (16%) | +67.1 / +0.289 | +28.1 (126) | +39.0 (106) | no |
| 3 10-year note price | friendly | 753 (51%) | +107.0 / +0.142 | +34.6 (397) | +72.4 (356) | |
| 3 10-year note price | unclear | 254 (17%) | +39.1 / +0.154 | +11.3 (121) | +27.8 (133) | |
| 3 10-year note price | hostile | 466 (32%) | +77.2 / +0.166 | -9.2 (210) | +86.4 (256) | no |
| 4 real yield (DFII10) | friendly | 723 (49%) | +97.7 / +0.135 | +45.5 (405) | +52.2 (318) | |
| 4 real yield (DFII10) | unclear | 313 (21%) | +30.8 / +0.098 | -12.5 (142) | +43.2 (171) | |
| 4 real yield (DFII10) | hostile | 437 (30%) | +94.9 / +0.217 | +3.8 (181) | +91.1 (256) | no |
| 5 broad dollar index | friendly | 647 (44%) | +122.5 / +0.189 | +37.5 (315) | +85.0 (332) | |
| 5 broad dollar index | unclear | 277 (19%) | +17.2 / +0.062 | -4.7 (168) | +21.8 (109) | |
| 5 broad dollar index | hostile | 549 (37%) | +83.7 / +0.152 | +3.9 (245) | +79.8 (304) | no |
| 6 gold fund shares | friendly | 1031 (70%) | +183.6 / +0.178 | +52.7 (519) | +130.9 (512) | |
| 6 gold fund shares | unclear | 7 (0%) | -4.7 / -0.668 | -2.9 (4) | -1.8 (3) | |
| 6 gold fund shares | hostile | 435 (30%) | +44.4 / +0.102 | -13.1 (205) | +57.5 (230) | no |
| 7 futures positioning | friendly | 789 (54%) | +115.5 / +0.146 | +22.3 (422) | +93.3 (367) | |
| 7 futures positioning | unclear | 0 (0%) | +0.0 / | +0.0 (0) | +0.0 (0) | |
| 7 futures positioning | hostile | 684 (46%) | +107.8 / +0.158 | +14.5 (306) | +93.3 (378) | no |
| 8 Oanda client positioning | friendly | 394 (27%) | +41.7 / +0.106 | +15.9 (326) | +25.9 (68) | |
| 8 Oanda client positioning | unclear | 198 (13%) | +26.9 / +0.136 | +13.7 (122) | +13.2 (76) | |
| 8 Oanda client positioning | hostile | 881 (60%) | +154.7 / +0.176 | +7.2 (280) | +147.5 (601) | no |
**M5 LONG: 1052 trades, +128.1R** (era A = 2019–2023: 258 trades, -10.4R; era B = 2024–2026: 794 trades, +138.5R)
| Source | Trade state | Trades (share) | Total R / mean | Era A R (trades) | Era B R (trades) | Hostile ≥ 8% and losing in both eras |
|---|---|---|---|---|---|---|
| 1 dollar (EUR/USD) | friendly | 439 (42%) | +85.3 / +0.194 | -11.5 (103) | +96.8 (336) | |
| 1 dollar (EUR/USD) | unclear | 211 (20%) | +28.6 / +0.136 | -0.9 (34) | +29.5 (177) | |
| 1 dollar (EUR/USD) | hostile | 402 (38%) | +14.2 / +0.035 | +2.0 (121) | +12.2 (281) | no |
| 2 silver | friendly | 556 (53%) | +89.3 / +0.161 | -7.6 (113) | +96.8 (443) | |
| 2 silver | unclear | 143 (14%) | +7.3 / +0.051 | -9.9 (45) | +17.2 (98) | |
| 2 silver | hostile | 353 (34%) | +31.5 / +0.089 | +7.1 (100) | +24.4 (253) | no |
| 3 10-year note price | friendly | 432 (41%) | +51.6 / +0.120 | -0.6 (119) | +52.2 (313) | |
| 3 10-year note price | unclear | 169 (16%) | -9.5 / -0.056 | -13.7 (49) | +4.2 (120) | |
| 3 10-year note price | hostile | 451 (43%) | +86.0 / +0.191 | +3.9 (90) | +82.1 (361) | no |
| 4 real yield (DFII10) | friendly | 377 (36%) | +4.2 / +0.011 | -15.0 (115) | +19.2 (262) | |
| 4 real yield (DFII10) | unclear | 186 (18%) | +32.3 / +0.174 | -7.0 (45) | +39.3 (141) | |
| 4 real yield (DFII10) | hostile | 489 (46%) | +91.6 / +0.187 | +11.6 (98) | +80.0 (391) | no |
| 5 broad dollar index | friendly | 447 (42%) | +131.2 / +0.294 | -0.7 (91) | +131.9 (356) | |
| 5 broad dollar index | unclear | 170 (16%) | +8.1 / +0.047 | -6.0 (40) | +14.1 (130) | |
| 5 broad dollar index | hostile | 435 (41%) | -11.2 / -0.026 | -3.7 (127) | -7.5 (308) | YES |
| 6 gold fund shares | friendly | 600 (57%) | +86.9 / +0.145 | -15.8 (142) | +102.7 (458) | |
| 6 gold fund shares | unclear | 3 (0%) | -1.8 / -0.608 | +0.0 (0) | -1.8 (3) | |
| 6 gold fund shares | hostile | 449 (43%) | +43.0 / +0.096 | +5.4 (116) | +37.6 (333) | no |
| 7 futures positioning | friendly | 493 (47%) | +41.1 / +0.083 | -17.0 (120) | +58.1 (373) | |
| 7 futures positioning | unclear | 0 (0%) | +0.0 / | +0.0 (0) | +0.0 (0) | |
| 7 futures positioning | hostile | 559 (53%) | +87.0 / +0.156 | +6.6 (138) | +80.4 (421) | no |
| 8 Oanda client positioning | friendly | 313 (30%) | +17.9 / +0.057 | -1.9 (99) | +19.8 (214) | |
| 8 Oanda client positioning | unclear | 92 (9%) | +2.3 / +0.025 | +0.5 (40) | +1.9 (52) | |
| 8 Oanda client positioning | hostile | 647 (62%) | +107.9 / +0.167 | -8.9 (119) | +116.9 (528) | no |
### 4.4 Verdict per source
| Source | Test A: real spread beyond gold's own trend | Test B: hostile trades ≥ 8% and losing in both eras (M15 / M5) | Verdict |
|---|---|---|---|
| 1 dollar (EUR/USD) | no | no / no | NO-GO |
| 2 silver | no | no / no | NO-GO |
| 3 10-year note price | no | no / no | NO-GO |
| 4 real yield (DFII10) | no | no / no | NO-GO |
| 5 broad dollar index | no | no / yes | WATCH |
| 6 gold fund shares | no | no / no | NO-GO |
| 7 futures positioning | no | no / no | NO-GO |
| 8 Oanda client positioning | no | no / no | NO-GO |
### 4.5 The one flag, looked at more closely (after the fact: description, not a test)
**M5 LONG: gold's own daily trend (rows) x 5 broad dollar index (columns)** — total R (trades)
| Gold's own daily trend vs the trade | dollar friendly | dollar unclear | dollar hostile |
|---|---|---|---|
| with | +118.8 (352) | +1.9 (105) | -0.1 (215) |
| unclear | +6.8 (33) | -2.1 (12) | +2.3 (73) |
| against | +5.6 (62) | +8.3 (53) | -13.3 (147) |
**M5 LONG: gold's own daily trend (rows) x 1 dollar (EUR/USD) (columns)** — total R (trades)
| Gold's own daily trend vs the trade | dollar friendly | dollar unclear | dollar hostile |
|---|---|---|---|
| with | +76.8 (372) | +23.0 (109) | +20.7 (191) |
| unclear | +4.5 (37) | -5.5 (19) | +7.9 (62) |
| against | +4.0 (30) | +11.1 (83) | -14.4 (149) |
**M5 LONG: broad-dollar hostile trades by year** — 2019: +1.4 (14); 2020: -3.4 (45); 2021: -0.6 (21); 2022: -1.1 (36); 2023: -0.1 (11); 2024: +3.5 (68); 2025: -8.5 (107); 2026: -2.4 (133)
**M5 LONG: broad-dollar friendly trades by year** — 2019: -1.5 (3); 2020: +0.0 (45); 2021: -0.0 (9); 2022: +0.0 (7); 2023: +0.7 (27); 2024: -0.1 (19); 2025: +40.3 (160); 2026: +91.7 (177)
W3 friendly: 397 trades (46%), +145.1R, halves +8.2 / +136.9
W3 unclear: 150 trades (17%), +15.6R, halves -3.0 / +18.7
W3 hostile: 323 trades (37%), -7.1R, halves +11.6 / -18.7
**M15 LONG (veto on): gold's own daily trend (rows) x 5 broad dollar index (columns)** — total R (trades)
| Gold's own daily trend vs the trade | dollar friendly | dollar unclear | dollar hostile |
|---|---|---|---|
| with | +93.2 (561) | +48.0 (196) | +68.5 (416) |
| unclear | +29.3 (86) | -30.8 (81) | +15.2 (133) |
| against | +0.0 (0) | +0.0 (0) | +0.0 (0) |
**M15 LONG (veto on): gold's own daily trend (rows) x 1 dollar (EUR/USD) (columns)** — total R (trades)
| Gold's own daily trend vs the trade | dollar friendly | dollar unclear | dollar hostile |
|---|---|---|---|
| with | +99.4 (635) | +41.8 (176) | +68.5 (362) |
| unclear | +27.9 (90) | -28.8 (76) | +14.5 (134) |
| against | +0.0 (0) | +0.0 (0) | +0.0 (0) |
**M15 LONG (veto on): broad-dollar hostile trades by year** — 2019: +12.5 (57); 2020: +11.5 (74); 2021: -6.7 (44); 2022: -9.2 (43); 2023: -4.1 (27); 2024: +65.1 (179); 2025: +9.9 (95); 2026: +4.8 (30)
**M15 LONG (veto on): broad-dollar friendly trades by year** — 2019: +4.7 (16); 2020: +25.0 (114); 2021: -8.9 (46); 2022: +8.2 (51); 2023: +8.5 (88); 2024: -4.4 (56); 2025: +52.1 (192); 2026: +37.3 (84)
W3 friendly: 373 trades (45%), +103.5R, halves +4.0 / +99.4
W3 unclear: 130 trades (16%), +28.2R, halves +6.2 / +22.1
W3 hostile: 321 trades (39%), +73.4R, halves +66.5 / +6.9
### 4.6 Reading
- **Nothing outside gold's own chart passes Test A.** For all eight sources the 5-day forward move
of gold on "friendly" days is not reliably different from "hostile" days once gold's own daily
trend is accounted for (largest t-values 1.2 and 1.8, the gold fund's share count; everything
else is under 1.2 in at least one era). The familiar stories (a falling dollar, falling real
yields, rising silver, fund inflows) describe gold's past move well: they sit on the same side
as gold's own daily trend on 59% to 88% of clear days. They do not add a forecast to it.
- **Oanda client positioning is available but not useful in this form.** The plan expected the
endpoint to be gone; it answers, with history back to 2017. Read the contrarian way (a growing
long share is hostile), the spread has the expected sign and no weight (t 1.1 and 0.3), and in
2024–2026 the crowd was adding longs on 516 of 613 clear days while gold rose. The trades taken
on those "hostile" days are the best part of both books. Only the daily state was tested; the
intraday snapshots (one per hour) were not.
- **The one flag is the broad dollar index on M5** (`WATCH`): the 435 M5 trades taken against the
dollar's trend lost 11.2R in total and lost in both eras, while the 447 taken with it made
+131.2R. The closer look shows what that is. All of the M5 profit sits in one cell: trades with
gold's own daily trend AND with the dollar's trend (+118.8R over 352 trades); the same trades
against the dollar's trend made nothing (−0.1R over 215). But every R of the friendly side was
earned in 2025 and 2026 (+40.3R and +91.7R), that is inside the one long rally from 2,600 to the
March 2026 peak (in 2025 the broad dollar fell 7.5% while gold rose 65%); before 2025 the
dollar's state separates nothing on M5 because the M5 book earned nothing at all. In the 3-year
window the hostile trades are positive in the first half (+11.6R) and negative only in the
second (−18.7R). On M15 the same state separates nothing: the hostile
trades made +65R in 2024 alone, a year when gold and the dollar rose together. The timelier
dollar measure (EUR/USD) shows the same lean on M5 without losing in both eras. So this is one
market phase seen from another angle, not a second source of information; it stays a
hypothesis, and it is the same picture as the context screens: M5 pays only when everything
agrees and has paid only since 2025.
### 4.7 Verdict
| Source | Verdict | Why |
|---|---|---|
| Dollar via EUR/USD | NO-GO | no forward spread; hostile trades are not losers in both eras |
| Silver | NO-GO | 88% the same information as gold's own trend; the spread has the wrong sign |
| US 10-year note | NO-GO | no forward spread |
| Real yield | NO-GO | no forward spread; on M5 the "hostile" trades are the better ones |
| Broad dollar index | WATCH | M5 trades against it lose in both eras, but the forward test finds nothing and the effect is the 2025–2026 phase; weekly data, four to ten days old when used |
| Gold fund share count | NO-GO | the nearest miss in the forward test (t 1.2 and 1.8), nothing on the books |
| Futures positioning | NO-GO | no forward spread, no difference on the books |
| Oanda client positioning | NO-GO in this daily form | available, but the contrarian reading failed in the rising years |
**Nothing ships and no feed is added.** The direction call was improved by the one input that
passed a formal test, gold's own daily chart on M15. If the M5 question is taken up again, the
honest test is forward: `signals.daily_trend` is now logged on every scan, so a few months of live
M5 rows can be split by the daily trend, and by the dollar's trend after the fact, without touching
the signal code.