전략 취약점 15건 수정 (코드 리뷰 기반)

## CRITICAL/HIGH (S1-S8)
- S1: Aggressive 모드 %B 스케일링 캡 1.3 (BB 중앙선 위 매수 방지)
- S2: ML scaler train-only fit (데이터 누수 제거)
- S3: SIDEWAYS = ADX<20 AND slope≈0 (트렌드 초기 차단 해소)
- S4: EOD 청산 실패 시 재시도 + CRITICAL 로그
- S5: 일일 손실 한도에 미실현 P&L 포함
- S6: trailing stop 고점 매 사이클 갱신
- S7: 섹터 필터 미매핑 종목 "기타" 분류 (max 3 적용)
- S8: 스캐너 RSI 기준 25→46, BB 점수 -3%~+1.5% 구간

## MEDIUM (M1-M7)
- M1: 스캐너 최소 거래량 100만→10만주
- M2: ADX 히스테리시스 18/22 (국면 플리핑 방지)
- M3: 분할매도 최소 수익 1.0%→0.5%
- M4: ORB 갭 필터 4% + 레인지 폭 0.3% 최소
- M5: 쿨다운 스트릭 부분매도 시 미변경
- M6: MDD 강제매도 loss_tracker 기록 제거 (허위 ban 방지)
- M7: RSI Wilder 스무딩으로 통일

## 인프라/보안
- 인증 누락 엔드포인트 수정 (analysis, journals)
- nginx 보안 헤더 location 블록 누락 수정
- Alembic 마이그레이션 IF NOT EXISTS 가드 추가
- SellRequest/UsOrderRequest 입력 검증 강화
- 차트 네이버 폴백 추가 (DB 데이터 없을 때)
- 서버 이전 시 자동 DB 마이그레이션 + KRX 초기 수집
- CLAUDE.md 섹션 5.1 백테스트 값 동기화 (4%→6%, -6%→-7%)
- MAX_SWING_POSITIONS 25→20 (CLAUDE.md 준수)
- mdd_manager failed_count에서 skip 종목 제외

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-03 11:41:52 +09:00
parent eda5d76af9
commit 5f0f839039
22 changed files with 299 additions and 132 deletions

View File

@@ -18,8 +18,9 @@ logger = logging.getLogger(__name__)
# 가격 필터 (CLAUDE.md 섹션 6.4)
MIN_PRICE_KRW = 5_000
# 전일 거래량 최솟값: 100만주 미만 종목 제외 (유동성 부족)
MIN_DAILY_VOLUME = 1_000_000
# 전일 거래량 최솟값: 10만주 미만 종목 제외 (유동성 부족)
# market_analyzer.py와 동일 수준. LIQUIDITY_PERCENTILE=0.80 이 추가 필터 역할.
MIN_DAILY_VOLUME = 100_000
# 거래대금 상위 20% 임계값 (하위 80% 제외)
LIQUIDITY_PERCENTILE = 0.80
@@ -155,8 +156,13 @@ class KosdaqScanner:
pct_vs_lower = (td.close - bb_lower) / bb_lower * 100
volume_ratio = td.volume / volume_ma20
rsi_score = max(0.0, (25.0 - rsi14) / 25.0)
bb_score = min(max(0.0, (0.0 - pct_vs_lower) / 3.0), 1.0) # 상한 1.0 — 폭락 종목 점수 왜곡 방지
# [S8] RSI 점수: config의 MEAN_REVERSION_RSI_THRESHOLD(46.0) 기준으로 정규화
from app.core.config import settings as _settings
_rsi_threshold = _settings.MEAN_REVERSION_RSI_THRESHOLD # 46.0
rsi_score = max(0.0, (_rsi_threshold - rsi14) / _rsi_threshold)
# [S8] BB 점수: CLAUDE.md 6.2 기준 -3%~+1.5% 구간 보상
# pct_vs_lower <= -3%: 최대 점수 1.0, +1.5% 이상: 점수 0.0
bb_score = min(max(0.0, (1.5 - pct_vs_lower) / 4.5), 1.0)
volume_score = min(volume_ratio, 2.0)
total_score = rsi_score * 0.5 + bb_score * 0.3 + volume_score * 0.2
@@ -169,8 +175,8 @@ class KosdaqScanner:
rsi_turning = rsi_prev is not None and rsi14 > rsi_prev
reason_parts = []
if rsi14 <= 25:
reason_parts.append(f"RSI({rsi14:.1f})≤25")
if rsi14 <= _rsi_threshold:
reason_parts.append(f"RSI({rsi14:.1f})≤{_rsi_threshold:.0f}")
if pct_vs_lower <= 0:
reason_parts.append(f"BB하단({pct_vs_lower:.1f}%)")
if volume_ratio >= 1.5: