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

@@ -6,6 +6,8 @@ SQLAlchemy ORM 모델 정의
- TradeHistory: 주문/체결 이력
- TradingRule: 매매 규칙 설정
- StrategyConfig: 전략 파라미터 DB 관리 (하드코딩 대체)
- ExchangeRate: 환율 이력
- UsStockUniverse: 미국 주식 종목 유니버스
"""
from datetime import datetime, date
from typing import Optional, List
@@ -117,7 +119,7 @@ class StrategyConfig(Base):
class TradeHistory(Base):
__tablename__ = "trade_history"
id = Column(Integer, primary_key=True, index=True)
rule_id = Column(Integer)
stock_code = Column(String(20), nullable=False, index=True)
@@ -139,6 +141,11 @@ class TradeHistory(Base):
commission = Column(Numeric(15, 2), nullable=True)
net_profit_loss = Column(Numeric(15, 2), nullable=True)
profit_loss_rate = Column(Numeric(10, 4), nullable=True)
# 전략 구분: 'swing' | 'daytrading' | 'kosdaq_scan' | 'short_term'
strategy_type = Column(String(20), nullable=False, default="swing", index=True)
currency_code = Column(String(3), nullable=False, default="KRW")
exchange_code = Column(String(10), nullable=True)
fx_rate = Column(Numeric(10, 4), nullable=True) # 체결 시점 환율
created_at = Column(DateTime, default=datetime.utcnow, index=True)
executed_at = Column(DateTime)
@@ -155,6 +162,10 @@ class Portfolio(Base):
profit_loss = Column(Numeric(15, 2))
profit_loss_rate = Column(Numeric(10, 4))
market = Column(String(10), nullable=True, default="KRX")
# 전략 구분: 'swing' | 'daytrading'
strategy_type = Column(String(20), nullable=False, default="swing", index=True)
currency_code = Column(String(3), nullable=False, default="KRW")
exchange_code = Column(String(10), nullable=True) # NASD, NYSE, AMEX, KRX
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
@@ -174,14 +185,15 @@ class MarketData(Base):
class News(Base):
__tablename__ = "news"
id = Column(Integer, primary_key=True, index=True)
title = Column(String(500), nullable=False)
content = Column(Text)
source = Column(String(100))
url = Column(Text)
stock_codes = Column(ARRAY(String))
sentiment = Column(String(20))
sentiment = Column(String(20)) # positive / negative / neutral
sentiment_score = Column(Numeric(5, 3), nullable=True) # -1.000 ~ +1.000
published_at = Column(DateTime, index=True)
created_at = Column(DateTime, default=datetime.utcnow)
@@ -249,9 +261,9 @@ class StockAnalysis(Base):
class ActiveTrade(Base):
"""현재 활성화된(보유 중인) 거래를 추적하기 위한 모델"""
__tablename__ = "active_trades"
id = Column(Integer, primary_key=True, index=True)
stock_code = Column(String(20), nullable=False)
stock_code = Column(String(20), nullable=False, index=True) # [FIX] 인덱스 추가
stock_name = Column(String(100))
quantity = Column(Integer, nullable=False)
entry_price = Column(Numeric(15, 2), nullable=False)
@@ -262,14 +274,44 @@ class ActiveTrade(Base):
take_profit = Column(Numeric(15, 2))
order_id = Column(String(100))
entry_reason = Column(Text)
status = Column(String(20), default="active")
status = Column(String(20), default="active", index=True) # [FIX] 인덱스 추가
remaining_pct = Column(Numeric(5, 2), default=1.0)
highest_since_entry = Column(Numeric(15, 2), nullable=True)
strategy_name = Column(String(100), nullable=True)
currency_code = Column(String(3), nullable=False, default="KRW")
exchange_code = Column(String(10), nullable=True) # NASD, NYSE, AMEX, KRX
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
class ExchangeRate(Base):
"""환율 이력 테이블"""
__tablename__ = "exchange_rates"
id = Column(Integer, primary_key=True, index=True)
currency_pair = Column(String(7), nullable=False, index=True) # USD/KRW
rate = Column(Numeric(12, 4), nullable=False)
source = Column(String(50), default="KIS")
recorded_at = Column(DateTime, default=datetime.utcnow, index=True)
class UsStockUniverse(Base):
"""미국 주식 종목 유니버스"""
__tablename__ = "us_stock_universe"
__table_args__ = (
UniqueConstraint('ticker', name='uq_us_ticker'),
)
id = Column(Integer, primary_key=True, index=True)
ticker = Column(String(10), nullable=False, index=True)
company_name = Column(String(200), nullable=False)
exchange = Column(String(10), nullable=False) # NASD, NYSE, AMEX
sector = Column(String(100), nullable=True)
market_cap = Column(BigInteger, nullable=True)
is_active = Column(Boolean, default=True, index=True)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
class TradeJournal(Base):
__tablename__ = "trade_journals"