From 713d04deefcd622b20402f28b47f7dd729536dc0 Mon Sep 17 00:00:00 2001 From: I Luk Kim Date: Mon, 20 Apr 2026 15:47:28 -0700 Subject: [PATCH] Fix EOD exit: sweep DB for stale pending candidates after restart; remove misleading compound_returns override - run_eod_exit now queries DB for any pending candidates not in-memory (guards against server restart mid-day leaving zombie pending records) - Remove compound_returns=True force-override; live engine doesn't use it and V23 config has compound_returns=false Co-Authored-By: Claude Sonnet 4.6 --- apps/orb_trader/engine.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/orb_trader/engine.py b/apps/orb_trader/engine.py index 7e75775..cda6a41 100644 --- a/apps/orb_trader/engine.py +++ b/apps/orb_trader/engine.py @@ -63,10 +63,9 @@ class ORBTradingEngine: self._params = params self._log_callback = log_callback # optional scheduler._log for UI visibility - # Force live trading overrides - self._params.compound_returns = True - self._params.settlement_days = 0 - self._params.slippage_bps = 0.0 + # Live trading overrides + self._params.settlement_days = 0 # paper trading; no real T+1 settlement + self._params.slippage_bps = 0.0 # real fills, no simulated slippage # IEX feed has ~1-3% market share vs SIP; RVOL computed from IEX ORB volume # relative to SIP avg_daily_vol would be ~0.01-0.03 (min_rvol=1.0 would filter # everything). Disable the threshold filter; RVOL is still used for ranking. @@ -883,11 +882,20 @@ class ORBTradingEngine: self._session.session_id, date_str, pos.ticker ) - # Cancel any unfilled breakout orders + # Cancel any unfilled breakout candidates (in-memory and DB) for cand in self._pending_cands: self._state.update_candidate_status( self._session.session_id, date_str, cand["ticker"], "timeout" ) + self._pending_cands = [] + + # Also sweep DB for any pending records not in in-memory list (e.g. after restart) + db_cands = self._state.list_candidates(self._session.session_id, date_str) + for c in db_cands: + if c["status"] == "pending": + self._state.update_candidate_status( + self._session.session_id, date_str, c["ticker"], "timeout" + ) return {"closed": closed}