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:
@@ -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 = []
|
||||
@@ -205,9 +213,37 @@ def analyze_rsi(chart_data: list) -> dict:
|
||||
rsi_prev = 100 - (100 / (1 + prev_rs))
|
||||
else:
|
||||
rsi_prev = rsi
|
||||
|
||||
|
||||
# [2026-03] RSI < 30 구간: 반등 시작 + BB 하단 근처 시 BUY
|
||||
if rsi < 30:
|
||||
return {"signal": None, "description": f"RSI 과매도 심화 ({rsi:.1f}) - 반등 대기"}
|
||||
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:
|
||||
|
||||
Reference in New Issue
Block a user