M5 at real cost: disable XAU_PB, squash partial EMA alignment

Both validated at the measured $0.65 spread on Oanda bars (12mo halves +
PF, OOS 2024-06->2025-03, 5yr; full evidence in pair_signals/xauusd.py
M5 overrides 4-5):

- m5_pullback_enabled False on M5: loss forensics identified XAU_PB as
  the largest wrong-direction loss source; 12mo PF 1.26 (failing the
  acceptance bar) -> 1.44, max DD 23.9R -> 13.9R. PB code stays for
  future regime-gated experiments.
- New TechnicalConfig.ema_partial_neutral (default False), True on M5
  only: partial 4-EMA ribbon alignment (2-3 of 4 checks) scores NEUTRAL
  instead of a weak BUY/SELL (-0.008R/84 vs +0.230R/341 fully aligned).
  Squash mirrored in the backtester's precomputed EMA scorer in this
  same commit (live==backtest parity). 12mo +97.6R/556 PF 1.48 DD
  10.7R halves +47.8/+49.8; 5yr +127.4R PF 1.38; OOS one-trade tie.
- Rejected and logged (memory + docstring): hour-19 block (OOS fail),
  hours-14/15, trail dist 0.75, confirm-TF swaps incl M15+H4 (OOS
  ordering), divergence/candlestick weight changes, bollinger removal.
- Tests 296 -> 302: partial-alignment fixture test, factory-equivalence
  mirrors, per-TF isolation test, BC-gate fixture force-enables PB.

Claude-Session: https://claude.ai/code/session_01H1eKWZsAVapJ1C4winYLqX
This commit is contained in:
Harwinder Sekhon
2026-08-04 16:54:09 -04:00
parent 775330ff16
commit 28a1c375bd
7 changed files with 124 additions and 2 deletions
+5
View File
@@ -529,6 +529,11 @@ class GPUTechnicalEngine(TechnicalEngine):
signal = SignalStrength.NEUTRAL
conf = 40
# Mirrors the live engine's ema_partial_neutral squash (parity).
if c.ema_partial_neutral and signal in (SignalStrength.BUY, SignalStrength.SELL):
signal = SignalStrength.NEUTRAL
conf = 40
crossover_desc = ""
# Live: `if len(ema_fast) >= 3:` then iloc[-2] — needs len ≥ 2 functionally,
# but live's guard requires len ≥ 3 so we match that to stay byte-identical.