"""일별 배치: 16:00 KST 에 시드 10종목 + 거시 + 뉴스 + DART 갱신. 수동 실행: python -m app.pipelines.daily_batch """ from __future__ import annotations import json import logging import time from typing import Any from app.fetch import macro as macro_mod from app.nlp.score_news import score_pending_news from app.pipelines.refresh_one import refresh_code from app.seed.seed_tickers import SEED_TICKERS logger = logging.getLogger(__name__) def run_daily_batch() -> dict[str, Any]: start_ts = time.time() reports: list[dict[str, Any]] = [] for t in SEED_TICKERS: logger.info("daily_batch refresh %s %s", t.code, t.name) rep = refresh_code(t.code, t.name, lookback_days=7) reports.append(rep.to_dict()) macros = macro_mod.fetch_macro_daily(years=1) macro_summary = [ {"key": m.key, "status": m.status(), "inserted": m.inserted, "updated": m.updated, "error": m.error} for m in macros ] # 시드 종목 refresh 내에서 종목당 200건만 스코어함. 잔여(여러 소스 합쳐 # 200건 초과 또는 코드 매핑 안된 google_rss 등)는 여기서 한 번에 mop-up. try: mop = score_pending_news(limit=2000) sentiment_summary: dict[str, Any] = { "status": "ok" if mop.error is None else "failed", "fetched": mop.fetched, "scored": mop.scored, "failed": mop.failed, "error": mop.error, } except Exception as exc: # noqa: BLE001 sentiment_summary = {"status": "failed", "error": str(exc)} elapsed = time.time() - start_ts return { "duration_seconds": round(elapsed, 2), "tickers": reports, "macro": macro_summary, "sentiment_mop": sentiment_summary, } if __name__ == "__main__": logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s") out = run_daily_batch() print(json.dumps(out, ensure_ascii=False, indent=2, default=str))