64 lines
2.1 KiB
Python
64 lines
2.1 KiB
Python
"""
|
|
분석종목(Watchlist) 관리 공용 서비스
|
|
|
|
아침 배치(batch_daily_analysis)와 장중 배치(batch_intraday_analysis)가 공유하는
|
|
초기화 함수. 각 배치 스크립트가 자신의 AsyncSession을 전달해 사용한다.
|
|
"""
|
|
from datetime import datetime, date
|
|
import logging
|
|
|
|
from sqlalchemy import select, update
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.models.models import WatchlistStock, StockAnalysis
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# 분석종목 관련 상수
|
|
WATCHLIST_INIT_SIZE: int = 50 # 아침 배치 초기화 종목 수
|
|
WATCHLIST_MAX_SIZE: int = 100 # 최대 관리 종목 수
|
|
WATCHLIST_ENTRY_SCORE: int = 60 # 장중 신규 진입 기준 점수
|
|
WATCHLIST_EXIT_SCORE: int = 20 # 장중 제거 기준 점수
|
|
|
|
|
|
async def initialize_watchlist(session: AsyncSession, analysis_date: date) -> int:
|
|
"""아침 배치 완료 후 분석종목 초기화.
|
|
|
|
기존 활성 종목을 전부 비활성화하고,
|
|
오늘 stock_analysis score 상위 WATCHLIST_INIT_SIZE 개로 새로 채운다.
|
|
|
|
Returns: 추가된 종목 수
|
|
"""
|
|
now = datetime.now()
|
|
|
|
# 1. 기존 활성 종목 전부 비활성화
|
|
await session.execute(
|
|
update(WatchlistStock)
|
|
.where(WatchlistStock.is_active == True)
|
|
.values(is_active=False, removed_at=now, removed_reason="daily_reset")
|
|
)
|
|
|
|
# 2. 오늘 score 상위 N개 조회
|
|
result = await session.execute(
|
|
select(StockAnalysis.stock_code, StockAnalysis.stock_name, StockAnalysis.score)
|
|
.where(StockAnalysis.analysis_date == analysis_date)
|
|
.order_by(StockAnalysis.score.desc())
|
|
.limit(WATCHLIST_INIT_SIZE)
|
|
)
|
|
top_stocks = result.all()
|
|
|
|
# 3. 신규 활성 종목 등록
|
|
for row in top_stocks:
|
|
session.add(WatchlistStock(
|
|
stock_code=row.stock_code,
|
|
stock_name=row.stock_name,
|
|
added_at=now,
|
|
added_reason="morning_batch",
|
|
score_at_add=row.score,
|
|
is_active=True,
|
|
))
|
|
|
|
await session.commit()
|
|
logger.info(f"📋 분석종목 초기화 완료: {len(top_stocks)}개 (기준일: {analysis_date})")
|
|
return len(top_stocks)
|