"""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). M15 override 7 — daily-trend veto (validated 2026-09-30, backtest/research/daily_trend_campaign_2026-09-30.md, pre-registered RISK-FIRST rule approved by the owner that day, CUDA twin runs paired with gpu_backtest.py MD5s, $0.65): daily_trend_veto="both". The engine sees at most the H1 chart. The daily trend is +1 when the last CLOSED daily bar closes above its 50-day EMA AND above the close 60 daily bars earlier, -1 when below both, else 0 (Oanda's Sunday stub bars are dropped; signal_aggregator.daily_trend_series). After every setup archetype has run, a setup AGAINST a non-zero state is dropped (grade D, no setup, warning "DAILY TREND FILTER: ..."). Candidate vs control: 3-year W3 2023-09-05 -> 2026-09-05 824/+205.12R PF 1.73 DD 12.4R vs 1105/+195.79R PF 1.49 DD 20.9R (halves +76.7/+128.4 vs +76.9/+118.9; at $0.30 +221.18R PF 1.81 DD 11.4R vs +216.53R PF 1.55 DD 19.6R); 7.6-year LONG 2019-01-01 -> 2026-08-07 1473/+223.33R PF 1.42 DD 41.5R vs 2091/+192.53R PF 1.24 DD 64.8R (2022 +3.2R vs -24.6R; 2021 NOT improved, -27.3R vs -25.6R; 2023 worse, +1.8R vs +11.7R); the unseen HOLDOUT 2026-09-05 -> 2026-10-01 18/-4.62R vs 24/-6.63R; 3 of 4 neighbouring definitions pass (90-day change, 120-day change, 100-day average; the 60-day change alone misses the 97% line by 1.7R). Trade diff W3: 281 removed (-9.3R: BUY 106/+7.6R, SELL 175/-16.9R), 0 added; the removed trades are break-even after costs (-0.03R each) against +0.25R for the kept ones, so the veto drops the no-edge quarter of the book rather than a pocket of big losers. ACCEPTED COST (owner decision 2026-09-30): R given up while gold only rises — 2-year W2 597/+155.89R PF 1.78 DD 11.4R vs 813/+154.15R PF 1.53 DD 15.6R with the first half +61.8R vs +70.1R, and the old OOS window 2024-06-01 -> 2025-03-30 258/+63.78R PF 1.80 DD 9.1R vs 313/+68.50R PF 1.67 DD 12.4R. The 2026-09-26 rule template (no half and no OOS window may lose) would have rejected it; the risk-first rule (3-year R >= 97%, PF +0.10, DD not deeper, long window better on R, DD and 2021+2022, holdout, both costs, plateau) is the owner's deliberate choice. M15 ONLY: the same veto FAILED on M5 ("both": W3 DD 10.1 -> 15.2R and the long window worse on R and DD; "buy": passes W3, loses the long window, no plateau) and on H1 (W3 +60.3R vs +70.0R). "buy"-only and "sell"-only FAILED on M15 as well ("sell" has the best W3 total, +212.7R, and a LONG DD of 76.4R vs 64.8R: in falling years the buys against the daily trend are the losers). The live wrapper and both backtesters load D1 as an extra REQUIRED frame while the veto is on. 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"] # Daily-trend veto on M15 only: a finished setup against a clear # daily trend (price vs its 50-day average AND the 60-day change) # is dropped. The live wrapper and both backtesters load the D1 # frame for it — see module docstring (M15 override 7, validated # 2026-09-30). M5, H1 and H4 FAILED the same rule and stay "off". config.xau_strategy.daily_trend_veto = "both" 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