Files
shuim de7921d270 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>
2026-03-26 16:05:41 +09:00

174 lines
5.1 KiB
Python

"""
공유 유틸리티 함수 및 상수
이 모듈은 여러 파일에서 중복되는 함수와 상수를 한 곳에 정의하여
코드 중복을 제거합니다.
포함 항목:
- _is_domestic(): 국내/해외 종목 판별
- CircuitBreakerState Enum: 회로차단기 상태
- Chart data extraction helpers: 차트 데이터 추출 유틸
- DomesticChartItem / OverseasChartItem: 차트 데이터 TypedDict
"""
from enum import Enum
from typing import List, Dict, Any, Optional, TypedDict
# ── 해외 거래소 코드 목록 ────────────────────────────────────────────────────────
OVERSEAS_MARKETS = {"NASD", "NYSE", "AMEX", "TSEX", "SEHK", "SHAA", "SZAA", "HASE", "VNSE"}
class CircuitBreakerState(Enum):
"""회로차단기(Circuit Breaker) 상태.
States:
CLOSED : 정상 운영 (요청 허용)
OPEN : 차단 (recovery_timeout 경과 전까지 요청 거부)
HALF_OPEN: 복구 시도 (1개 요청 허용 → 성공 시 CLOSED, 실패 시 OPEN)
"""
CLOSED = "CLOSED"
OPEN = "OPEN"
HALF_OPEN = "HALF_OPEN"
class DomesticChartItem(TypedDict, total=False):
"""한국 국내 주식 차트 데이터 아이템 (KIS API).
Field descriptions:
stck_clpr: 종가 (closing price)
stck_hgpr: 고가 (high price)
stck_lwpr: 저가 (low price)
stck_oprc: 시가 (opening price)
acml_vol: 누적거래량 (accumulated volume)
stck_bsop_date: 영업일자 (business date)
"""
stck_clpr: str
stck_hgpr: str
stck_lwpr: str
stck_oprc: str
acml_vol: str
stck_bsop_date: str
class OverseasChartItem(TypedDict, total=False):
"""해외 주식 차트 데이터 아이템 (KIS API).
Field descriptions:
clos: 종가 (closing price)
high: 고가 (high price)
low: 저가 (low price)
open: 시가 (opening price)
v: 거래량 (volume)
"""
clos: str
high: str
low: str
open: str
v: str
def _is_domestic(stock_code: str, market: str = None) -> bool:
"""국내 종목 여부 판별.
market 컬럼이 있으면 우선 사용, 없으면 종목코드 패턴으로 폴백.
Args:
stock_code: 종목 코드 (예: "005930")
market: 시장 코드 (예: "NASD", "KRX"). Optional.
Returns:
True if domestic (KRX), False if overseas.
"""
if market:
return market not in OVERSEAS_MARKETS
# 폴백: 6자리 숫자이면 국내(KRX)
return stock_code.isdigit() and len(stock_code) == 6
def extract_closes(chart_data: List[Dict[str, Any]], is_domestic: bool = True) -> List[float]:
"""차트 데이터에서 종가(close price) 추출.
KIS API는 최신순으로 반환하므로 필요시 역순 처리.
Args:
chart_data: KIS API 차트 데이터 (최신순 또는 시간순)
is_domestic: True면 국내(stck_clpr), False면 해외(clos) 필드 사용
Returns:
종가 리스트 (float)
"""
if not chart_data:
return []
key = "stck_clpr" if is_domestic else "clos"
return [float(item.get(key, 0)) for item in chart_data]
def extract_highs(chart_data: List[Dict[str, Any]], is_domestic: bool = True) -> List[float]:
"""차트 데이터에서 고가(high price) 추출.
Args:
chart_data: KIS API 차트 데이터
is_domestic: True면 국내(stck_hgpr), False면 해외(high) 필드 사용
Returns:
고가 리스트 (float)
"""
if not chart_data:
return []
key = "stck_hgpr" if is_domestic else "high"
return [float(item.get(key, 0)) for item in chart_data]
def extract_lows(chart_data: List[Dict[str, Any]], is_domestic: bool = True) -> List[float]:
"""차트 데이터에서 저가(low price) 추출.
Args:
chart_data: KIS API 차트 데이터
is_domestic: True면 국내(stck_lwpr), False면 해외(low) 필드 사용
Returns:
저가 리스트 (float)
"""
if not chart_data:
return []
key = "stck_lwpr" if is_domestic else "low"
return [float(item.get(key, 0)) for item in chart_data]
def extract_opens(chart_data: List[Dict[str, Any]], is_domestic: bool = True) -> List[float]:
"""차트 데이터에서 시가(open price) 추출.
Args:
chart_data: KIS API 차트 데이터
is_domestic: True면 국내(stck_oprc), False면 해외(open) 필드 사용
Returns:
시가 리스트 (float)
"""
if not chart_data:
return []
key = "stck_oprc" if is_domestic else "open"
return [float(item.get(key, 0)) for item in chart_data]
def extract_volumes(chart_data: List[Dict[str, Any]], is_domestic: bool = True) -> List[float]:
"""차트 데이터에서 거래량(volume) 추출.
Args:
chart_data: KIS API 차트 데이터
is_domestic: True면 국내(acml_vol), False면 해외(v) 필드 사용
Returns:
거래량 리스트 (float)
"""
if not chart_data:
return []
key = "acml_vol" if is_domestic else "v"
return [float(item.get(key, 0)) for item in chart_data]