0e77c055baa59f58498631858999fb3d3c6d07d8
The market-regime filter (suppress directional signals in choppy/sideways conditions, downgrade STRONG signals in volatile ones) already existed, but only as a manual post-classification check inside signal_service.py's live-trading path. Backtest and walk-forward called signal_scoring.py's classifier directly, bypassing it entirely — so backtest results systematically overestimated trade frequency and risk exposure relative to what live trading actually does. Factored the filter into a shared _apply_regime_filter() in signal_scoring.py and added an optional market_regime param to _classify_signal_combined() (default None preserves existing behavior for every other caller, e.g. MTF sub-votes). backtest_engine.py now precomputes adx()/atr() alongside the other rolling-window indicators and computes detect_market_regime() per candle with the same bounded-window formula live trading uses (candle_service.py), applying the filter once a threshold combo resolves a concrete signal type. signal_service.py now passes its regime into the shared classifier instead of duplicating the check. Also found and fixed a second, independent regime system: close_stale_trades() (SL/TP sizing for open trades) computed its own cruder ATR-percentile-only regime bucketing, which could disagree with the ADX+BB+Choppiness+ Efficiency-Ratio classification used for entry filtering. It now reads market_regime from get_indicators() — the same TTL-cached function the live signal-generation loop already populates — so entry filtering and exit sizing agree on what "volatile" or "choppy" means for a given symbol. 14 new tests (unit tests for _apply_regime_filter, backtest integration tests proving the filter suppresses/allows trades by regime, and a signal_service test confirming close_stale_trades sources its regime from the shared cache). 170 backend tests passing, frontend build clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Description
Test repo