Add session filter + auto-toggle, extend trade journal diagnostics

Session filter restricts trades to a UTC hour window (default 07-16,
London + NY) — opt-in via --session-filter, with --session-start /
--session-end overrides. Wired into both the backtester (cheap hour
check next to the regime gate) and live mode (downgrades signal to
NEUTRAL/F when current UTC hour is outside the window).

Auto-toggle (--auto-session-filter) tracks rolling mean pnl_pct over
the last N closed trades; when it falls below threshold, the session
filter activates, releasing once expectancy recovers. Default lookback
10 trades, threshold -0.3%.

Trade dataclass extended with diagnostic fields captured at entry:
entry_hour, entry_dow, ADX, ATR%, market_regime, volatility_regime,
mtf_agreement. These let --journal-csv exports surface loss-pattern
clusters when a window underperforms.

Validated on 2024 trend / 2023 chop / 2026 recent windows. Auto-toggle
preserves ~50% of trend edge while still cutting ~25% of recent-regime
losses — pure regime filter is still best on cumulative, so both
session flags ship default-off.
This commit is contained in:
Harwinder
2026-05-07 18:38:49 -04:00
parent fb1eb5b73f
commit 2e5d66db1b
5 changed files with 139 additions and 1 deletions
+25
View File
@@ -130,8 +130,33 @@ class SignalAggregator:
if bt.regime_filter:
self._apply_regime_filter_live(report, dfs)
if bt.session_filter:
self._apply_session_filter_live(report)
return report
def _apply_session_filter_live(self, report: SignalReport) -> None:
"""Skip signals outside the configured UTC trading window."""
bt = self.config.backtest
now_h = datetime.now(timezone.utc).hour
if not (bt.session_start_hour <= now_h < bt.session_end_hour):
report.warnings.append(
f"SESSION FILTER: {now_h:02}:00 UTC outside "
f"{bt.session_start_hour:02}:00-{bt.session_end_hour:02}:00 — skipping"
)
report.final_signal = SignalStrength.NEUTRAL
report.signal_quality = "F"
report.action_recommendation = (
f"NO TRADE — Outside session "
f"({bt.session_start_hour:02}-{bt.session_end_hour:02} UTC; now {now_h:02})"
)
report.trade_setup = None
else:
report.warnings.append(
f"Session: {now_h:02}:00 UTC inside trading window "
f"{bt.session_start_hour:02}-{bt.session_end_hour:02}"
)
def _apply_regime_filter_live(
self, report: SignalReport, dfs: Dict[Timeframe, pd.DataFrame]
) -> None: