DB오류 처리중
This commit is contained in:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user