버그 및 크리티컬 에러 수정
This commit is contained in:
@@ -23,6 +23,9 @@ from datetime import datetime, date, timedelta
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
import pytz
|
||||
KST = pytz.timezone('Asia/Seoul')
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
|
||||
from sqlalchemy import delete, select
|
||||
@@ -83,8 +86,8 @@ async def detect_and_log_market_regime() -> str:
|
||||
from pykrx import stock as pykrx_stock
|
||||
from app.services.mean_reversion_strategy import detect_market_regime
|
||||
|
||||
today = datetime.now().strftime("%Y%m%d")
|
||||
start = (datetime.now() - timedelta(days=400)).strftime("%Y%m%d")
|
||||
today = datetime.now(KST).strftime("%Y%m%d")
|
||||
start = (datetime.now(KST) - timedelta(days=400)).strftime("%Y%m%d")
|
||||
|
||||
# KOSPI 지수 코드 1001
|
||||
df = pykrx_stock.get_index_ohlcv_by_date(start, today, "1001")
|
||||
@@ -119,7 +122,7 @@ async def get_all_tradable_stocks(kis_api: KoreaInvestmentAPI, limit: int = 500)
|
||||
try:
|
||||
from pykrx import stock as pykrx_stock
|
||||
|
||||
today = datetime.now().strftime("%Y%m%d")
|
||||
today = datetime.now(KST).strftime("%Y%m%d")
|
||||
|
||||
SKIP_KEYWORDS = [
|
||||
"ETF", "레버리지", "인버스", "KODEX", "TIGER", "ARIRANG",
|
||||
@@ -281,6 +284,7 @@ async def run_db_scanner(analysis_date: date) -> set[str]:
|
||||
- 종가 ≤ BB 하단 × 1.015 (BB 하단 근처)
|
||||
- 시세 ≥ 5,000원
|
||||
- ADX ≤ 30 (지나치게 강한 추세는 평균회귀 부적합)
|
||||
- MA5 ≥ MA20 × 0.95 (ADX 방향 proxy — 강한 하락 추세 종목 제외)
|
||||
|
||||
Returns: 신호 종목 코드 set
|
||||
"""
|
||||
@@ -293,6 +297,8 @@ async def run_db_scanner(analysis_date: date) -> set[str]:
|
||||
StockAnalysis.rsi,
|
||||
StockAnalysis.bollinger_lower,
|
||||
StockAnalysis.adx_14,
|
||||
StockAnalysis.ma5,
|
||||
StockAnalysis.ma20,
|
||||
).where(
|
||||
StockAnalysis.analysis_date == analysis_date,
|
||||
StockAnalysis.current_price >= 5000,
|
||||
@@ -319,9 +325,16 @@ async def run_db_scanner(analysis_date: date) -> set[str]:
|
||||
if adx is not None and adx > 30:
|
||||
continue
|
||||
|
||||
# ADX 방향 proxy: MA5 < MA20 × 0.95 → 강한 하락 추세 → 평균회귀 부적합
|
||||
# DI+/DI- 컬럼이 없으므로 MA 방향으로 추세 하락 여부 판단
|
||||
ma5, ma20 = row.ma5, row.ma20
|
||||
if ma5 is not None and ma20 is not None and ma20 > 0:
|
||||
if float(ma5) < float(ma20) * 0.95:
|
||||
continue
|
||||
|
||||
signal_tickers.add(row.stock_code)
|
||||
|
||||
logger.info("🔍 DB 스캐너: %d개 신호 종목 (RSI≤30 + BB하단 + ADX≤30)", len(signal_tickers))
|
||||
logger.info("🔍 DB 스캐너: %d개 신호 종목 (RSI≤30 + BB하단 + ADX≤30 + MA방향)", len(signal_tickers))
|
||||
return signal_tickers
|
||||
|
||||
except Exception as exc:
|
||||
@@ -348,8 +361,8 @@ async def batch_analyze_all_stocks(limit: int = None):
|
||||
- DB 트랜잭션: 1,000회 → 50회 (20× 감소)
|
||||
- 동시 처리: 5 → 10 종목
|
||||
"""
|
||||
start_time = datetime.now()
|
||||
analysis_date = date.today()
|
||||
start_time = datetime.now(KST)
|
||||
analysis_date = datetime.now(KST).date()
|
||||
|
||||
logger.info("🚀 Starting daily batch analysis for %s", analysis_date)
|
||||
logger.info("⚙️ 동시 처리: %d종목 | 벌크저장 단위: %d개 | API 세마포어: %dreq",
|
||||
@@ -409,7 +422,7 @@ async def batch_analyze_all_stocks(limit: int = None):
|
||||
logger.warning("⚠️ 워치리스트 초기화 실패 (non-critical): %s", exc)
|
||||
|
||||
# 결과 요약
|
||||
duration = (datetime.now() - start_time).total_seconds()
|
||||
duration = (datetime.now(KST) - start_time).total_seconds()
|
||||
stats = korea_investment_api.get_monitor_stats()
|
||||
|
||||
logger.info("=" * 60)
|
||||
|
||||
Reference in New Issue
Block a user