청산 권고 트리거 30m/1h 만 + BB 상/하단 차단 제거 + RSI 완화

## 청산 권고 트리거 제한
변동성 큰 날 5m/15m opposite signal 노이즈로 청산권고 폭주 방지.
30m / 1h 의 새 진입 신호만 청산 권고 트리거.

## BB 상/하단 차단 제거 + RSI 완화
거대 양봉/음봉이 BB 한 끝까지 가도 마커 발화하도록.
- long_signal: close < BB_upper 제거, RSI 60 -> 75
- short_signal: close > BB_lower 제거, RSI 35 -> 25

기존 close vs open 방향성 + bull_ma_2/bear_ma_2 만 유지.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
ILSEON-RYU
2026-05-04 23:59:15 +09:00
parent b78176d4b8
commit 260f68adca
+18 -14
View File
@@ -185,18 +185,20 @@ def check_and_alert(df, symbol, interval):
f"손절가: {stop_price:,.2f}"
)
entry_record = {"price": entry_price, "stop": stop_price, "open_time": candle_time, "entry_msg": msg}
# 반대 방향 활성 진입이 있으면 청산 권고 + 추적 해제 (모든 TF 대상)
opposite_dict = alert_state.short_entry if direction == "long" else alert_state.long_entry
opposite_label = "" if direction == "long" else ""
for opp_interval, opp_rec in list(opposite_dict.items()):
if opp_rec is None:
continue
send_telegram(
f"[반대 신호 감지 - {opposite_label} 청산 권장]\n"
f"--- 기존 진입 ---\n{opp_rec['entry_msg']}\n"
f"--- 반대 신호 ---\n{msg}"
)
opposite_dict[opp_interval] = None
# 청산 권고는 30m / 1h 의 새 진입 신호만 트리거 (5m / 15m opposite
# 은 노이즈가 많아 청산권고로 부적합 — 변동성 큰 날 폭주 방지).
if interval in ("30m", "1h"):
opposite_dict = alert_state.short_entry if direction == "long" else alert_state.long_entry
opposite_label = "" if direction == "long" else ""
for opp_interval, opp_rec in list(opposite_dict.items()):
if opp_rec is None:
continue
send_telegram(
f"[반대 신호 감지 - {opposite_label} 청산 권장]\n"
f"--- 기존 진입 ---\n{opp_rec['entry_msg']}\n"
f"--- 반대 신호 ---\n{msg}"
)
opposite_dict[opp_interval] = None
if direction == "long":
alert_state.long_entry[interval] = entry_record
else:
@@ -326,8 +328,10 @@ def compute_signals(df, interval="5m"):
# 현재 캔들 자체의 방향이 신호 방향과 일치해야 발사.
# 늦은 진입 (반등 중인 녹색 캔들에 short 등) 차단 + 현재 진행 중인 breakdown
# (빨간 거대 캔들에 short) 은 통과 시킴.
df["long_signal"] = df["bull_ma_2"] & (df["RSI"] < 60) & (df["MACD_hist"] > df["MACD_hist"].shift(1)) & (df["close"] > df["BB_mid"]) & (df["close"] > df["open"])
df["short_signal"] = df["bear_ma_2"] & (df["RSI"] > 35) & (df["MACD_hist"] < df["MACD_hist"].shift(1)) & (df["close"] < df["BB_mid"]) & (df["close"] < df["open"])
# BB 상/하단 차단 제거 + RSI 임계 완화 (60→75 / 35→25). 큰 양봉/음봉이라도
# 마커 발화하도록. 늦은 진입 차단보다 신호 캡처 우선.
df["long_signal"] = df["bull_ma_2"] & (df["RSI"] < 75) & (df["MACD_hist"] > df["MACD_hist"].shift(1)) & (df["close"] > df["BB_mid"]) & (df["close"] > df["open"])
df["short_signal"] = df["bear_ma_2"] & (df["RSI"] > 25) & (df["MACD_hist"] < df["MACD_hist"].shift(1)) & (df["close"] < df["BB_mid"]) & (df["close"] < df["open"])
df["long_signal"] = df["long_signal"] & (df["long_signal"].rolling(5, min_periods=1).sum().shift(1).fillna(0) == 0)
df["short_signal"] = df["short_signal"] & (df["short_signal"].rolling(5, min_periods=1).sum().shift(1).fillna(0) == 0)