@ -538,7 +538,7 @@ class AutoScheduler:
# ── Catch-up on startup ───────────────────────────────────────────────────
async def _run_catchup ( self ) - > None :
""" Run missed pipeline steps on startup. Mirrors auto.py _run_catchup() ."""
""" Run missed pipeline steps and paper trading phases on startup ."""
now_et = self . _now_et ( )
today = now_et . date ( )
catchup_items : list [ tuple [ str , list [ list [ str ] ] ] ] = [ ]
@ -553,15 +553,35 @@ class AutoScheduler:
if pre_market_et < now_et :
catchup_items . append ( ( f " Pre-market pipeline ( { today } ) " , _PIPELINE_CMDS ) )
if not catchup_items :
return
if catchup_items :
self . _log ( " ━━━ Catch-up: 놓친 파이프라인 실행 ━━━ " )
for label , cmds in catchup_items :
self . _log ( f " ▶ { label } " )
await self . _run_pipeline ( cmds )
self . _log ( " ━━━ Catch-up 완료 ━━━ " )
# Paper trading phase catchup: if run_open was missed but market is still open, run now.
# This fires when the server starts after 9:35 AM ET — the scheduler would otherwise
# silently skip run_open because its scheduled time has already passed.
if self . _is_trading_day ( today ) and not self . _dry_run :
run_open_et = self . _et_dt_for ( today , _SCHEDULE [ 1 ] ) # run_open 9:35
market_close_et = now_et . replace ( hour = 16 , minute = 0 , second = 0 , microsecond = 0 )
if run_open_et < = now_et < market_close_et :
sessions = self . _sessions or self . _get_active_sessions ( )
if sessions and self . _db_path :
from apps . paper_trader . state import StateManager
state_mgr = StateManager ( self . _db_path )
already_ran = any (
( sess := state_mgr . get_session ( s ) ) is not None
and state_mgr . is_phase_processed ( sess . session_id , today , " next_open " )
for s in sessions
)
if not already_ran :
self . _log ( " ━━━ Catch-up: run_open 누락 (9:35 ET 이후 시작) — 지금 실행 ━━━ " )
await self . _run_trading ( " run-open " , sessions )
self . _completed . add ( " run_open " )
self . _log ( " ━━━ Catch-up run_open 완료 ━━━ " )
# ── Main scheduler loop ───────────────────────────────────────────────────
async def _run_loop ( self ) - > None :