From b94b5973d6697002f43df3a970daebf213e7db60 Mon Sep 17 00:00:00 2001 From: gahusb Date: Sun, 31 May 2026 22:22:04 +0900 Subject: [PATCH] =?UTF-8?q?feat(agent-office):=20StockAgent=20holdings=20E?= =?UTF-8?q?OD(16:40)+=EB=B8=8C=EB=A6=AC=ED=95=91(08:30)=20cron?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- agent-office/app/agents/stock.py | 39 ++++++++++++++++++++++++++++++++ agent-office/app/scheduler.py | 12 ++++++++++ 2 files changed, 51 insertions(+) diff --git a/agent-office/app/agents/stock.py b/agent-office/app/agents/stock.py index df59a5b..35eab93 100644 --- a/agent-office/app/agents/stock.py +++ b/agent-office/app/agents/stock.py @@ -336,7 +336,46 @@ class StockAgent(BaseAgent): await self.transition("idle", "AI 뉴스 완료") + async def run_holdings_eod(self) -> dict: + """평일 16:40 — 보유종목 시그널 계산·저장.""" + from ..service_proxy import stock_holdings_run + from ..db import create_task, update_task_status, add_log + task_id = create_task(self.agent_id, "holdings_eod", {}) + try: + res = await stock_holdings_run() + update_task_status(task_id, "succeeded", res) + add_log(self.agent_id, f"holdings_eod: {res}", "info", task_id) + return {"ok": True, **res} + except Exception as e: + update_task_status(task_id, "failed", {"error": str(e)}) + add_log(self.agent_id, f"holdings_eod 실패: {e}", "error", task_id) + return {"ok": False, "message": str(e)} + + async def run_holdings_brief(self) -> dict: + """평일 08:30 — 저장된 시그널 브리핑 텔레그램.""" + from ..service_proxy import stock_holdings_brief + from ..notifiers.telegram_stock import send_holdings_brief + from ..db import create_task, update_task_status, add_log + task_id = create_task(self.agent_id, "holdings_brief", {}) + try: + payload = await stock_holdings_brief() + await send_holdings_brief(payload) + update_task_status(task_id, "succeeded", {"date": payload.get("date"), + "count": len(payload.get("holdings", []))}) + add_log(self.agent_id, f"holdings_brief 발송: {payload.get('date')}", "info", task_id) + return {"ok": True} + except Exception as e: + update_task_status(task_id, "failed", {"error": str(e)}) + add_log(self.agent_id, f"holdings_brief 실패: {e}", "error", task_id) + return {"ok": False, "message": str(e)} + async def on_command(self, command: str, params: dict) -> dict: + if command == "holdings_eod": + return await self.run_holdings_eod() + + if command == "holdings_brief": + return await self.run_holdings_brief() + if command == "run_screener": await self.on_screener_schedule() return {"ok": True, "message": "스크리너 실행 트리거 완료"} diff --git a/agent-office/app/scheduler.py b/agent-office/app/scheduler.py index abbc00d..e599c3f 100644 --- a/agent-office/app/scheduler.py +++ b/agent-office/app/scheduler.py @@ -22,6 +22,16 @@ async def _run_stock_ai_news(): if agent: await agent.on_ai_news_schedule() +async def _run_stock_holdings_eod(): + agent = AGENT_REGISTRY.get("stock") + if agent: + await agent.run_holdings_eod() + +async def _run_stock_holdings_brief(): + agent = AGENT_REGISTRY.get("stock") + if agent: + await agent.run_holdings_brief() + async def _run_insta_schedule(): agent = AGENT_REGISTRY.get("insta") if agent: @@ -111,6 +121,8 @@ def init_scheduler(): minute=0, id="stock_ai_news_sentiment", ) + scheduler.add_job(_run_stock_holdings_eod, "cron", day_of_week="mon-fri", hour=16, minute=40, id="stock_holdings_eod") + scheduler.add_job(_run_stock_holdings_brief, "cron", day_of_week="mon-fri", hour=8, minute=30, id="stock_holdings_brief") scheduler.add_job(_run_insta_schedule, "cron", hour=9, minute=30, id="insta_pipeline") # 외부 트렌드 수집은 장 마감 후 16:40 — 9시 주식 활발 시간대 NAS 자원 회피. # screener(16:30)와 10분 스태거: Celeron 2C/2.0GHz 동시 실행 시 CPU 폭주 방지 (CHECK_POINT FU-A)