PULLBACK ENTRY PATTERN — IMPLEMENTATION PLAN ============================================= Drafted 2026-07-09. Status: IMPLEMENTED & VALIDATED (same day). OUTCOME: shipped as XAU_PB. 12mo M5 validation: 254 PB trades, +38.3R, avgR +0.151, WR 58%, halves +20.1/+18.1, all four full quarters positive. Core breakout trades undisturbed (-3.1R displacement). Combined book: 549 trades (~10.6/wk), +140.1R, PF 1.78, DD 11.3R. Calibration lesson: M5 gold trend legs measure 3-4 ATR swing-to-trough — the drafted 0.5-2.5 ATR retrace window rejected 81% of valid pullbacks (fixed: 0.8-6.0). PB stops are ~$8 vs ~$25 core, so PB got its own trail arm (0.8R vs 0.6R). Detector lives in signal_aggregator (NOT engine.py) so the GPU backtest engine exercises the same code path as live. WHY (evidence from 12mo M5 backtests, $0.30 spread, trailing exits) ------------------------------------------------------------------- All 311 current trades are one archetype: trend-continuation breakout (EMA 4/4 aligned + ADX>25 + MACD accelerating + price through Keltner band). We systematically enter at maximum extension: - Trades carrying the "NO PULLBACK — price >2.5 ATR from EMA21" warning average +0.063R vs +0.112R without it (145 vs 103 trades, 6mo set). - 28% of stopped-out trades never moved toward the target — instant reversals from buying the local top / selling the local bottom. - "Extended — RSI in trend" warning trades: +0.057R vs +0.183R without. A pullback entry catches the SAME trends at better prices: enter on the retrace toward EMA21 / Keltner midline, stop below the retrace swing instead of 2×ATR behind an extended price. Tighter risk, same trend. This ADDS trades (new signal source) — it does not filter existing ones. DETECTOR SPEC (engine.py — new module-level check in M5 path) ------------------------------------------------------------- Trend context (all required): 1. EMA alignment >= 3/4 in trend direction (allow 9<21 wobble mid-pullback) 2. ADX >= 20 on M5 (relaxed vs breakout's 25: ADX decays during retrace) 3. H1 confirmation score agrees with trend direction (>= +10 / <= -10), reuse Gate-3 machinery. Pullback trigger (all required): 4. Price touched/undercut EMA21 or KC midline within last 3 bars (low <= band for BUY; high >= band for SELL). 5. Retrace depth 0.5–2.5 ATR from the pre-pullback swing extreme (deeper = trend likely broken; shallower = still extended). 6. Resumption bar: close back in trend direction (close > open for BUY) AND close above EMA9 (below for SELL) — do not catch the falling knife. 7. RSI in the pullback zone: BUY 35–55, SELL 45–65 (NOT the extended zones the breakout entries fire in — that is the whole point). Suppression: 8. Skip if a breakout signal fired within cooldown (no double entry on the same leg — cd2/cd3 tests proved same-direction pyramiding is train-half-only noise). 9. All existing M5 gates 1–6 still apply where meaningful; Gate 1 (|score|>=30) will need a variant — pullback bars have weaker composite scores BY DESIGN (price below the momentum bands), so validate a separate m5_pullback_min_score knob (start ~20). GEOMETRY -------- - SL: below the pullback swing low (BUY) − 0.5×ATR buffer, floored at min_sl_pips ($8). Expect typical SL 40–60% tighter than breakout SLs. - Exit: same trailing stop (arm +0.6R, trail 0.75R, max_hold 300). NOTE: tighter SL means R units are smaller in dollars — re-validate trail params on pullback trades separately; the arm/dist plateau was measured on breakout-sized risk. If needed give pullback its own trail knobs. - Tag trades strategy="XAU_PB" in the backtester so every report splits breakout vs pullback cleanly. VALIDATION PROTOCOL (same discipline as 2026-07-09 sessions) ------------------------------------------------------------ 1. Implement detector behind config flag m5_pullback_enabled=False. 2. 365d backtest, flag on; export CSV; analyze XAU_PB trades alone: - REQUIRE: positive totalR in BOTH data halves - REQUIRE: positive in >= 3 of 4 full quarters - REQUIRE: does not degrade breakout-trade totals (displacement check vs baseline entry_time set, like the cooldown analysis) - TARGET: >= +0.15R/trade average, >= 1 trade/week added 3. Threshold sweeps (retrace depth, RSI zone, ADX floor) via the offline exit-sim harness pattern where possible; full reruns where entries change. 4. Reject-and-document if it fails — same as blocked-hours/cooldown experiments (see memory: entry-side experiments rejected). BASELINE TO BEAT (do not regress) --------------------------------- 12mo M5: 311 trades, +105.0R, PF 2.27, DD 7.9R, WR 61.4%, train/val +54.6/+50.4, every quarter positive, ~6-8 trades/week. (commit 987ec5b, CSV: m5_365d_trail300 in session scratchpad) IMPLEMENTATION ORDER -------------------- 1. config.py: m5_pullback_enabled, m5_pullback_min_score, pullback RSI zones, retrace depth bounds. 2. engine.py: pullback detector producing a candidate flag + swing levels (attach as result._pullback_setup, underscore-private). 3. signal_aggregator.py: consume flag, build XAU_PB trade setup with pullback geometry; route through gates with pullback score variant. 4. gpu_backtest.py: ensure strategy tag flows to CSV (already does via strategy_tag) and pre-filter loop does not drop pullback candidates. 5. Backtest + validate per protocol; tune; commit only on pass. RISKS ----- - Pullback entries in a trend that IS reversing = catching the knife; the resumption-bar condition (6) is the main guard — do not weaken it. - Score-gate variant (9) is the most likely source of overfitting; sweep it last, keep the grid coarse. - M5 pullbacks during news spikes: calendar buffer already applies via existing pipeline; verify it fires for XAU_PB too.