feat: 안전형 스윙 개선(서킷브레이커·own_trend) + 매수 현금해결 방어

퀀트 리서치(공정 유니버스+walk-forward)로 검증된 안전 게이트 2종과
매수 경로 현금 해결 방어 코드 추가. 모두 기존 시그니처 유지(§4).

- 지수 서킷브레이커: KODEX200 종가 < MA20이면 신규 스윙 진입 전면 중단
  (하락장 상관붕괴=2024H2형 방어). execute_swing_entries가 기존
  check_market_regime의 drop_from_ma20을 재사용(추가 API 없음). 백테스트
  루프에도 동일 적용. 검증: 최근1년 Sharpe 0.82→1.13, CAGR 7.2→8.6%, MDD 개선.
- own_trend 게이트: 평균회귀·눌림목 매수 시 종목 MA20 >= MA60×0.97일 때만
  진입(하락추세 물타기 방지). 실서비스는 recommendations.is_mean_reversion_candidate
  에서 StockAnalysis.ma20/ma60로, check_buy_signal엔 ma20/ma60 선택 파라미터
  (기본 None=하위호환) 추가. 백테스트(kr_backtest_engine, run_backtest)도 평균회귀 한정.
- 매수 현금 해결 방어(trade_executor._execute_buy): 0-현금 캐시를 신뢰하지 않고
  현금<=0이면 자산과 무관하게 KIS 예수금 재조회, 실현금(>0)일 때만 캐시.
  0-현금 고착으로 수량 0이 되는 잠재 무한루프 방어.

검증: code-verifier 통과(CONFIRMED 버그 없음, None-safe, §3/§4/§5 준수),
pytest 442 통과, 6파일 컨테이너 컴파일·리로드 정상.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBmzf1HDnvFHLraJ8eaaKJ
This commit is contained in:
2026-09-16 13:17:17 +09:00
parent a0973812fb
commit 8a8e3700db
6 changed files with 92 additions and 11 deletions

View File

@@ -294,6 +294,8 @@ def check_buy_signal(
prev_volume: int,
is_reversal: bool = False,
rsi_prev: Optional[float] = None, # [2026-03] RSI 반등 확인용 — 3봉 전 RSI
ma20: Optional[float] = None, # [안전형 개선①] own_trend 게이트용 — 종목 자체 MA20
ma60: Optional[float] = None, # [안전형 개선①] own_trend 게이트용 — 종목 자체 MA60
) -> Optional[Dict]:
"""CLAUDE.md 6.2: 매수 조건 판별
@@ -302,12 +304,25 @@ def check_buy_signal(
- BULL: RSI < 40, BB하단 -3%~+1.5%, 거래량 >= 20일평균
- BEAR: RSI < 30, 종가 <= BB하단, 되돌림 캔들, 거래량 > 1.5×20일평균
- RSI 반등 확인: rsi_prev 제공 시, RSI가 반등 중일 때만 진입 허용
[안전형 개선①] own_trend 게이트 (검증 완료: Sharpe 0.27→0.57)
- ma20/ma60 제공 시: 종목 자체 MA20 < MA60*0.97 (하락추세)이면 진입 차단
(물타기 방지 — 시장 국면과 무관하게 개별 종목이 자체 하락추세면 평균회귀 매수 금지)
- ma20/ma60 미제공(기본값 None): 게이트 미적용 — 기존 호출부/테스트 하위호환 유지
"""
# CLAUDE.md 6.1: 횡보장(SIDEWAYS)에서는 모든 진입 신호를 무시
if regime == MarketRegime.SIDEWAYS:
logger.debug("⏭️ SIDEWAYS 국면 — 진입 차단 (CLAUDE.md 6.1)")
return None
# [안전형 개선①] own_trend 게이트 — 종목 자체 하락추세 물타기 방지
if ma20 is not None and ma60 is not None and ma60 > 0 and ma20 < ma60 * 0.97:
logger.debug(
"⏭️ own_trend 게이트 — 종목 자체 하락추세 진입 차단: MA20(%.1f) < MA60(%.1f)*0.97",
ma20, ma60,
)
return None
if current_volume < avg_volume_20d:
return None