From 2e916d48cbe87c773657650b815000541c969761 Mon Sep 17 00:00:00 2001 From: ILSEON-RYU Date: Mon, 4 May 2026 20:03:39 +0900 Subject: [PATCH] =?UTF-8?q?1m/3m=20=EC=95=8C=EB=A6=BC=20=EC=A0=9C=EC=99=B8?= =?UTF-8?q?=20+=20=EC=A7=84=EC=9E=85=20=EC=8B=A0=ED=98=B8=20=ED=95=84?= =?UTF-8?q?=ED=84=B0=EB=A5=BC=20close=20vs=20open=20=EB=B0=A9=ED=96=A5?= =?UTF-8?q?=EC=84=B1=20=EA=B2=80=EC=A6=9D=EC=9C=BC=EB=A1=9C=20=EA=B5=90?= =?UTF-8?q?=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 변경 요약 1. ALERT_TIMEFRAMES 에서 1m / 3m 제거 -> [5m, 15m, 30m, 1h] 만 모니터링. 1m / 3m 의 진입 알림 / 취소 알림 / 손절가 알림 모두 차단. 2. 진입 신호 (long/short/strong_long/strong_short) 의 늦은 진입 차단 필터를 BB position + 3봉 모멘텀 -> 현재 캔들 자체의 close vs open 방향성으로 교체. - long_signal / strong_long_signal: close > open (이번 캔들이 양봉) - short_signal / strong_short_signal: close < open (이번 캔들이 음봉) 이전 BB position 필터는 breakdown / breakup 캔들에서 추세 진입을 막아버리는 부작용이 있었음 (예: 15m 19:00 -1.4% 거대 빨간 캔들에 short 마커 안 뜸). close vs open 검증은 "이번 캔들 자체가 신호 방향과 일치" 만 요구해, 진행 중인 추세는 잡고, 반등 / 반락 캔들의 늦은 진입은 차단. ## 변경 안 한 것 - 다단계 ROI 알림 (-5/-10/-15%) 은 사용자 의도가 별개 (1m/3m 볼륨 변화를 선행 지표로 활용) 라 이번 커밋에선 미적용. 추후 별도 작업. - vol_long / vol_short 신호 정의는 그대로. Co-Authored-By: Claude Opus 4.7 (1M context) --- app_streamlit.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/app_streamlit.py b/app_streamlit.py index 4ed4302..a46ea69 100644 --- a/app_streamlit.py +++ b/app_streamlit.py @@ -299,15 +299,14 @@ def compute_signals(df, interval="5m"): df["bear_ma"] = ( (df["close"] < df["MA7"]) & (df["MA7"] < df["MA25"]) ) - # BB position: 0 = BB_lower, 0.5 = BB_mid, 1 = BB_upper. + # BB position 보존 (디버그 / 차트 hover 용도) — 신호 정의에는 미사용. bb_range = (df["BB_upper"] - df["BB_lower"]).replace(0, float("nan")) df["bb_pos"] = (df["close"] - df["BB_lower"]) / bb_range - # 최근 3봉 모멘텀: 이미 큰 폭으로 움직인 후의 늦은 진입 차단. - # 롱: 최근 3봉 동안 이미 +0.5% 이상 오른 상태면 차단 (이미 늦음). - # 숏: 최근 3봉 동안 이미 -0.5% 이상 떨어진 상태면 차단. - recent_change_pct = (df["close"] - df["close"].shift(3)) / df["close"].shift(3) * 100 - df["long_signal"] = df["bull_ma_2"] & (df["RSI"] < 60) & (df["MACD_hist"] > df["MACD_hist"].shift(1)) & (df["bb_pos"] > 0.5) & (df["bb_pos"] < 0.7) & (recent_change_pct < 0.5) - df["short_signal"] = df["bear_ma_2"] & (df["RSI"] > 35) & (df["MACD_hist"] < df["MACD_hist"].shift(1)) & (df["bb_pos"] < 0.5) & (df["bb_pos"] > 0.3) & (recent_change_pct > -0.5) + # 현재 캔들 자체의 방향이 신호 방향과 일치해야 발사. + # 늦은 진입 (반등 중인 녹색 캔들에 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"]) 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) @@ -331,8 +330,8 @@ def compute_signals(df, interval="5m"): df["fr_long_favor"] = df["taker_buy_vol"].rolling(3).mean() > df["taker_sell_vol"].rolling(3).mean() df["fr_short_favor"] = df["taker_sell_vol"].rolling(3).mean() > df["taker_buy_vol"].rolling(3).mean() - df["strong_long_signal"] = df["bull_ma_2"] & (df["RSI"] < 65) & (df["MACD_hist"] > df["MACD_hist"].shift(1)) & df["oi_up_2"] & df["taker_buy_2"] & df["fr_long_favor"] & (df["bb_pos"] > 0.5) & (df["bb_pos"] < 0.7) & (recent_change_pct < 0.5) - df["strong_short_signal"] = df["bear_ma_2"] & (df["RSI"] > 35) & (df["MACD_hist"] < df["MACD_hist"].shift(1)) & df["oi_down_2"] & df["taker_sell_2"] & df["fr_short_favor"] & (df["bb_pos"] < 0.5) & (df["bb_pos"] > 0.3) & (recent_change_pct > -0.5) + df["strong_long_signal"] = df["bull_ma_2"] & (df["RSI"] < 65) & (df["MACD_hist"] > df["MACD_hist"].shift(1)) & df["oi_up_2"] & df["taker_buy_2"] & df["fr_long_favor"] & (df["close"] > df["open"]) + df["strong_short_signal"] = df["bear_ma_2"] & (df["RSI"] > 35) & (df["MACD_hist"] < df["MACD_hist"].shift(1)) & df["oi_down_2"] & df["taker_sell_2"] & df["fr_short_favor"] & (df["close"] < df["open"]) df["strong_long_signal"] = df["strong_long_signal"] & (df["strong_long_signal"].rolling(10, min_periods=1).sum().shift(1).fillna(0) == 0) df["strong_short_signal"] = df["strong_short_signal"] & (df["strong_short_signal"].rolling(10, min_periods=1).sum().shift(1).fillna(0) == 0) @@ -700,7 +699,7 @@ def _build_signal_df(symbol, interval, klines_limit=200): df = compute_indicators(df, interval) return df -ALERT_TIMEFRAMES = ["1m", "3m", "5m", "15m", "30m", "1h"] +ALERT_TIMEFRAMES = ["5m", "15m", "30m", "1h"] def _alert_loop(): while True: