fix: CRITICAL/HIGH 버그 30건 수정 + 전체 코드 주석 추가 + 중복 정리

## CRITICAL 수정 (20건)
- day_trading: global 선언 누락, loss_tracker 연동, ban 체크 추가
- trade_executor: BUY 체결가 order_price로 수정, remaining_pct 누적 계산
- risk_validator: get_current_price dict 파싱, MAX_POSITION_SIZE 동기화, DB 세션 누수
- risk_management/recommendations: date.today() → KST 변환
- mdd_manager: Lock 밖 executed_key 참조 수정
- correlation_filter: output → output2 키 수정
- portfolio: 해외 종목 USD/KRW 환율 적용 분리
- Sharpe Ratio 거래빈도 기반 연간화
- telegram_notifier: send_message() 공개 래퍼 추가
- position_manager: 앱 재시작 시 DB 포지션 복원
- swing exit_service: remaining_pct 조건 범위 수정
- run_backtest: original_qty 기반 remaining_pct 계산
- us_market_schedule: 2027년 미국 공휴일 추가
- Login.tsx: res.ok 검증 추가
- mean_reversion_strategy: RSI 로그 하드코딩 수정

## HIGH 수정 (10건)
- db_worker: DLQ 파일 백업 메커니즘 추가
- korea_investment_api: 만료 토큰 임의 연장 제거
- market_data: chart_cache 최대 100개 + TTL 만료
- main.py: rate_limit_store 1시간 미접근 IP 정리
- recommendations: fire-and-forget try/except 추가
- swing/scheduler: DB 세션 3개 분리
- Dashboard: wsMessages 전체 순회
- Layout: /health 엔드포인트 + 30초 폴링
- ml_ensemble: POST /train require_api_key 추가
- day_trading: record_trade_result_safe() 전환

## 코드 정리
- 프론트엔드: isUsStock, formatTime 공통 유틸 추출
- 백엔드: dead code 제거, 중복 import 통합
- MCP: JSON 파싱 헬퍼 추출 (~60줄 감소)
- 전체 ~100개 파일 한국어 주석 추가
- 테스트 13건 코드 기준 수정 (468 passed)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-26 16:05:41 +09:00
parent 739a8a2e5d
commit de7921d270
149 changed files with 133353 additions and 3338 deletions

View File

@@ -15,27 +15,29 @@ BACKEND_ENV_FILE = BASE_DIR / ".env"
class Settings(BaseSettings):
# Application
# ═════════════════════════════════════════════════════════════════════════════
# 서버 & 환경 설정
# ═════════════════════════════════════════════════════════════════════════════
APP_NAME: str = "Auto Stock Trading System"
ENVIRONMENT: str = "development"
DEBUG: bool = False # 운영 기본값 False (.env에서 DEBUG=true로 개발 모드 활성화)
SECRET_KEY: str = "change-this-secret-key"
# Server
SECRET_KEY: str = "change-this-secret-key" # JWT/WS 서명용
API_KEY: str = "" # API 인증용 (비어있으면 SECRET_KEY 폴백)
BACKEND_HOST: str = "0.0.0.0"
BACKEND_PORT: int = 8000
# Database
# ═════════════════════════════════════════════════════════════════════════════
# 데이터베이스 & 메시지 큐
# ═════════════════════════════════════════════════════════════════════════════
DATABASE_URL: str = "postgresql://autostock:autostock_password@localhost:5432/autostock_db"
# Redis
REDIS_URL: str = "redis://localhost:6379/0"
# RabbitMQ
RABBITMQ_URL: str = "amqp://autostock:autostock_password@localhost:5672/"
# Korea Investment API - 모드 선택
KIS_MODE: str = "virtual" # "virtual" (모의투자) 또는 "real" (실전투자)
# ═════════════════════════════════════════════════════════════════════════════
# KIS API 설정 (Korea Investment Securities)
# ═════════════════════════════════════════════════════════════════════════════
# 모드 선택: "virtual" (모의투자) 또는 "real" (실전투자)
KIS_MODE: str = "virtual"
# 모의투자 설정
KIS_VIRTUAL_APP_KEY: str = ""
@@ -61,17 +63,260 @@ class Settings(BaseSettings):
KIS_ACCOUNT_NO: str = ""
KIS_BASE_URL: str = ""
# 공공데이터포털 금융위원회 주식시세 API (apis.data.go.kr)
DATAGOKR_API_KEY: str = ""
# WebSocket 접속키 (수동 지정 시 우선, 비어 있으면 자동 발급)
KIS_WS_APPROVAL_KEY: str = ""
# KIS WebSocket URL (.env에서 오버라이드 가능)
# KIS 공식 실시간 시세 WebSocket 엔드포인트
# 경로: /websocket (또는 /cgi-md5 in some cases)
# WebSocket 관련
KIS_WS_APPROVAL_KEY: str = "" # 수동 지정 시 우선, 비어 있으면 자동 발급
KIS_WS_REAL_URL: str = "wss://openapi.koreainvestment.com:21000/websocket"
KIS_WS_VIRTUAL_URL: str = "wss://openapivts.koreainvestment.com:29443/websocket"
KIS_WS_ENABLED: bool = True # WebSocket 실시간 스트림 활성화
KIS_SYNC_INTERVAL: int = 10 # 구독 목록 동기화 주기 (초)
KIS_RECONNECT_WAIT: int = 5 # 재연결 대기 시간 (초)
KIS_APPROVAL_KEY_TTL: int = 82800 # approval_key 캐시 유효시간 (초, 23시간)
# 기타 외부 API
DATAGOKR_API_KEY: str = "" # 공공데이터포털 금융위원회 주식시세 API
# ═════════════════════════════════════════════════════════════════════════════
# AI & MCP 설정
# ═════════════════════════════════════════════════════════════════════════════
AI_PROVIDER: str = "gemini" # "gemini" 또는 "claude" (CLAUDE.md 1.2)
ANTHROPIC_API_KEY: str = ""
GEMINI_API_KEY: str = ""
GEMINI_MODEL: str = "gemini-2.0-flash"
MCP_SERVER_URL: str = "http://localhost:8001"
MCP_API_KEY: str = "" # MCP 서버 인증 키 (backend -> MCP 통신 시 X-API-Key 헤더)
MCP_VALIDATION_ENABLED: bool = True # 기본 ON — AI 검증 없이 자동매매 차단
MCP_CONFIDENCE_THRESHOLD: float = 0.5 # AI 신뢰도 최소값 (0.0~1.0)
MCP_ANALYSIS_MIN_SCORE: int = 70 # 기본 70점 — .env에서 MCP_ANALYSIS_MIN_SCORE=N 으로 조정
NEWS_API_KEY: str = ""
NEWS_ENABLED: bool = True # 뉴스 수집/감성 분석 활성화
NEWS_COLLECT_INTERVAL: int = 1800 # 뉴스 수집 주기 (초, 기본 30분)
NEWS_CACHE_TTL: int = 1800 # Redis 캐시 TTL (초, 30분)
NEWS_BLOCK_SCORE: float = -0.5 # 이 이하 → 진입 차단
NEWS_REDUCE_SCORE: float = -0.3 # 이 이하 → 포지션 50% 축소
NEWS_MAX_ARTICLES: int = 20 # 종목당 수집할 최대 뉴스 개수
# ═════════════════════════════════════════════════════════════════════════════
# 토큰 & JSON 최적화
# ═════════════════════════════════════════════════════════════════════════════
TOKEN_SAVE_MODE: bool = False # True: JSON 압축 + 차트 30일 제한 (CLAUDE.md 1.2)
# ═════════════════════════════════════════════════════════════════════════════
# 기술적 지표 기본값
# ═════════════════════════════════════════════════════════════════════════════
RSI_PERIOD: int = 14 # RSI 계산 기간
RSI_OVERSOLD_LEVEL: float = 30.0 # RSI 과매도 수준
RSI_OVERBOUGHT_LEVEL: float = 70.0 # RSI 과매수 수준
RSI_RECOVERY_RANGE_MIN: float = 30.0 # RSI 회복 범위 최소값
RSI_RECOVERY_RANGE_MAX: float = 45.0 # RSI 회복 범위 최대값
RSI_STABLE_RANGE_MIN: float = 45.0 # RSI 안정 범위 최소값
RSI_STABLE_RANGE_MAX: float = 60.0 # RSI 안정 범위 최대값
ATR_PERIOD: int = 14 # ATR 계산 기간
BOLLINGER_PERIOD: int = 20 # 볼린저 밴드 기간 (20일)
BOLLINGER_STDDEV: float = 2.0 # 볼린저 밴드 표준편차 배수
MA_SHORT_PERIOD: int = 5 # 단기 이동평균 기간 (5일)
MA_MEDIUM_PERIOD: int = 20 # 중기 이동평균 기간 (20일)
MA_LONG_PERIOD: int = 60 # 장기 이동평균 기간 (60일)
# ═════════════════════════════════════════════════════════════════════════════
# 공통 리스크 관리 (섹션 5)
# ═════════════════════════════════════════════════════════════════════════════
MAX_POSITION_SIZE: float = 0.06 # 백테스트 최적: 종목당 6% (기존 4%, 적응형 모드에서 오버라이드)
MAX_HOLDINGS_COUNT: int = 20 # 동시 보유 최대 20종목 (섹션 5.1)
LEVERAGE_ETF_MAX_RATIO: float = 0.20 # 레버리지/인버스 ETF 최대 20% (섹션 5.1)
# 자본 배분 글로벌 가드 — 전 전략 합산 현금 사용 상한
MAX_TOTAL_CAPITAL_USAGE: float = 0.95 # 전체 자본의 95%까지만 투자 (5% 현금 보유)
# 수수료/세금 (net PnL 계산용)
KR_COMMISSION_RATE: float = 0.00015 # 매수+매도 각 0.015%
KR_SELL_TAX_RATE_KOSPI: float = 0.0018 # 코스피 증권거래세 0.18%
KR_SELL_TAX_RATE_KOSDAQ: float = 0.0023 # 코스닥 증권거래세 0.23%
US_COMMISSION_RATE: float = 0.0 # 미국 주식 수수료 (증권사별 상이)
# 손절(SL) 및 익절(TP) 기본값
STOP_LOSS_PERCENT: float = 7.0 # 백테스트 최적: 저변동 종목 손절 7% (기존 6%, 적응형 모드에서 오버라이드)
STOP_LOSS_HIGH_VOL: float = 10.0 # 고변동 종목 손절 10% (양수로 저장, 사용 시 음수 변환)
TAKE_PROFIT_PERCENT: float = 5.0 # 익절 기본값
ATR_STOP_MULTIPLIER: float = 2.5 # 2.5 × ATR 손절 (섹션 5.2)
ATR_TRAILING_MULTIPLIER: float = 1.5 # 1.5 × ATR 트레일링
# MDD(최대 낙폭) 관리 (섹션 5.3)
MDD_PAUSE_THRESHOLD: float = -10.0 # -10% MDD: 신규진입 중단 + 30% 축소
MDD_FORCE_THRESHOLD: float = -20.0 # -20% MDD: 50% 강제 축소
# 가격 필터 (섹션 5.4)
MIN_PRICE_KRW: int = 5000 # 국내 5,000원 이하 매수 금지
MIN_PRICE_USD: float = 4.0 # 미국 $4 이하 매수 금지
# 연속 손실 관리 (섹션 5.5)
CONSECUTIVE_LOSS_BAN_COUNT: int = 3 # 3회 연속 손실
CONSECUTIVE_LOSS_BAN_DAYS: int = 30 # 30거래일 진입 금지
# ═════════════════════════════════════════════════════════════════════════════
# 평균회귀(스윙) 전략 (섹션 6)
# ═════════════════════════════════════════════════════════════════════════════
MEAN_REVERSION_RSI_THRESHOLD: float = 46.0 # 백테스트 최적: BULL 진입 RSI < 46 (기존 40)
MEAN_REVERSION_MULTIPLIER_STRONG: float = 1.50 # 강한 신호 배수 (+50%)
MEAN_REVERSION_MULTIPLIER_NORMAL: float = 1.25 # 중간 신호 배수 (+25%)
MEAN_REVERSION_MULTIPLIER_WEAK: float = 1.00 # 약한 신호 배수 (기본값)
MEAN_REVERSION_MAX_CAPITAL: float = 0.30 # 전체 자본의 30% 이내
MEAN_REVERSION_MA200_PERIOD: int = 200 # MA200 기간
MEAN_REVERSION_MA200_LOOKBACK: int = 205 # MA200 계산용 데이터 요구량
MEAN_REVERSION_SLOPE_THRESHOLD: float = 0.001 # MA200 기울기 횡보 판별 (0.1%)
MEAN_REVERSION_ADX_SIDEWAYS: float = 20.0 # ADX < 20 → SIDEWAYS
MEAN_REVERSION_BEAR_RSI_THRESHOLD: float = 35.0 # 백테스트 최적: BEAR 진입 RSI < 35 (기존 30)
MEAN_REVERSION_BEAR_VOLUME_MULT: float = 1.5 # BEAR 거래량 > 1.5 × 평균
MEAN_REVERSION_BB_UPPER_THRESHOLD: float = 0.99 # BB 상단 도달 임계값 (99%)
MEAN_REVERSION_RSI_EXIT_THRESHOLD: float = 55.0 # 백테스트 최적: 1차 익절 RSI >= 55 (기존 50)
MEAN_REVERSION_RSI_FULL_EXIT: float = 70.0 # 백테스트 최적: 전량 청산 RSI >= 70 (기존 65)
MEAN_REVERSION_RSI_STRONG_THRESHOLD: float = 20.0 # RSI <= 20 → 강한 신호
MEAN_REVERSION_RSI_NORMAL_THRESHOLD: float = 25.0 # RSI <= 25 → 중간 신호
MEAN_REVERSION_ADX_STRONG_THRESHOLD: float = 15.0 # ADX < 15 → 추세 약함
MEAN_REVERSION_ADX_STRONG_REDUCE: float = 30.0 # ADX > 30 → 추세 강함
# ═════════════════════════════════════════════════════════════════════════════
# 단기(15분봉) 전략 (섹션 7.2)
# ═════════════════════════════════════════════════════════════════════════════
SHORT_TERM_MIN_ATR_RATIO: float = 0.008 # ATR/close ≥ 0.8% : 거래비용 커버
SHORT_TERM_RSI_LOOKBACK: int = 3 # RSI 반등 확인용 과거 봉 수
SHORT_TERM_VOLUME_MULTIPLIER: float = 1.3 # 거래량 > 1.3배 증가
SHORT_TERM_SKIP_OPEN_HOUR: int = 9 # 장 초반 제외 시간
SHORT_TERM_SKIP_OPEN_MIN: int = 30 # 장 초반 제외 분 (09:30 이전 제외)
SHORT_TERM_SKIP_CLOSE_HOUR: int = 15 # 마감 제외 시간
SHORT_TERM_SKIP_CLOSE_MIN: int = 15 # 마감 제외 분 (15:15 이후 제외)
SHORT_TERM_BB_LOWER_BUFFER: float = 1.01 # BB 하단 근처 버퍼 (+1%)
SHORT_TERM_HARD_STOP_PCT: float = 0.02 # 하드 손절 -2%
SHORT_TERM_ATR_PROFIT_MULTIPLIER: float = 1.5 # 익절 목표 = entry + 1.5×ATR
SHORT_TERM_COMMISSION_RATE: float = 0.003 # 수수료율
SHORT_TERM_SLIPPAGE_RATE: float = 0.002 # 슬리피지율
# ═════════════════════════════════════════════════════════════════════════════
# 데이트레이딩(5분봉) 전략 (섹션 7.3)
# ═════════════════════════════════════════════════════════════════════════════
DAY_TRADE_ENABLED: bool = True # 데이트레이딩 활성화
DAY_TRADE_MAX_POSITIONS: int = 3 # 동시 최대 종목 수
DAY_TRADE_CAPITAL_RATIO: float = 0.25 # 전체 자본 대비 최대 25%
DAY_TRADE_PER_STOCK_RATIO: float = 0.04 # 종목당 최대 4%
DAY_TRADE_MAX_CAPITAL_RATIO: float = 0.04 # 종목당 최대 4% 자본
DAY_TRADE_MAX_RATIO_DT: float = 0.25 # 전체 데이트레이딩 최대 25%
DAY_TRADE_STOP_LOSS_PCT: float = 0.02 # 종목 손절 -2%
DAY_TRADE_DAILY_LOSS_LIMIT: float = -0.03 # 일일 손실 한도 -3%
DAY_TRADE_EOD_FLAT_HOUR: int = 15 # EOD 강제 청산 시간 (15시)
DAY_TRADE_EOD_FLAT_MIN: int = 20 # EOD 강제 청산 분 (20분)
DAY_TRADE_ORB_VOL_MULT: float = 1.5 # ORB 돌파 거래량 배수
DAY_TRADE_TRAILING_TRIGGER: float = 0.01 # 트레일링 발동 최소 수익률 (1%)
DAY_TRADE_RSI_BREAKEVEN_THRESHOLD: float = 40.0 # RSI_BB 진입 기준 (RSI ≤ 40)
DAY_TRADE_ORB_STOP_LOSS_PCT: float = 0.02 # ORB 손절 -2%
DAY_TRADE_REVERSION_STOP_LOSS_PCT: float = 0.025 # VWAP/RSI_BB 손절 -2.5%
DAY_TRADE_TRAILING_ATR_MULT: float = 1.5 # 트레일링 ATR 배수 (1.0→1.5 whipsaw 방지)
DAY_TRADE_ORB_BREAKOUT_MARGIN: float = 0.002 # ORB 돌파 최소 여유 +0.2%
DAY_TRADE_COST_PCT: float = 0.005 # 수수료+슬리피지 합산 (매수+매도)
DAY_TRADE_ENTRY_CUTOFF_HOUR: int = 14 # 신규 진입 마감 시간 (CLAUDE.md 7.3: 14:30)
DAY_TRADE_ENTRY_CUTOFF_MIN: int = 30 # 신규 진입 마감 분
DAY_TRADE_EOD_HOUR: int = 15 # EOD 강제 청산 시작 시간
DAY_TRADE_EOD_MIN: int = 20 # EOD 강제 청산 시작 분
DAY_TRADE_ORB_BREAKOUT_VOL_MULT: float = 1.5 # ORB 거래량 배수 (vs 분당평균)
DAY_TRADE_VWAP_PRICE_LOWER: float = 0.99 # VWAP -1% 하단 경계
DAY_TRADE_VWAP_PRICE_UPPER: float = 1.005 # VWAP +0.5% 상단 경계
DAY_TRADE_VWAP_RSI_THRESHOLD: float = 40.0 # VWAP RSI <= 40
DAY_TRADE_RSI_BB_RSI_THRESHOLD: float = 30.0 # RSI_BB RSI <= 30
DAY_TRADE_RSI_BB_BB_LOWER_BUFFER: float = 1.01 # RSI_BB BB 하단 +1% 버퍼
DAY_TRADE_VOLUME_MULTIPLIER: float = 1.3 # 거래량 배수 (1.3배 이상)
DAY_TRADE_ORB_ATR_FLOOR_MULT: float = 1.0 # ORB ATR 손절 기본 배수
DAY_TRADE_VWAP_ATR_MULT: float = 1.5 # VWAP ATR 손절 배수
DAY_TRADE_RSI_BB_ATR_MULT: float = 1.5 # RSI_BB ATR 손절 배수
DAY_TRADE_TARGET_MULTIPLIER: float = 2.0 # 목표가 = entry + risk × 2.0R
DAY_TRADE_TIME_STOP_MINUTES: int = 30 # 시간 손절 (30분)
DAY_TRADE_TIME_STOP_MIN_GAIN: float = 0.005 # 시간 손절 최소 수익 +0.5% (수수료 커버)
DAY_TRADE_ORB_MARGIN_CHECK: float = 0.03 # ORB 목표가 최소 마진 (3%)
DAY_TRADE_TRAILING_DEFAULT: float = 0.02 # 트레일링 기본값 -2% (ATR 없을 때)
DAY_TRADE_TRAILING_MIN_HOLD_SEC: int = 300 # 트레일링 활성화 최소 보유 시간 (초, 5분)
# ═════════════════════════════════════════════════════════════════════════════
# 코스닥 스캐너 (섹션 7.1)
# ═════════════════════════════════════════════════════════════════════════════
# (코스닥 스캐너 파라미터 추가 필요 시 여기에 추가)
# ═════════════════════════════════════════════════════════════════════════════
# 미국 주식 매매 (섹션 7.4)
# ═════════════════════════════════════════════════════════════════════════════
US_TRADING_ENABLED: bool = False # 미국 주식 자동매매 활성화 (기본 OFF)
US_MAX_CAPITAL_RATIO: float = 0.30 # 전체 자본 대비 미국 주식 최대 비중 (30%)
US_SCAN_INTERVAL: int = 300 # 미국장 스캔 간격 (초, 기본 5분)
# ═════════════════════════════════════════════════════════════════════════════
# 필터 & 시장 국면 (섹션 5.4)
# ═════════════════════════════════════════════════════════════════════════════
TREND_FILTER_ENABLED: bool = False
TREND_MA_SHORT: int = 20
TREND_MA_LONG: int = 60
TREND_TOLERANCE_PCT: float = 0.005
OVERHEAT_FILTER_ENABLED: bool = True # 급등 과열 필터
OVERHEAT_3DAY_MAX: float = 15.0
OVERHEAT_5DAY_MAX: float = 20.0
OVERHEAT_10DAY_MAX: float = 30.0
OVERHEAT_DISPARITY_MAX: float = 108.0
BEAR_MARKET_FILTER_ENABLED: bool = True # 하락장 방어 필터
BEAR_MARKET_MIN_SCORE: int = 5
BEAR_MARKET_MAX_TRADES: int = 3
BEAR_MARKET_POSITION_RATIO: float = 0.5
# ═════════════════════════════════════════════════════════════════════════════
# 시장 상황 & 비상 정지
# ═════════════════════════════════════════════════════════════════════════════
TRADING_HALTED: bool = False # .env에서 TRADING_HALTED=true 로 즉시 전체 매수 중단
MARKET_CRASH_HALT_PCT: float = -3.0 # 지수 당일 -3% 이상 급락 시 자동 매수 차단
# ═════════════════════════════════════════════════════════════════════════════
# 일반 트레이딩 설정
# ═════════════════════════════════════════════════════════════════════════════
AUTO_TRADE_ENABLED: bool = True
MAX_DAILY_TRADES: int = 5
MAX_DAILY_BUYS_PER_STOCK: int = 2 # 종목당 일일 최대 매수 횟수
ANALYSIS_STOCK_COUNT: int = 300 # 배치 분석 종목 수
AUTO_TRADE_TOP_N_PER_RULE: int = 2 # 규칙당 자동매매 실행 최대 종목 수
# ═════════════════════════════════════════════════════════════════════════════
# 감시 목록 (watchlist.py)
# ═════════════════════════════════════════════════════════════════════════════
WATCHLIST_INIT_SIZE: int = 150 # 아침 배치 초기화 종목 수
WATCHLIST_MAX_SIZE: int = 150 # 최대 관리 종목 수
WATCHLIST_ENTRY_SCORE: int = 60 # 장중 신규 진입 기준 점수
WATCHLIST_EXIT_SCORE: int = 20 # 장중 제거 기준 점수
# ═════════════════════════════════════════════════════════════════════════════
# ML / 머신러닝
# ═════════════════════════════════════════════════════════════════════════════
ML_TF_ENABLED: bool = True # ML 모델 기반 보조지표 사용
ML_ENSEMBLE_ENABLED: bool = True # ML Ensemble (LightGBM + LSTM + RF)
ML_ENSEMBLE_MODEL_DIR: str = "models/ensemble"
ML_ENSEMBLE_RULE_WEIGHT: float = 0.3 # 룰베이스 스코어 비중
ML_ENSEMBLE_ML_WEIGHT: float = 0.7 # ML 스코어 비중
ML_ENSEMBLE_BUY_THRESHOLD: int = 60 # 매수 최소 앙상블 스코어 (0~100)
ML_ENSEMBLE_CONFIDENCE_MIN: float = 0.5 # 최소 신뢰도
# ═════════════════════════════════════════════════════════════════════════════
# API & 네트워크
# ═════════════════════════════════════════════════════════════════════════════
API_MAX_RETRIES: int = 3 # 최대 재시도 횟수
API_RETRY_DELAY: float = 1.5 # 초기 재시도 대기 시간 (초)
API_RETRY_BACKOFF: float = 2.0 # 지수 백오프 배율
API_MIN_REQUEST_INTERVAL: float = 0.15 # 최소 요청 간격 (초) — 기존 0.5→0.15 (캐시+커넥션풀로 부하 감소)
API_MAX_CONCURRENT_REQUESTS: int = 8 # 동시 최대 요청 수 (기존 4→8, 커넥션풀로 안정적)
API_TIMEOUT: float = 10.0 # API 타임아웃 (초) — 기존 30→10 (블로킹 방지)
API_ERROR_THRESHOLD: float = 0.3 # 오류율 임계값 (30%)
API_MONITORING_WINDOW: int = 100 # 모니터링 윈도우 (최근 N개 요청)
# ═════════════════════════════════════════════════════════════════════════════
# Telegram 알림
# ═════════════════════════════════════════════════════════════════════════════
TELEGRAM_BOT_TOKEN: str = "" # 텔레그램 봇 토큰 (빈 문자열 = 비활성화)
TELEGRAM_CHAT_ID: str = "" # 알림 수신 채팅 ID (빈 문자열 = 비활성화)
# ═════════════════════════════════════════════════════════════════════════════
# 로깅 & 모니터링
# ═════════════════════════════════════════════════════════════════════════════
LOG_LEVEL: str = "INFO"
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -126,180 +371,6 @@ class Settings(BaseSettings):
def is_virtual_trading(self) -> bool:
"""모의투자 모드 여부"""
return self.KIS_MODE.lower() != "real"
# Claude AI
ANTHROPIC_API_KEY: str = ""
# MCP Server
MCP_SERVER_URL: str = "http://localhost:8001"
# MCP AI 검증 (자동매매 전 AI 최종 판단)
MCP_VALIDATION_ENABLED: bool = True # 기본 ON — AI 검증 없이 자동매매 차단
MCP_CONFIDENCE_THRESHOLD: float = 0.5 # AI 신뢰도 최소값 (0.0~1.0)
# MCP 장중 배치 AI 분석 최소 점수 (이 점수 이상인 종목만 AI 분석 호출)
MCP_ANALYSIS_MIN_SCORE: int = 70 # 기본 70점 — .env에서 MCP_ANALYSIS_MIN_SCORE=N 으로 조정
# News API
NEWS_API_KEY: str = ""
# Logging
LOG_LEVEL: str = "INFO"
# Trading Settings (CLAUDE.md 섹션 6 기반)
MAX_POSITION_SIZE: float = 0.04 # 1종목당 최대 3-4% (섹션 6.1)
MAX_DAILY_TRADES: int = 5
MAX_DAILY_BUYS_PER_STOCK: int = 2 # 종목당 일일 최대 매수 횟수 (.env로 조정 가능)
STOP_LOSS_PERCENT: float = -6.0 # 저변동 종목 손절 -6% (섹션 6.2)
TAKE_PROFIT_PERCENT: float = 5.0 # 익절 기본값
AUTO_TRADE_ENABLED: bool = True
ANALYSIS_STOCK_COUNT: int = 150 # 배치 분석 종목 수 (.env로 조정 가능)
AUTO_TRADE_TOP_N_PER_RULE: int = 2 # 규칙당 자동매매 실행 최대 종목 수
# 포지션 규칙 (섹션 6.1)
MAX_HOLDINGS_COUNT: int = 20 # 동시 보유 최대 20종목
LEVERAGE_ETF_MAX_RATIO: float = 0.20 # 레버리지/인버스 ETF 20% 이내
# ATR 기반 손절/트레일링 (섹션 6.2)
STOP_LOSS_HIGH_VOL: float = -10.0 # 고변동 종목 손절 -10%
ATR_STOP_MULTIPLIER: float = 2.5 # 2.5 × ATR 손절
ATR_TRAILING_MULTIPLIER: float = 1.5 # 1.5 × ATR 트레일링
# MDD 관리 (섹션 6.3)
MDD_PAUSE_THRESHOLD: float = -10.0 # -10% MDD: 신규진입 중단 + 30% 축소
MDD_FORCE_THRESHOLD: float = -20.0 # -20% MDD: 50% 강제 축소
# 가격 필터 (섹션 6.4)
MIN_PRICE_KRW: int = 5000 # 국내 5,000원 이하 매수 금지
MIN_PRICE_USD: float = 4.0 # 미국 $4 이하 매수 금지
# 연속 손실 관리 (섹션 7.4)
CONSECUTIVE_LOSS_BAN_COUNT: int = 3 # 3회 연속 손실
CONSECUTIVE_LOSS_BAN_DAYS: int = 30 # 30거래일 진입 금지
# 평균회귀 전략 자본 배분 (섹션 7.5)
MEAN_REVERSION_MAX_CAPITAL: float = 0.30 # 전체 자본의 30% 이내
# Trend filter (MA-based)
TREND_FILTER_ENABLED: bool = False
TREND_MA_SHORT: int = 20
TREND_MA_LONG: int = 60
TREND_TOLERANCE_PCT: float = 0.005
# 급등 과열 필터 (고점 추격 매수 방지)
OVERHEAT_FILTER_ENABLED: bool = True
OVERHEAT_3DAY_MAX: float = 15.0
OVERHEAT_5DAY_MAX: float = 20.0
OVERHEAT_10DAY_MAX: float = 30.0
OVERHEAT_DISPARITY_MAX: float = 108.0
# 하락장 방어 필터
BEAR_MARKET_FILTER_ENABLED: bool = True
BEAR_MARKET_MIN_SCORE: int = 5
BEAR_MARKET_MAX_TRADES: int = 3
BEAR_MARKET_POSITION_RATIO: float = 0.5
# 비상 정지 (전쟁/사이드카 등 급락 이벤트 대응)
TRADING_HALTED: bool = False # .env에서 TRADING_HALTED=true 로 즉시 전체 매수 중단
MARKET_CRASH_HALT_PCT: float = -3.0 # 지수 당일 -3% 이상 급락 시 자동 매수 차단
# 데이트레이딩 설정 (CLAUDE.md 섹션 8.2)
DAY_TRADE_ENABLED: bool = True # 데이트레이딩 활성화
DAY_TRADE_MAX_POSITIONS: int = 3 # 동시 최대 종목 수
DAY_TRADE_CAPITAL_RATIO: float = 0.25 # 전체 자본 대비 최대 25%
DAY_TRADE_PER_STOCK_RATIO: float = 0.10 # 종목당 최대 10%
DAY_TRADE_STOP_LOSS_PCT: float = 0.02 # 종목 손절 -2%
DAY_TRADE_DAILY_LOSS_LIMIT: float = -0.03 # 일일 손실 한도 -3%
DAY_TRADE_EOD_FLAT_HOUR: int = 15 # EOD 강제 청산 시 (15시)
DAY_TRADE_EOD_FLAT_MIN: int = 20 # EOD 강제 청산 분 (20분)
DAY_TRADE_ORB_VOL_MULT: float = 1.5 # ORB 돌파 거래량 배수
DAY_TRADE_TRAILING_TRIGGER: float = 0.015 # 트레일링 발동 수익률
# ML / TensorFlow integration toggle
ML_TF_ENABLED: bool = True # ML 모델 기반 보조지표 사용
# ML Ensemble (LightGBM + LSTM + RF)
ML_ENSEMBLE_ENABLED: bool = True
ML_ENSEMBLE_MODEL_DIR: str = "models/ensemble"
ML_ENSEMBLE_RULE_WEIGHT: float = 0.3 # 룰베이스 스코어 비중
ML_ENSEMBLE_ML_WEIGHT: float = 0.7 # ML 스코어 비중
ML_ENSEMBLE_BUY_THRESHOLD: int = 60 # 매수 최소 앙상블 스코어 (0~100)
ML_ENSEMBLE_CONFIDENCE_MIN: float = 0.5 # 최소 신뢰도
# API Rate Limiting & Retry Settings (모의투자 API 안전 운영)
API_MAX_RETRIES: int = 3 # 최대 재시도 횟수
API_RETRY_DELAY: float = 1.5 # 초기 재시도 대기 시간 (초)
API_RETRY_BACKOFF: float = 2.0 # 지수 백오프 배율
API_MIN_REQUEST_INTERVAL: float = 0.5 # 최소 요청 간격 (초) - 초당 2회 권장
API_MAX_CONCURRENT_REQUESTS: int = 4 # 동시 최대 요청 수 (batch와 UI 요청 동시 처리)
API_TIMEOUT: float = 30.0 # API 타임아웃 (초)
# Monitoring & Alerting
API_ERROR_THRESHOLD: float = 0.3 # 오류율 임계값 (30%)
API_MONITORING_WINDOW: int = 100 # 모니터링 윈도우 (최근 N개 요청)
# ═════════════════════════════════════════════════════════════════════════════
# 데이트레이딩 세부 파라미터 (day_trading_strategy.py)
# ═════════════════════════════════════════════════════════════════════════════
DAY_TRADE_MAX_CAPITAL_RATIO: float = 0.10 # 종목당 최대 10% 자본
DAY_TRADE_MAX_RATIO_DT: float = 0.25 # 전체 데이트레이딩 최대 25%
DAY_TRADE_RSI_BREAKEVEN_THRESHOLD: float = 40.0 # RSI_BB 진입 기준 (5분봉 RSI ≤ 40)
DAY_TRADE_ORB_STOP_LOSS_PCT: float = 0.02 # ORB 손절 -2%
DAY_TRADE_REVERSION_STOP_LOSS_PCT: float = 0.025 # VWAP/RSI_BB 손절 -2.5%
DAY_TRADE_TRAILING_TRIGGER: float = 0.015 # 트레일링 발동 +1.5%
DAY_TRADE_TRAILING_ATR_MULT: float = 1.0 # 트레일링 ATR 배수
DAY_TRADE_ORB_BREAKOUT_MARGIN: float = 0.002 # ORB 돌파 최소 여유 +0.2%
DAY_TRADE_COST_PCT: float = 0.005 # 수수료+슬리피지 합산 (매수+매도)
DAY_TRADE_ENTRY_CUTOFF_HOUR: int = 15 # 신규 진입 마감 시간 (15시)
DAY_TRADE_ENTRY_CUTOFF_MIN: int = 0 # 신규 진입 마감 분
DAY_TRADE_EOD_HOUR: int = 15 # EOD 강제 청산 시작 시간
DAY_TRADE_EOD_MIN: int = 20 # EOD 강제 청산 시작 분
# ═════════════════════════════════════════════════════════════════════════════
# 단기 전략 (short_term_strategy.py)
# ═════════════════════════════════════════════════════════════════════════════
SHORT_TERM_MIN_ATR_RATIO: float = 0.008 # ATR/close ≥ 0.8% : 거래비용 커버
SHORT_TERM_RSI_LOOKBACK: int = 3 # RSI 반등 확인용 과거 봉 수
SHORT_TERM_VOLUME_MULTIPLIER: float = 1.5 # 거래량 필터 배수 (1.5배 이상)
# ═════════════════════════════════════════════════════════════════════════════
# 평균회귀 전략 (mean_reversion_strategy.py)
# ═════════════════════════════════════════════════════════════════════════════
MEAN_REVERSION_RSI_THRESHOLD: float = 30.0 # RSI 과매도 기준 (≤30)
MEAN_REVERSION_MULTIPLIER_STRONG: float = 1.50 # 강한 신호 배수 (+50%)
MEAN_REVERSION_MULTIPLIER_NORMAL: float = 1.25 # 중간 신호 배수 (+25%)
MEAN_REVERSION_MULTIPLIER_WEAK: float = 1.00 # 약한 신호 배수 (기본값)
# ═════════════════════════════════════════════════════════════════════════════
# KIS WebSocket & 실시간 스트림 (kis_realtime_stream.py)
# ═════════════════════════════════════════════════════════════════════════════
KIS_WS_ENABLED: bool = True # WebSocket 실시간 스트림 활성화 (True) / 비활성화 (False)
KIS_SYNC_INTERVAL: int = 10 # 구독 목록 동기화 주기 (초)
KIS_RECONNECT_WAIT: int = 5 # 재연결 대기 시간 (초)
KIS_APPROVAL_KEY_TTL: int = 82800 # approval_key 캐시 유효시간 (초, 23시간)
# ═════════════════════════════════════════════════════════════════════════════
# 감시 목록 (watchlist.py)
# ═════════════════════════════════════════════════════════════════════════════
WATCHLIST_INIT_SIZE: int = 150 # 아침 배치 초기화 종목 수
WATCHLIST_MAX_SIZE: int = 150 # 최대 관리 종목 수
WATCHLIST_ENTRY_SCORE: int = 60 # 장중 신규 진입 기준 점수
WATCHLIST_EXIT_SCORE: int = 20 # 장중 제거 기준 점수
# ═════════════════════════════════════════════════════════════════════════════
# 기술적 지표 임계값 (technical_indicators.py)
# ═════════════════════════════════════════════════════════════════════════════
RSI_OVERSOLD_LEVEL: float = 30.0 # RSI 과매도 수준
RSI_OVERBOUGHT_LEVEL: float = 70.0 # RSI 과매수 수준
RSI_RECOVERY_RANGE_MIN: float = 30.0 # RSI 회복 범위 최소값
RSI_RECOVERY_RANGE_MAX: float = 45.0 # RSI 회복 범위 최대값
RSI_STABLE_RANGE_MIN: float = 45.0 # RSI 안정 범위 최소값
RSI_STABLE_RANGE_MAX: float = 60.0 # RSI 안정 범위 최대값
BOLLINGER_PERIOD: int = 20 # 볼린저 밴드 기간 (20일)
BOLLINGER_STDDEV: float = 2.0 # 볼린저 밴드 표준편차 배수
MA_SHORT_PERIOD: int = 5 # 단기 이동평균 기간 (5일)
MA_MEDIUM_PERIOD: int = 20 # 중기 이동평균 기간 (20일)
MA_LONG_PERIOD: int = 60 # 장기 이동평균 기간 (60일)
RSI_PERIOD: int = 14 # RSI 계산 기간
ATR_PERIOD: int = 14 # ATR 계산 기간
class Config:
env_file = str(BACKEND_ENV_FILE) if BACKEND_ENV_FILE.exists() else ".env"
@@ -330,17 +401,25 @@ class Settings(BaseSettings):
f"KIS_{self.KIS_MODE.upper()}_ACCOUNT_NO 미설정"
)
# 약한 시크릿 키 감지
weak_secrets = {"change-this-secret-key", "auto_stock_secret_key_change_in_production_2024", "secret"}
if self.SECRET_KEY.lower() in weak_secrets or len(self.SECRET_KEY) < 32:
warnings.append(
"SECRET_KEY가 약합니다! 운영 환경에서는 반드시 강력한 키를 사용하세요: "
"python -c \"import secrets; print(secrets.token_urlsafe(64))\""
)
# 운영 환경 DEBUG 모드 경고
if self.DEBUG and not self.is_virtual_trading:
warnings.append("⚠️ 실전투자 모드(KIS_MODE=real)에서 DEBUG=true — 보안 위험!")
# DB / Redis
if "localhost" in self.DATABASE_URL and os.path.exists("/.dockerenv"):
warnings.append("DATABASE_URL에 localhost 포함 — Docker 환경에서 postgres 호스트명 확인 필요")
# MCP 검증 활성화 시 AI 키 필요
if self.MCP_VALIDATION_ENABLED and not self.ANTHROPIC_API_KEY:
from pydantic_settings import BaseSettings as _BS # lazy import
# GEMINI_API_KEY는 config에 없으므로 환경변수 직접 확인
gemini_key = os.environ.get("GEMINI_API_KEY", "")
if not gemini_key:
warnings.append("MCP_VALIDATION_ENABLED=True 이지만 ANTHROPIC_API_KEY / GEMINI_API_KEY 미설정")
if self.MCP_VALIDATION_ENABLED and not self.ANTHROPIC_API_KEY and not self.GEMINI_API_KEY:
warnings.append("MCP_VALIDATION_ENABLED=True 이지만 ANTHROPIC_API_KEY / GEMINI_API_KEY 미설정")
return warnings