1454ea1838
Live signals.db review (2026-09-04 → 09-25, 100 unique setups replayed on the scans' stored candles): the stop-hunt claim is refuted (71% of stop-outs ran ≥ 1R past the stop, the same as the books' 70–72%); −25.1R of the −37.8R raw live book were consecutive-bar re-entries the backtester's 5-bar cooldown never takes; the cooldown view sits at the 3rd–5th percentile of the books' three-week windows. Delivery (book-neutral): - telegram_bot: 5-bar alert cooldown per timeframe (_ALERT_COOLDOWN_BARS = backtest.cooldown_bars); setup block prints the trail first as the tested exit, TP1/TP2 as guides with their R, "Planned TP1 RR", and one validated-book line per setup class (agent_panel_base_rates.json); the informational 100-pip TP line is removed (owner request). - AI block rewritten for a new trader: "AI check: the odds look better than / worse than / about usual", the chance "in 100" against the usual odds, one reason for and one against, no verdict word or confidence figure; rendered whenever the verdict carries a probability. agent_panel: persona prompts ban trading jargon (PANEL_PROMPT_VERSION v2.1-2026-09-26); the macro-source verdict now carries its persona's p_win (every live v2 row had panel_probability NULL). Dashboard and guides mirror the wording. - telegram_bot: level-breach rescans skip the settlement-pause window (the 20:45 M15 bar was re-logged at 22:01/22:06/22:11 every evening). Signal (pre-registered rule-1 campaign, CUDA twin paired with gpu_backtest.py): - M15 grade-A SELLs blocked (sell_min_quality ["A+","B"], M15 override 6): W2 813/+154.15R PF 1.53 vs 931/+146.14R PF 1.43, OOS +68.5 vs +60.67, W3 max DD 20.9 vs 19.3R. PASSED a–f. - Printed target 1 floored at 1R in every generator (signals.tp_print_floor_rr), applied AFTER the min-RR and spread gates so no trade changes; mirrored in cuda_signal_kernels.py K2. Label-only re-pin of all four timeframes (only tp1/rr_planned columns move). A floor applied before the gate cost −24.6R and was rejected. - FAILED: M15 min_rr_ratio 1.0 (trade-identical, −2.0R). Owner's call: M5 tp_floor_rr 1.0 (+48.9R W2, max DD 10.1 → 15.9R), not shipped. New pins: M5 W2 e599c8a8…, M15 W2 5b65ecf6…, M15 OOS 09b8a8e7…, H1 W3 a44fd19b…, H4 W3 f3587bae…; twin and reference MD5s equal on every window. Base-rate table rebuilt from the new pins. Suite 558 passed. Evidence: backtest/research/rr_and_sell_campaign_2026-09-26.md (plus the 2026-09-18 loss-anatomy and wrong-direction reports it builds on). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
342 lines
20 KiB
Python
342 lines
20 KiB
Python
"""XAU/USD signal producer config.
|
||
|
||
PlatformConfig defaults ARE the tuned XAU/USD configuration, so this
|
||
factory sets the timeframes plus documented per-timeframe overrides.
|
||
It must stay equivalent to the inline PlatformConfig(symbol=XAUUSD,
|
||
...) construction (plus those overrides) used by the backtester and
|
||
Telegram bot (enforced by a test in test_all.py).
|
||
|
||
M15 override (validated 2026-07-11, window 2025-03-30 -> 2026-05-31,
|
||
$0.30 spread, trailing exits): tp_floor_rr 1.0 scores +116.6R/460
|
||
trades PF 1.83 vs +105.4R/424 PF 1.82 at the 0.5 default — better in
|
||
both train/val halves and on the 2024-06 -> 2025-03 out-of-sample
|
||
window (+30.3R vs +10.6R; the 1R floor lifts targets past the min-TP
|
||
spread gate, roughly doubling trades there). The same knob HURTS M5
|
||
(pinned 12mo book: +131.3R/699 vs +139.9R/547, PF 1.55 vs 1.78), so it
|
||
is per-timeframe, exactly as PENDING_STEPS' decision rule anticipated.
|
||
|
||
M15 override 2 (validated 2026-07-11, 12mo window 2025-07-11 ->
|
||
2026-07-11 + OOS 2024-06-01 -> 2025-03-30, $0.30 spread): block the
|
||
mixed "trending" regime (ADX strong but EMAs unaligned — momentum
|
||
without directional structure). Those trades lost -6.8R/24 on 12mo,
|
||
negative in BOTH halves; blocking scores +65.7R/499 PF 1.38 DD 10.4R
|
||
vs +59.0R/521 PF 1.32 DD 12.6R baseline, better in both halves. OOS
|
||
is neutral (-1.4R = the 4 such trades that existed there; no power to
|
||
confirm or refute). M5 never trades this regime (its gates already
|
||
exclude it), so the block is M15-only. A second candidate — blocking
|
||
transitioning-regime SELLs (-4.0R/47 on 12mo) — was REJECTED: those
|
||
sells made +5.7R/32 in the 2024 OOS window (bull-market artifact).
|
||
|
||
M15 override 3 (validated 2026-07-16, 5-year replay 2021-07-17 ->
|
||
2026-07-16 under the audit-fixed backtester, $0.30 spread, trailing
|
||
exits): block SELL entries whose bar CLOSES at 15:00 or 17:00 UTC
|
||
(sell_blocked_hours_utc=[15, 17], gate 6g3 — BUYs unaffected; those
|
||
hours flank the already-blocked hour 16). The pocket lost -33.5R/165
|
||
trades, negative in 6/6 calendar years and in BOTH halves of the last
|
||
12 months (H1 -6.8R, H2 -4.2R); each hour independently is 5/6 years
|
||
negative with both halves negative (hours 14/18 fail that screen and
|
||
stay open). Cross-TF the M5 book CONFIRMS (same pocket -14.1R/59,
|
||
5/6 years negative) rather than contradicts — unlike the rejected
|
||
trending_down block. Full replay with the gate: +176.7R/1627 PF 1.31
|
||
DD 29.1R vs +144.9R/1781 PF 1.22 DD 34.4R control; better in ALL SIX
|
||
years; last-12mo halves both improve (H1 +36.3 vs +29.5, H2 +46.9 vs
|
||
+43.2; 12mo PF 1.55 vs 1.43); OOS 2024-06-01 -> 2025-03-30 improves
|
||
(+45.4R PF 1.47 DD 17.8 vs +41.9R PF 1.39 DD 21.7). SELL side goes
|
||
-1.2R -> +30.6R over 5 years. BUYs at those hours made +34.3R, hence
|
||
SELL-only rather than a blocked_hours_utc entry. Mechanism: NY-session
|
||
shorts against gold's macro uptrend (15:00 = post-US-data reversal
|
||
window, 17:00 = London close unwind).
|
||
|
||
M5 override 2 (2026-07-16, chart patterns): enable BUY-only CP on M5
|
||
(inv_hs, double_bottom, bull_flag — drop all bearish patterns). SELL CP
|
||
is consistently negative (OOS -3.21R, 5yr +3.76R PF 1.07) while BUY CP
|
||
is positive across windows: 12mo +41.8R PF 1.60 (train +9.66 PF 1.30,
|
||
val +32.17 PF 1.86), 5yr +65.2R PF 1.48, OOS +1.20R (aggregate
|
||
positive, val half -1.89R — marginal but sign-correct in aggregate).
|
||
Gold's structural uptrend makes bullish patterns fundamentally more
|
||
reliable. M15/H1 fail on all windows; M5-only enablement.
|
||
|
||
M5 override 3 (validated 2026-07-21, 5-year replay 2021-07-21 ->
|
||
2026-07-21, $0.30 spread, next-open fills): trailing distance widened
|
||
to 0.85R (trail_dist_r 0.85, arm unchanged 0.60). Same 30-cell grid
|
||
methodology as the M15 campaign, opposite finding — on M5 the arm
|
||
point barely matters; the winners need a looser leash. Plateau arm
|
||
0.5-0.7 x dist 0.85-1.0 (+227..+234R vs +218.0R baseline). Chosen
|
||
0.60/0.85 (OOS-preferred end of the plateau): +231.2R/2028 PF 1.30 WR
|
||
57.1% vs +218.0R PF 1.29 WR 58.3%; both last-12mo halves better
|
||
(+56.8/+115.1 vs +54.0/+104.6); 5yr max DD 19.2R vs 19.1R (noise);
|
||
OOS 2024-06-01 -> 2025-03-30 +14.5R DD 15.1 vs +11.1R DD 15.4.
|
||
dist 1.0 was REJECTED at the OOS gate (+10.9R < baseline +11.1R)
|
||
despite the best in-sample total (+233.3R) — the OOS ordering picks
|
||
the conservative plateau edge. XAU_PB trades are unaffected (they
|
||
carry their own validated pb_trail 0.8/0.75 per-trade overrides);
|
||
XAU_CP trades share the global params and were validated inside this
|
||
book. M15 arms at 0.70 (its own campaign, same day); the divergence
|
||
is the per-TF pattern yet again.
|
||
|
||
M15 override 4 (validated 2026-07-21, 5-year replay 2021-07-21 ->
|
||
2026-07-21, $0.30 spread, next-open fills): trailing-stop arm raised to
|
||
0.70R (trail_arm_r 0.70, dist unchanged 0.75). Full grid arm 0.3-0.9 x
|
||
dist 0.5-1.0 (30 cells): every earlier-arm cell (0.3/0.45) is WORSE —
|
||
the "arm earlier to save fading trades" hypothesis is refuted; the
|
||
plateau is arm 0.70-0.80 x dist 0.70-0.85 (all >= +190R). Chosen
|
||
plateau center 0.70/0.75: +210.7R/1629 PF 1.35 WR 57.8% vs baseline
|
||
0.60/0.75 +175.7R PF 1.30 WR 53.9%; both last-12mo halves improve
|
||
(+49.7/+50.0 vs +36.4/+46.0); per-year better 4/6 (2022 -0.9R, 2023
|
||
-1.4R, both within tolerance); OOS 2024-06-01 -> 2025-03-30 +57.4R
|
||
PF 1.57 DD 17.0R vs +45.4R PF 1.47 DD 17.8R — better on every OOS
|
||
metric. One clause waived BY OWNER DECISION 2026-07-21: 5yr max DD is
|
||
33.9R vs 29.1R baseline (+4.8R deeper worst episode, 2022-23 chop),
|
||
accepted in exchange for +20% total R. M5 keeps the global 0.6 arm
|
||
(same per-TF divergence pattern as tp_floor_rr and the hour-9 block).
|
||
|
||
M15 override 5 — RSI regime multiplier x 0.5 in every regime
|
||
(validated 2026-09-09, 2-year Oanda window 2024-09-05 -> 2026-09-05 at
|
||
$0.65, pre-registered rule in backtest/research/
|
||
weight_test_2026-09-09.md): 793/+117.62R PF 1.41 DD 14.8R ->
|
||
931/+146.14R PF 1.43 DD 16.1R, fixed halves +27.9/+0.6R vs control;
|
||
OOS 2024-06-01 -> 2025-03-30 300/+40.59R PF 1.38 -> 355/+60.67R
|
||
PF 1.49; 3-year 1092/+151.90R PF 1.38 -> 1273/+186.61R PF 1.39 (max DD
|
||
15.5 -> 19.3R, all in the 2023-24 year; 2026 -4R is the one calendar
|
||
year that does not improve). Mechanism: RSI is neutral on ~73% of M15
|
||
entries and votes against the trend when it fires; halving it lets more
|
||
trend-following entries clear the score band (210 added trades +26.8R,
|
||
mostly B-grade BUYs; 72 removed -7.1R). Candidate came from the
|
||
recorded replay screen (replay_recording_2026-09-09.md); the same
|
||
screen's M5 picks (MACD-down) all FAILED the replay, and ema_trend x 2
|
||
/ divergence -> 0 on M15 failed too. Canonical M15 book re-pinned to
|
||
backtest/oanda_m15_2yr_065_20260909.csv.
|
||
|
||
M15 override 6 — grade-A SELLs blocked (validated 2026-09-26,
|
||
backtest/research/rr_and_sell_campaign_2026-09-26.md, pre-registered
|
||
rule, CUDA twin runs paired with gpu_backtest.py MD5s, $0.65):
|
||
sell_min_quality=["A+", "B"] on M15, so gate 6e downgrades every
|
||
grade-A short to D (A+ and B shorts still trade). The bucket was the
|
||
one cycle-2 candidate from the 2026-09-10 screen: M15 grade-A SELLs
|
||
230 / -14.4R on the 3-year window, negative in every 12-month slice
|
||
and in the OOS window. Candidate vs control: 2-year W2 2024-09-05 ->
|
||
2026-09-05 813/+154.15R PF 1.53 DD 15.6R (halves +70.1/+84.0) vs
|
||
931/+146.14R PF 1.43 DD 16.1R (+66.1/+80.0); OOS 2024-06-01 ->
|
||
2025-03-30 313/+68.50R PF 1.67 DD 12.4R vs 355/+60.67R PF 1.49 DD
|
||
17.1R; 3-year W3 2023-09-05 -> 2026-09-05 1105/+195.79R PF 1.49 DD
|
||
20.9R vs 1273/+186.61R PF 1.39 DD 19.3R (+8%, inside the 10% clause),
|
||
better in 2024, 2025 and 2026, -2.4R in the 4 months of 2023; at $0.30
|
||
+167.53R vs +161.44R (W2). Trade diff on W2: 162 removed (-8.1R, all
|
||
grade-A SELLs), 44 added (-0.1R, cooldown displacement). Counter-fact
|
||
on record: M15 A-grade shorts paid in the 2021-22 bear phase
|
||
(m15_5yr_cuda_2026-09-18.md), outside the owner's 3-year window.
|
||
Tested and NOT shipped in the same campaign: signals.min_rr_ratio 1.0
|
||
on M15 (trade-identical, -2.0R W2, -2.8R W3: the swing-anchored
|
||
GENERIC stop is not better than the 2 x ATR stop on the same grade-A
|
||
signals); the combination with this block (-0.7R vs the block alone).
|
||
|
||
M5 override (validated 2026-07-11, full-history replay 2020-03-17 ->
|
||
2026-07-11 + 12mo book, $0.30 spread): block hour 9 UTC (post-London-
|
||
open whipsaw). Hour-9 entries lost -28.9R/143 over 6 years, negative
|
||
in 5/7 calendar years including winning years (2022 -9.2R). Blocking:
|
||
+207.1R vs +178.3R baseline on the 6-year replay, max DD 28.7R vs
|
||
35.5R, improves 5/7 years (2023 goes -13.0R -> breakeven); the tuned
|
||
12mo book is unchanged (+139.0R vs +139.3R). M15-and-up keep hour 9:
|
||
it is POSITIVE there (M15 6yr +1.7R, M15 OOS +8.6R), so the block is
|
||
M5-only, same per-timeframe pattern as the M15 overrides.
|
||
|
||
M5 override 2 — relaxation campaign (validated 2026-07-30, Oanda
|
||
bars, $0.30 spread, trailing exits): UNBLOCK hour 21 UTC on M5 only,
|
||
combined with the config.py M5 gate relaxations (m5_min_abs_score
|
||
30->25, m5_min_confirmation_score 10->5). The combined config beat
|
||
the pre-relaxation control in ALL 6 calendar years of the 5yr replay
|
||
2021-07-30 -> 2026-07-30 (+230.9R/2319 PF 1.26 DD 21.3 vs
|
||
+168.0R/2048 PF 1.21 DD 27.0), on 12mo (+107.4R PF 1.36, halves
|
||
+68.6/+38.8 vs +84.6R PF 1.33), on OOS 2024-06-01 -> 2025-03-30
|
||
(+26.1R vs +17.2R), and at $0.70 spread (+86.9R vs +66.4R). Hour-21
|
||
trades alone: +28.0R/22, positive every year — overturning the old
|
||
block per the full-evidence rule. Hour 21 stays BLOCKED on M15+
|
||
(12mo M15 unblock tested -0.3R). Declined-but-open from the same
|
||
campaign: an M5 hour-22 block (+4.8R on 12mo — the burst-heavy
|
||
"institutional" hour — but -3.2R on 5yr and -1.1R on OOS: regime-
|
||
specific); M15 hour-16 unblock (+0.8R/+57 trades 12mo but -18.3R
|
||
DD +34% on 5yr); every SELL-gate/vol/TP-size relaxation retested
|
||
negative (see memory notes for the full grid).
|
||
|
||
M5 override 4 — XAU_PB disabled (validated 2026-08-04, Oanda bars,
|
||
$0.65 REAL spread — first campaign validated at measured cost on the
|
||
live feed, per the 2026-08-04 re-pin baseline): m5_pullback_enabled
|
||
False on M5. Loss forensics on the Oanda books identified XAU_PB as
|
||
the largest wrong-direction loss source (12mo: -43.5R of the -156.6R
|
||
wrong-direction bucket; 5yr: -274.5R). Disabling: 12mo +96.6R/588
|
||
PF 1.44 max DD 13.9R halves +51.2/+45.4 vs +82.3R/788 PF 1.26 DD
|
||
23.9R shipped (which FAILS the PF>=1.3 clause at real cost); OOS
|
||
2024-06-01 -> 2025-03-30 +9.5R PF 1.34; 5yr +123.9R/956 PF 1.35 vs
|
||
PF 1.16 with PB. PB's 5yr net contribution (+23.6R) was almost
|
||
entirely the 2022 chop year (+36.1R vs -2.2R without) — a regime
|
||
earner that has been a drag on trend-regime bars since; its tight
|
||
stops are also the most cost-punished at $0.65. PB code and the
|
||
pb_trail_* params STAY for future regime-gated experiments (same
|
||
pattern as cp_enabled). Rejected in the same campaign (4 candidates
|
||
total, N logged): hour-19 block (+3.7R 12mo but -3.3R OOS, -1.5R
|
||
5yr — OOS gate, the classic trap); hours-14/15 block (-6.9R 12mo
|
||
once PB is removed — their raw negativity WAS the PB losses);
|
||
trail_dist_r 0.75 (-2.6R 12mo; the 0.88R average give-back is the
|
||
validated price of riding trends, exits confirmed NOT the loss
|
||
driver: exit-management accounts for 1-2% of lost R vs 50%
|
||
wrong-direction / 49% entry-timing).
|
||
|
||
M5 override 6 — SELL block in transitioning regime (validated
|
||
2026-09-03, signal-log campaign, `backtest/research/
|
||
signal_log_campaign_2026-09.md`, $0.65 round trip, same CPU harness
|
||
as its control): sell_blocked_regimes=["transitioning"]. Live
|
||
evidence: M5 SELLs in transitioning were -7.9R/12mo PF 0.21 and
|
||
-5.2R/5yr PF 0.49 in the pinned books; the live signal log showed the
|
||
same pocket -7.9R/PF 0.56 over 3 weeks. Blocking: 12mo (2025-08-14 ->
|
||
2026-08-14) 557 trades +112.21R PF 1.56 (halves +55.9/+56.4, PF
|
||
1.54/1.58) vs control 575/+104.34R PF 1.50; 5yr (2021-08-01 ->
|
||
2026-08-04) 889/+133.7R PF 1.41 vs 911/+128.4R PF 1.39; OOS
|
||
2024-06-01 -> 2025-03-30 unchanged (86/+9.45R PF 1.33 — no such
|
||
trades in that window). Removed trades: 18 in 12mo (-7.9R), 22 in
|
||
5yr (-5.3R).
|
||
|
||
H1 override — all SELL entries blocked (validated 2026-09-03, same
|
||
campaign): sell_min_quality=[] (gate 6e in signal_aggregator.py
|
||
downgrades any actionable-grade SELL whose quality is not in this
|
||
list to D, so an empty list downgrades every H1 short). H1 shorts
|
||
were a structural loser: -16.7R over the 5yr control window and
|
||
-11.5R OOS. Blocking: 12mo (2025-08-04 -> 2026-08-04) 91/+22.2R
|
||
PF 1.79 (halves +20.6/+1.6) vs control 138/+24.0R PF 1.55 (12mo cost
|
||
-1.8R); 5yr 335/+49.1R PF 1.46 vs 515/+32.4R PF 1.18; OOS 78/+16.7R
|
||
PF 1.74 vs 104/+5.1R PF 1.13. New reference books:
|
||
backtest/oanda_h1_{12mo,5yr,oos}_065_20260903.csv,
|
||
backtest/oanda_m5_12mo_065_nopb_20260903.csv,
|
||
backtest/oanda_m5_5yr_065_nopb_20260903.csv.
|
||
|
||
Rejected/parked in the same campaign (see the memo for the full
|
||
table): M15 sell_min_quality=["B"] (5yr -8.9R, max DD 35.8 -> 41.4R
|
||
— REJECTED); Bollinger weight 0 in trending regimes on M5, M15, H1
|
||
(M5 -20.4R/12mo, -15.5R/5yr; M15 -24.0R/12mo — REJECTED across the
|
||
board); divergence disabled on M15 (R improves +7.4/+11.9/+13.5R
|
||
across windows but 5yr max DD 35.8 -> 47.4R with PF flat — DECLINED,
|
||
owner call); divergence disabled on H1 (+4.6/+8.1/+2.4R, PF
|
||
1.62/1.20/1.17) — PARKED: it passes rule 1 in combination with the
|
||
H1 no-short override (b12_h1_nosell_nodiv: 12mo 100/+23.1R PF 1.75,
|
||
halves +21.8/+1.3; 5yr 364/+58.7R PF 1.52; OOS 88/+21.9R PF 1.92 —
|
||
better than the no-shorts override alone on both 5yr and OOS), but
|
||
shipping it would route through technical.disabled_indicators, which
|
||
CLAUDE.md rule 8 reserves for experiments; owner decision, recommended
|
||
vehicle is an H1-only regime_weights_override with divergence weight
|
||
0 plus a fresh validation run.
|
||
|
||
M5 override 5 — EMA partial-alignment squash (validated 2026-08-04,
|
||
Oanda bars, $0.65 real spread): ema_partial_neutral True on M5 —
|
||
partial 4-EMA ribbon alignment (2-3 of 4 checks) scores NEUTRAL
|
||
instead of a weak BUY/SELL. Motivated by the indicator audit: partial-
|
||
alignment trades averaged -0.008R/84 vs +0.230R/341 fully aligned.
|
||
Replay (knob mirrored in the backtester's precomputed EMA scorer in
|
||
the same commit — live==backtest parity): 12mo +97.6R/556 PF 1.48
|
||
DD 10.7R halves +47.8/+49.8 vs control +96.6R/588 PF 1.44 DD 13.9R;
|
||
5yr +127.4R/912 PF 1.38 DD 12.8R vs +123.9R/956 PF 1.35 DD 13.2R,
|
||
2022 improves -2.2 -> -1.1; OOS 2024-06-01 -> 2025-03-30 +9.4R
|
||
PF 1.33 vs +9.5R PF 1.34 — a one-trade tie, documented as such (the
|
||
OOS window holds up; it neither prefers nor punishes). Net effect:
|
||
32 fewer marginal trades, every risk-adjusted measure better.
|
||
Rejected in the same round (trial-logged): confirmation-TF swap
|
||
M5->[M15,H4] (12mo +104.0R PF 1.51 DD 10.3 but OOS +7.8R PF 1.27
|
||
vs control +9.5R PF 1.34 and 2022 3x worse — the H4 confirm keeps
|
||
endorsing stale direction in chop; OOS-ordering rejection, same
|
||
precedent as trail dist 1.0); confirm [H1,H4] (-31.8R 12mo);
|
||
triple-confirm [M15,H1,H4] (-4.9R); divergence weight -1/3
|
||
(-3.8R 12mo); candlestick weight +50% (-3.0R 12mo). The weight
|
||
vector keeps proving calibrated as a system: divergence/candlestick/
|
||
bollinger all look mis-weighted in-book and all replay worse when
|
||
"fixed" (bollinger weight-0: +80.9R PF 1.29 DD 23.8 — its constant
|
||
oppose vote is a load-bearing quality bar, like ROC).
|
||
"""
|
||
|
||
from typing import Dict, Optional, List
|
||
from config import PlatformConfig, TechnicalConfig, Timeframe
|
||
from app_config import apply_pair_overrides
|
||
|
||
_CONFIRMATIONS = {
|
||
Timeframe.M5: [Timeframe.M15, Timeframe.H1],
|
||
Timeframe.M15: [Timeframe.M5, Timeframe.H1],
|
||
Timeframe.H1: [Timeframe.M15, Timeframe.H4],
|
||
Timeframe.H4: [Timeframe.H1, Timeframe.D1],
|
||
}
|
||
|
||
|
||
def _m15_regime_weights() -> Dict[str, Dict[str, float]]:
|
||
"""Shipped regime weight table with the RSI multiplier halved in
|
||
every regime — the M15-only override validated 2026-09-09 (see the
|
||
module docstring, M15 override 5). Derived from the default table so
|
||
the intent ("RSI x 0.5, everything else as shipped") stays explicit;
|
||
the Module 9 equivalence test pins the resulting numbers."""
|
||
from engine import regime_weight_table # local import: keep the factory import-light
|
||
table = regime_weight_table(TechnicalConfig()) # a fresh TechnicalConfig has no override -> the shipped table
|
||
return {regime: {name: (mult * 0.5 if name == "rsi" else mult)
|
||
for name, mult in weights.items()}
|
||
for regime, weights in table.items()}
|
||
|
||
|
||
def make_config(
|
||
primary_tf: Timeframe,
|
||
confirmation_tfs: Optional[List[Timeframe]] = None,
|
||
) -> PlatformConfig:
|
||
config = PlatformConfig()
|
||
# Deployment overlay (config.json) BEFORE the validated per-TF
|
||
# deltas below, so e.g. the M5 hour-9 append lands on the JSON base.
|
||
apply_pair_overrides(config)
|
||
config.primary_timeframe = primary_tf
|
||
config.confirmation_timeframes = (
|
||
confirmation_tfs or _CONFIRMATIONS.get(primary_tf, [Timeframe.M15, Timeframe.H4])
|
||
)
|
||
if primary_tf == Timeframe.M5:
|
||
# Block hour 9 UTC on M5 only; UNBLOCK hour 21 on M5 only
|
||
# (positive every year of the 5yr replay) — see docstring.
|
||
config.xau_strategy.blocked_hours_utc = [
|
||
h for h in config.xau_strategy.blocked_hours_utc if h != 21
|
||
] + [9]
|
||
# Deliberately NOT mirrored into config.backtest.blocked_hours_utc:
|
||
# that copy is the generic non-XAU fallback carrying the JSON base
|
||
# only. Propagating a gold-validated per-TF delta there would leak
|
||
# XAU-calibrated hours to a future pair (pair-isolation rule).
|
||
# Every XAU consumer branches to the xau_strategy copy. Enforced
|
||
# by the Module 13 test "M5 factory appends hour 9 on top of a
|
||
# JSON base".
|
||
# BUY-only chart patterns on M5 — see module docstring.
|
||
config.xau_strategy.cp_enabled = True
|
||
config.xau_strategy.cp_patterns = ["inv_hs", "double_bottom", "bull_flag"]
|
||
# XAU_PB pullback entries OFF — largest wrong-direction loss
|
||
# source at real cost on Oanda bars — see module docstring.
|
||
config.xau_strategy.m5_pullback_enabled = False
|
||
# Partial EMA-ribbon alignment scores NEUTRAL on M5 — its
|
||
# trades carried no edge — see module docstring.
|
||
config.technical.ema_partial_neutral = True
|
||
# Wider trailing distance on M5 only — see module docstring.
|
||
config.signals.trail_arm_r = 0.60
|
||
config.signals.trail_dist_r = 0.85
|
||
# Block SELL entries while the regime is "transitioning" on M5
|
||
# only — see module docstring (M5 override 6).
|
||
config.xau_strategy.sell_blocked_regimes = ["transitioning"]
|
||
if primary_tf == Timeframe.M15:
|
||
# 1R minimum target on M15 only — see module docstring.
|
||
config.signals.tp_floor_rr = 1.0
|
||
# Block the mixed "trending" regime on M15 only — see docstring.
|
||
config.xau_strategy.blocked_regimes = ["trending"]
|
||
# Block SELL entries at 15:00/17:00 UTC on M15 only — see docstring.
|
||
config.xau_strategy.sell_blocked_hours_utc = [15, 17]
|
||
# Later trailing-stop arm on M15 only — see module docstring.
|
||
config.signals.trail_arm_r = 0.70
|
||
config.signals.trail_dist_r = 0.75
|
||
# RSI regime multiplier × 0.5 in every regime on M15 only — see
|
||
# module docstring (M15 override 5, validated 2026-09-09).
|
||
config.technical.regime_weights_override = _m15_regime_weights()
|
||
# Grade-A SELLs blocked on M15 only (gate 6e downgrades an
|
||
# actionable-grade short whose grade is not listed) — see module
|
||
# docstring (M15 override 6, validated 2026-09-26).
|
||
config.xau_strategy.sell_min_quality = ["A+", "B"]
|
||
if primary_tf == Timeframe.H1:
|
||
# Block every H1 SELL — the SELL quality gate (6e in
|
||
# signal_aggregator.py) downgrades any actionable-grade short
|
||
# to D when its grade is not in this list; an empty list means
|
||
# no grade qualifies. H1-only — see module docstring.
|
||
config.xau_strategy.sell_min_quality = []
|
||
return config
|