수정본
Some checks failed
CI/CD Pipeline / test-backend (push) Has been cancelled
CI/CD Pipeline / test-frontend (push) Has been cancelled
CI/CD Pipeline / build-and-push (push) Has been cancelled

This commit is contained in:
2026-03-27 14:47:49 +09:00
parent 844ee8944f
commit c818810667
25 changed files with 2708 additions and 266 deletions

View File

@@ -223,6 +223,95 @@ async def lifespan(app: FastAPI):
app.state.ml_retrain_task = asyncio.create_task(ml_retrain_scheduler())
logger.info("ML retrain scheduler started")
# ── AI 전략 스케줄러 (4단계: 장 전/장중/매매직전/장 후) ──────────────────
async def _ai_strategy_scheduler():
"""AI 4단계 전략 스케줄러.
08:30 장 전 Sonnet 배치 분석 (스윙 50종목)
08:50 데이트레이딩 종목 자동 선정 (Haiku)
10분 장중 뉴스 모니터링 (Haiku, 악재 시 Sonnet)
15:40 장 후 리뷰 + Telegram (Sonnet)
"""
import pytz as _tz
from datetime import datetime as _dt
await asyncio.sleep(5)
_kst = _tz.timezone("Asia/Seoul")
_pre_market_done_today = None
_daytrading_done_today = None
_post_market_done_today = None
_last_news_check = None
logger.info("🤖 [AI Strategy] Scheduler started")
while True:
try:
now = _dt.now(_kst)
today = now.date()
hm = now.hour * 100 + now.minute # HHMM 형식
# 평일만 (월~금)
if now.weekday() >= 5:
await asyncio.sleep(300)
continue
# 08:30 — 장 전 스윙 배치 분석
if 830 <= hm < 845 and _pre_market_done_today != today:
try:
from app.services.ai_strategy_service import pre_market_analysis
result = await pre_market_analysis()
suitable = [s for s in result.get("suitable_stocks", []) if s.get("suitable")]
logger.info(f"🤖 [AI Strategy] 장 전 분석 완료: {len(suitable)}종목 적합")
_pre_market_done_today = today
except Exception as e:
logger.warning(f"[AI Strategy] 장 전 분석 실패: {e}")
# 08:50 — 데이트레이딩 종목 선정
if 850 <= hm < 900 and _daytrading_done_today != today:
if settings.DAY_TRADE_ENABLED:
try:
from app.services.ai_strategy_service import select_daytrading_candidates
candidates = await select_daytrading_candidates()
logger.info(f"🤖 [AI Strategy] 데이트레이딩 후보: {len(candidates)}종목")
_daytrading_done_today = today
except Exception as e:
logger.warning(f"[AI Strategy] 데이트레이딩 선정 실패: {e}")
# 09:10~15:20 — 장중 뉴스 모니터링 (10분 주기)
if 910 <= hm <= 1520:
should_check = (
_last_news_check is None
or (now - _last_news_check).total_seconds() >= 600
)
if should_check:
try:
from app.services.ai_strategy_service import monitor_news
alerts = await monitor_news()
if alerts:
logger.warning(f"🚨 [AI Strategy] 뉴스 악재 감지: {len(alerts)}건")
_last_news_check = now
except Exception as e:
logger.debug(f"[AI Strategy] 뉴스 모니터링 실패: {e}")
# 15:40 — 장 후 리뷰
if 1540 <= hm < 1600 and _post_market_done_today != today:
try:
from app.services.ai_strategy_service import post_market_review
review = await post_market_review()
grade = review.get("overall_grade", "?")
logger.info(f"🤖 [AI Strategy] 장 후 리뷰 완료: 등급 {grade}")
_post_market_done_today = today
except Exception as e:
logger.warning(f"[AI Strategy] 장 후 리뷰 실패: {e}")
except Exception as e:
logger.error(f"[AI Strategy] 스케줄러 오류: {e}")
await asyncio.sleep(30)
app.state.ai_strategy_task = asyncio.create_task(_ai_strategy_scheduler())
logger.info("🤖 AI strategy scheduler started (pre-market/news/review)")
# ── 적응형 전략 엔진 초기화 + 주기적 갱신 ────────────────────────────────
async def _adaptive_strategy_scheduler():
"""적응형 전략 파라미터를 2분 주기로 갱신."""
@@ -262,6 +351,7 @@ async def lifespan(app: FastAPI):
"ml_retrain_task",
"pre_market_us_task",
"adaptive_strategy_task",
"ai_strategy_task",
):
try:
task = getattr(app.state, task_attr, None)
@@ -278,6 +368,13 @@ async def lifespan(app: FastAPI):
except Exception as e:
logger.warning(f"Failed to close http_client: {e}")
# ── KIS API httpx 클라이언트 종료 ───────────────────────────────────────
try:
from app.services.korea_investment_api import korea_investment_api
await korea_investment_api.close()
except Exception as e:
logger.warning(f"Failed to close KIS http_client: {e}")
# ── Redis 클라이언트 종료 ─────────────────────────────────────────────────
try:
await close_redis()