DB오류 처리중

This commit is contained in:
2026-02-23 16:01:17 +09:00
parent 138bf494db
commit 6d9c9cb010
12 changed files with 368 additions and 109 deletions

View File

@@ -32,26 +32,55 @@ logging.basicConfig(
logger = logging.getLogger(__name__)
async def batch_analysis_scheduler():
"""10분 간격 배치 분석 스케줄러.
장중 10분마다 KIS API로 종목 분석 후 stock_analysis DB에 upsert.
auto_trade_scheduler가 DB를 빠르게 읽어 매매 판단에 활용한다.
"""
await asyncio.sleep(15) # 부팅 안정화 (auto_trade_scheduler보다 늦게 시작)
from app.api.endpoints.recommendations import get_rule_based_recommendations_realtime
interval = int(getattr(settings, "BATCH_ANALYSIS_INTERVAL", 600)) # 기본 10분
logger.info(f"📊 Batch analysis scheduler started (every {interval}s)")
try:
while True:
if not is_market_open():
await asyncio.sleep(1800)
continue
try:
logger.info("🔄 [Batch] 10-min analysis cycle starting...")
result = await get_rule_based_recommendations_realtime()
count = len(result.get("recommendations", [])) if result else 0
logger.info(f"✅ [Batch] Done: {count} stocks saved/updated in stock_analysis DB")
except Exception as e:
logger.error(f"❌ Batch analysis error: {e}", exc_info=True)
await asyncio.sleep(interval)
except asyncio.CancelledError:
logger.info("⏹️ Batch analysis scheduler stopped")
raise
async def auto_trade_scheduler():
"""1분 간격 자동매매 스케줄러.
실시간 분석을 수행하고, 보유 종목 손절/익절을 체크하며, 자동매매를 실행한다.
DB 캐시에서 추천 종목을 읽어 손절/익절 및 신규 매수를 실행한다.
실제 KIS API 분석은 batch_analysis_scheduler(10분)가 담당한다.
"""
# 지연 시작으로 앱 부팅 안정화
await asyncio.sleep(2)
from app.api.endpoints.recommendations import (
get_rule_based_recommendations_realtime,
get_rule_based_recommendations_from_db,
execute_auto_trade_background,
)
from app.api.endpoints.portfolio import check_and_execute_exit_trades
logger.info("⏱️ Auto-trade scheduler started (every 60s)")
logger.info("⏱️ Auto-trade scheduler started (every 60s, DB mode)")
try:
while True:
try:
# 장 운영 시간 체크
if not is_market_open():
logger.info("💤 Market is closed. Skipping auto-trade cycle. Next check in 30 minutes.")
# 장 종료 시에는 30분(1800초) 대기하여 리소스 절약
await asyncio.sleep(1800)
continue
@@ -62,17 +91,17 @@ async def auto_trade_scheduler():
await check_and_execute_exit_trades(session)
except Exception as e:
logger.error(f"Exit trade check error: {e}", exc_info=True)
# 2. 자동매매가 활성화된 경우에만 신규 매수 진행
# 2. 자동매매: DB 캐시에서 추천 조회 (빠름 - API 호출 없음)
if settings.AUTO_TRADE_ENABLED:
logger.info("🔄 Starting real-time analysis cycle...")
rec = await get_rule_based_recommendations_realtime()
logger.info("🔄 Checking DB recommendations for auto-trade...")
rec = await get_rule_based_recommendations_from_db(session)
if rec and rec.get("recommendations_by_rule"):
logger.info(f"📊 Found recommendations, executing auto-trade")
await execute_auto_trade_background(rec, session)
else:
logger.info("⏭️ Auto-trade skipped: no recommendations matched rules")
logger.info("⏭️ Auto-trade skipped: no recommendations in DB")
else:
logger.info("⏸️ Auto-trade disabled - only monitoring stop-loss/take-profit")
except Exception as e:
@@ -260,13 +289,14 @@ async def lifespan(app: FastAPI):
# 스케줄러 시작
app.state.auto_trade_task = asyncio.create_task(auto_trade_scheduler())
app.state.batch_analysis_task = asyncio.create_task(batch_analysis_scheduler())
app.state.day_trade_task = asyncio.create_task(day_trade_scheduler())
yield
# 종료 시 정리 작업
# 스케줄러 중단
for task_attr in ("auto_trade_task", "day_trade_task"):
for task_attr in ("auto_trade_task", "batch_analysis_task", "day_trade_task"):
try:
task = getattr(app.state, task_attr, None)
if task: