From 844ee8944fa9108dee85e4c0521a4a683a98e683 Mon Sep 17 00:00:00 2001 From: shuim Date: Fri, 27 Mar 2026 11:06:31 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20ADX=20=EA=B3=84=EC=82=B0=20=EB=B2=84?= =?UTF-8?q?=EA=B7=B8=20=EC=88=98=EC=A0=95=20+=20Crisis=20=EC=86=90?= =?UTF-8?q?=EC=A0=88=20=EC=86=8C=EA=B8=89=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. mean_reversion_strategy.py: ADX 초기값을 sum→mean으로 변경 — ADX가 252로 0-100 범위를 초과하던 버그 수정 — SIDEWAYS 국면 감지가 정상 작동하도록 복원 — _wilder_smooth() 함수는 변경하지 않음 (ATR/DM은 합산이 정상) 2. swing/exit_service.py: 고정비율 손절에 적응형 모드 손절값 반영 — Crisis 모드 전환 시 기존 포지션에도 -3% 손절이 소급 적용됨 — min(config값, adaptive값)으로 타이트한 쪽 선택 Co-Authored-By: Claude Opus 4.6 (1M context) --- backend/app/services/mean_reversion_strategy.py | 8 ++++++-- backend/app/services/swing/exit_service.py | 9 +++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/backend/app/services/mean_reversion_strategy.py b/backend/app/services/mean_reversion_strategy.py index 041e1f0..b1d8a60 100644 --- a/backend/app/services/mean_reversion_strategy.py +++ b/backend/app/services/mean_reversion_strategy.py @@ -137,8 +137,12 @@ def calculate_adx(highs: List[float], lows: List[float], closes: List[float], pe if len(dxs) < period: return None - adx_s = _wilder_smooth(dxs) - return round(adx_s[-1], 2) + # ADX 평활: 초기값은 mean(DX[:period]) — ATR/DM과 달리 합산이 아닌 평균 + # _wilder_smooth()는 초기값이 sum이므로 ADX에는 인라인 계산 사용 + adx_val = sum(dxs[:period]) / period # 초기값 = 평균 + for dx_v in dxs[period:]: + adx_val = adx_val - adx_val / period + dx_v + return round(adx_val, 2) def detect_market_regime(index_closes: List[float], diff --git a/backend/app/services/swing/exit_service.py b/backend/app/services/swing/exit_service.py index 68bd58f..91298d1 100644 --- a/backend/app/services/swing/exit_service.py +++ b/backend/app/services/swing/exit_service.py @@ -251,6 +251,15 @@ async def check_and_execute_exit_v2(db: AsyncSession) -> list[dict]: # ── 고정 비율 폴백 손절 ─────────────────────────────────── if exit_signal is None: stop_loss_pct = abs(float(getattr(settings, "STOP_LOSS_PERCENT", 6.0))) + # 적응형 모드(Crisis 등)의 손절값과 비교하여 타이트한 쪽 적용 + try: + from app.services.adaptive_strategy import get_current_adaptive_params + _adaptive = get_current_adaptive_params() + if not _adaptive.fallback_used: + _adaptive_sl = abs(_adaptive.stop_loss_pct) + stop_loss_pct = min(stop_loss_pct, _adaptive_sl) + except Exception: + pass # 적응형 전략 로드 실패 시 기본값 유지 profit_rate = ((latest_price - avg_price) / avg_price) * 100 if profit_rate <= -stop_loss_pct: from app.services.mean_reversion_strategy import ExitSignal