feat: 리스크 관리 강화 — 포트폴리오 락, MDD 단기전략 비활성화, 상관관계 필터

- portfolio.py: summary_lock으로 동시성 보호, apply_buy/apply_sell async화
- mdd_manager.py: MDD -10% 시 단기전략 비활성화 (is_short_term_strategy_paused)
- loss_tracker.py: DB 직접 접근 → db_worker 큐 기반 전환
- db_worker.py: upsert_stock_ban 태스크 추가
- correlation_filter.py: 섹터 집중도 + 피어슨 상관관계 검증 (CLAUDE.md 5.4)
- trade_executor.py: 상관관계 필터 통합, await 적용
- mean_reversion_strategy.py: config 값 타입 안전성 (float 변환)
- main.py/day_trading.py: MDD 체크 후 자동매매/데이트레이딩 차단

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 17:26:13 +09:00
parent 783e932145
commit a477072bdc
9 changed files with 661 additions and 87 deletions

View File

@@ -225,7 +225,7 @@ def check_buy_signal(
return None
if regime == MarketRegime.BULL:
rsi_ok = rsi <= strategy_cfg.get("MEAN_REVERSION_RSI_THRESHOLD", 30.0)
rsi_ok = rsi <= float(strategy_cfg.get("MEAN_REVERSION_RSI_THRESHOLD") or 30.0)
if rsi_ok:
# [2026-03] RSI 반등 확인: rsi_prev 제공 시 RSI 하락 중이면 진입 금지
@@ -303,8 +303,8 @@ def check_exit_signal(
# ── 1. 손절 (최우선) ──────────────────────────────────────────
# [2026-03] ATR 손절 기준: lowest_since_entry → entry_price
# 이유: 매수 직후 저점이 낮으면 ATR 손절가가 현재가보다 훨씬 아래 → 손절 사실상 무력화
atr_stop_mult = strategy_cfg.get("ATR_STOP_MULTIPLIER", 2.5)
stop_loss_pct = strategy_cfg.get("STOP_LOSS_PERCENT", -6.0) # e.g. -6.0
atr_stop_mult = float(strategy_cfg.get("ATR_STOP_MULTIPLIER") or 2.5)
stop_loss_pct = float(strategy_cfg.get("STOP_LOSS_PERCENT") or -6.0) # e.g. -6.0
atr_stop = entry_price - atr_stop_mult * atr
pct_stop = entry_price * (1 + stop_loss_pct / 100)
stop_price = max(atr_stop, pct_stop) # 높은 값 = 타이트한 손절
@@ -394,13 +394,13 @@ def calculate_position_size(
if rsi is not None:
if rsi <= 20:
multiplier = strategy_cfg.get("MEAN_REVERSION_MULTIPLIER_STRONG", 1.50)
multiplier = float(strategy_cfg.get("MEAN_REVERSION_MULTIPLIER_STRONG") or 1.50)
elif rsi <= 25:
multiplier = strategy_cfg.get("MEAN_REVERSION_MULTIPLIER_NORMAL", 1.25)
multiplier = float(strategy_cfg.get("MEAN_REVERSION_MULTIPLIER_NORMAL") or 1.25)
else:
multiplier = strategy_cfg.get("MEAN_REVERSION_MULTIPLIER_WEAK", 1.00)
multiplier = float(strategy_cfg.get("MEAN_REVERSION_MULTIPLIER_WEAK") or 1.00)
else:
multiplier = strategy_cfg.get("MEAN_REVERSION_MULTIPLIER_WEAK", 1.00)
multiplier = float(strategy_cfg.get("MEAN_REVERSION_MULTIPLIER_WEAK") or 1.00)
if adx is not None and adx < 15:
multiplier = min(multiplier + 0.25, 2.0)