From c4cb18a25ca920ef0991aa92c04711e4abafd594 Mon Sep 17 00:00:00 2001 From: gahusb Date: Tue, 12 May 2026 13:49:45 +0900 Subject: [PATCH] =?UTF-8?q?feat(stock-lab):=20/run=20mode=3Dauto=20?= =?UTF-8?q?=EA=B3=B5=ED=9C=B4=EC=9D=BC=C2=B7=EC=A3=BC=EB=A7=90=20skipped?= =?UTF-8?q?=5Fholiday=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stock-lab/app/screener/router.py | 34 +++++++++++++++++++++++++++ stock-lab/app/test_screener_router.py | 8 +++++++ 2 files changed, 42 insertions(+) diff --git a/stock-lab/app/screener/router.py b/stock-lab/app/screener/router.py index c57224e..aadd10f 100644 --- a/stock-lab/app/screener/router.py +++ b/stock-lab/app/screener/router.py @@ -17,6 +17,29 @@ from .registry import NODE_REGISTRY, GATE_REGISTRY router = APIRouter(prefix="/api/stock/screener") +import json as _json +import pathlib as _pathlib + +_HOLIDAYS_CACHE = None + + +def _holidays(): + global _HOLIDAYS_CACHE + if _HOLIDAYS_CACHE is None: + path = _pathlib.Path(__file__).resolve().parent.parent / "holidays.json" + try: + with path.open(encoding="utf-8") as f: + data = _json.load(f) + _HOLIDAYS_CACHE = set(data) if isinstance(data, list) else set(data.keys()) + except FileNotFoundError: + _HOLIDAYS_CACHE = set() + return _HOLIDAYS_CACHE + + +def _is_holiday(d: dt.date) -> bool: + return d.weekday() >= 5 or d.isoformat() in _holidays() + + def _db_path() -> str: return os.environ.get("STOCK_DB_PATH", "/app/data/stock.db") @@ -147,6 +170,17 @@ def post_run(body: schemas.RunRequest): started_at = dt.datetime.utcnow().isoformat() with _conn() as c: asof = _resolve_asof(body.asof, c) + + # Skipped holiday handling for mode='auto' + if body.mode == "auto" and _is_holiday(asof): + return schemas.RunResponse( + asof=asof.isoformat(), mode="auto", status="skipped_holiday", + run_id=None, survivors_count=None, + weights={}, top_n=0, + results=[], telegram_payload=None, + warnings=[f"{asof.isoformat()} is a holiday — skipped"], + ) + defaults = _load_settings(c) if body.mode == "auto": diff --git a/stock-lab/app/test_screener_router.py b/stock-lab/app/test_screener_router.py index 630e5e3..dd444d2 100644 --- a/stock-lab/app/test_screener_router.py +++ b/stock-lab/app/test_screener_router.py @@ -144,3 +144,11 @@ def test_runs_list_and_detail(client): assert detail.status_code == 200 assert detail.json()["meta"]["id"] == run_id assert isinstance(detail.json()["results"], list) + + +def test_run_holiday_returns_skipped(client): + # 2026-05-09는 토요일 (주말). _is_holiday 가 weekday>=5를 잡음. + r = client.post("/api/stock/screener/run", + json={"mode": "auto", "asof": "2026-05-09"}) + assert r.status_code == 200 + assert r.json()["status"] == "skipped_holiday"