Fix paper trader startup: run missed run_open if market still open; improve poll_error logging

- AutoScheduler._run_catchup: if server starts after 9:35 AM ET but before
  market close (16:00 ET), and run_open hasn't already run today
  (checked via processed_phases), run it immediately instead of silently
  skipping it — prevents AVGO/event entries being missed on late starts

- filing_poller: log exc_type alongside error so empty-string exceptions
  (e.g. HTTPError()) are still identifiable by their type

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main
I Luk Kim 4 months ago
parent 86419beeb0
commit 5ea8850ac2

@ -116,7 +116,7 @@ async def poll_filings(
) )
except Exception as exc: except Exception as exc:
logger.error("poll_error", ticker=ticker, error=str(exc)) logger.error("poll_error", ticker=ticker, error=str(exc) or repr(exc), exc_type=type(exc).__name__)
stats["errors"] += 1 stats["errors"] += 1
# Update job record # Update job record

@ -538,7 +538,7 @@ class AutoScheduler:
# ── Catch-up on startup ─────────────────────────────────────────────────── # ── Catch-up on startup ───────────────────────────────────────────────────
async def _run_catchup(self) -> None: 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() now_et = self._now_et()
today = now_et.date() today = now_et.date()
catchup_items: list[tuple[str, list[list[str]]]] = [] catchup_items: list[tuple[str, list[list[str]]]] = []
@ -553,15 +553,35 @@ class AutoScheduler:
if pre_market_et < now_et: if pre_market_et < now_et:
catchup_items.append((f"Pre-market pipeline ({today})", _PIPELINE_CMDS)) catchup_items.append((f"Pre-market pipeline ({today})", _PIPELINE_CMDS))
if not catchup_items: if catchup_items:
return
self._log("━━━ Catch-up: 놓친 파이프라인 실행 ━━━") self._log("━━━ Catch-up: 놓친 파이프라인 실행 ━━━")
for label, cmds in catchup_items: for label, cmds in catchup_items:
self._log(f"{label}") self._log(f"{label}")
await self._run_pipeline(cmds) await self._run_pipeline(cmds)
self._log("━━━ Catch-up 완료 ━━━") 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 ─────────────────────────────────────────────────── # ── Main scheduler loop ───────────────────────────────────────────────────
async def _run_loop(self) -> None: async def _run_loop(self) -> None:

Loading…
Cancel
Save