fix(technical_indicators): analyze_rsi RSI<30 구간 BB하단 반등 진입 신호 추가

[문제]
- rsi < 30 이면 signal=None (반등 대기) 으로만 처리
- RSI가 30 이하에서 실제로 반등 시작해도 BUY 신호가 나오지 않음
- 결과적으로 check_buy_signal(rsi_prev)의 반등 확인 로직이 무의미

[수정]
- rsi < 30 AND rsi > rsi_prev (반등 확인) AND 볼린저 하단 근처: BUY 신호
- rsi < 30 AND rsi <= rsi_prev (아직 하락): signal=None 유지 (기존)
- 기존 30~45 반등 구간 로직은 그대로 유지
This commit is contained in:
2026-03-03 10:20:48 +09:00
parent 9104d1a0e7
commit 14e6d87025

View File

@@ -37,7 +37,6 @@ def _passes_uptrend(closes: list, ma_short: int = TREND_MA_SHORT, ma_long: int =
close = closes[-1]
if ma_s is None or ma_l is None:
return None
# 허용 오차 적용: 거의 골든크로스/이탈 직후도 허용
return (ma_s >= ma_l * (1 - tol)) and (close >= ma_s * (1 - tol))
@@ -158,6 +157,14 @@ def analyze_macd(chart_data: list) -> dict:
def analyze_rsi(chart_data: list) -> dict:
"""RSI 분석 + 볼린저 하단 결합 진입 신호
[2026-03 수정] RSI < 30 구간에서도 반등 확인 시 BUY 신호 발생
- 기존: rsi < 30 → signal=None (항상 반등 대기만)
- 개선: rsi < 30 AND rsi > rsi_prev(반등 시작) AND BB 하단 근처 → BUY
→ 이유: RSI 30 이하에서 반등이 시작된 시점이 핵심 진입 기회이며,
30~45 구간으로 올라오기까지 기다리면 이미 3~5% 상승 후 진입
"""
rsi_period = settings.RSI_PERIOD # 기본값 14
if len(chart_data) < rsi_period + 1:
return {"signal": None, "description": "데이터 부족"}
@@ -183,6 +190,7 @@ def analyze_rsi(chart_data: list) -> dict:
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))
# 직전 RSI 계산 (반등 확인용)
if len(chart_data) >= rsi_period + 2:
prev_prices = [float(item.get("stck_clpr", 0)) for item in chart_data[-(rsi_period+2):-(1)]]
prev_gains = []
@@ -206,8 +214,36 @@ def analyze_rsi(chart_data: list) -> dict:
else:
rsi_prev = rsi
# [2026-03] RSI < 30 구간: 반등 시작 + BB 하단 근처 시 BUY
if rsi < 30:
rsi_rebounding = rsi > rsi_prev # RSI 바닥 찍고 반등 중
if rsi_rebounding:
# 볼린저 하단 근처 확인 (-3% ~ +1.5%)
bb_lower = None
if len(chart_data) >= 20:
bb_closes = [float(item.get("stck_clpr", 0)) for item in chart_data[-20:]]
bb_mid = sum(bb_closes) / 20
bb_std = (sum((p - bb_mid) ** 2 for p in bb_closes) / 20) ** 0.5
bb_lower = bb_mid - 2 * bb_std
close = float(chart_data[-1].get("stck_clpr", 0))
if bb_lower and bb_lower * 0.97 <= close <= bb_lower * 1.015:
return {
"signal": "buy",
"description": f"RSI 바닥 탈출 반등 ({rsi_prev:.1f}→{rsi:.1f}) + BB하단"
}
else:
# BB 하단 근처는 아니지만 RSI 반등 중: 약한 신호
return {
"signal": None,
"description": f"RSI 과매도 반등 중 ({rsi_prev:.1f}→{rsi:.1f}) - BB하단 대기"
}
else:
# RSI 여전히 하락 중 → 낙하하는 칼 잡기 방지
return {"signal": None, "description": f"RSI 과매도 심화 ({rsi:.1f}) - 반등 대기"}
# 기존 30~45 반등 구간 로직 유지
elif 30 <= rsi <= 45 and rsi > rsi_prev:
return {"signal": "buy", "description": f"RSI 바닥 탈출 반등 ({rsi:.1f})"}
elif rsi > 70: