From 255054683a94cda893e0f9ccf2096053342ed99a Mon Sep 17 00:00:00 2001 From: ILSEON-RYU Date: Mon, 4 May 2026 19:47:28 +0900 Subject: [PATCH] =?UTF-8?q?=EC=8B=A0=ED=98=B8=20=EC=A0=95=EC=9D=98=20?= =?UTF-8?q?=EC=9E=AC=EA=B2=80=EC=A6=9D=20(18:55+=20=EB=93=9C=EB=A1=AD=20?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20+=2018:35=20=EA=B0=80=EC=A7=9C=20?= =?UTF-8?q?=EB=A1=B1=20=EC=BC=80=EC=9D=B4=EC=8A=A4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 변경 사항 ### 1. OI 필터 활성도 기반으로 변경 이전: vol_short/vol_long 이 oi_up 만 허용 -> "OI 하락 + 매도 우세 = 롱 청산" 케이스 못 잡음. 이후: oi_active 추가 (|OI pct change| > 0.1%). 방향 무관, 의미 있는 변동만 통과. 신규 진입 + 청산 모두 캡처. ### 2. strong_long/strong_short MA99 의존 제거 이전: bear_ma (close 8h SMA 정렬까지 요구하니 단기 급락 못 잡음. 이후: bear_ma_2 / bull_ma_2 사용 (MA7/MA25 만). MA99 빼버림. bull_ma / bear_ma 정의 자체에서도 MA99 조건 삭제. ### 3. long_signal / short_signal 에 BB 상/하단 차단 추가 이전: long_signal 조건이 close > BB_mid 만 -> BB 상단 위 (과매수) 에서도 발화. 18:35 5분봉 = close 79,775 > BB_upper 79,768 -> 롱 신호 떴는데 직후 -2% 폭락. 이후: long_signal 에 close < BB_upper 추가 (BB 중간선 위 + 상단 아래 중간 zone 만 OK). short_signal 에는 close > BB_lower 추가. ## 검증 - 18:35 5분봉: long_signal=False (BB 상단 위라 차단) ✓ - 19:05 5분봉: vol_short_signal=True (OI 활성 + sell spike) ✓ Co-Authored-By: Claude Opus 4.7 (1M context) --- app_streamlit.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/app_streamlit.py b/app_streamlit.py index dcbc48e..8caa226 100644 --- a/app_streamlit.py +++ b/app_streamlit.py @@ -294,15 +294,13 @@ def compute_signals(df, interval="5m"): (df["close"] < df["MA7"]) & (df["MA7"] < df["MA25"]) ) df["bull_ma"] = ( - (df["close"] > df["MA7"]) & (df["MA7"] > df["MA25"]) & - (df["MA25"] > df["MA99"]) + (df["close"] > df["MA7"]) & (df["MA7"] > df["MA25"]) ) df["bear_ma"] = ( - (df["close"] < df["MA7"]) & (df["MA7"] < df["MA25"]) & - (df["MA25"] < df["MA99"]) + (df["close"] < df["MA7"]) & (df["MA7"] < df["MA25"]) ) - df["long_signal"] = df["bull_ma_2"] & (df["RSI"] < 60) & (df["MACD_hist"] > df["MACD_hist"].shift(1)) & (df["close"] > df["BB_mid"]) - df["short_signal"] = df["bear_ma_2"] & (df["RSI"] > 35) & (df["MACD_hist"] < df["MACD_hist"].shift(1)) & (df["close"] < df["BB_mid"]) + 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["BB_upper"]) + 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["BB_lower"]) 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) @@ -314,6 +312,9 @@ def compute_signals(df, interval="5m"): df["oi_down"] = oi_series < oi_series.shift(1) df["oi_up_2"] = df["oi_up"] & df["oi_up"].shift(1).fillna(False) df["oi_down_2"] = df["oi_down"] & df["oi_down"].shift(1).fillna(False) + # OI 활성도: 방향 무관, 의미 있는 변동만 통과 (0.1% 이상). 신규 진입과 + # 청산 모두 캡처하기 위함. vol_short / vol_long 신호의 OI 필터로 사용. + df["oi_active"] = oi_series.pct_change().abs() > 0.001 df["taker_buy_dom"] = df["taker_buy_vol"] > df["taker_sell_vol"] df["taker_sell_dom"] = df["taker_sell_vol"] > df["taker_buy_vol"] @@ -323,8 +324,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"] & (df["RSI"] < 65) & (df["MACD_hist"] > df["MACD_hist"].shift(1)) & df["oi_up_2"] & df["taker_buy_2"] & df["fr_long_favor"] - df["strong_short_signal"] = df["bear_ma"] & (df["RSI"] > 35) & (df["MACD_hist"] < df["MACD_hist"].shift(1)) & df["oi_down_2"] & df["taker_sell_2"] & df["fr_short_favor"] + 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["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["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) @@ -344,7 +345,7 @@ def compute_signals(df, interval="5m"): (df["sell_net"] > sell_net_avg * 2) & (df["sell_net"] > 0) & (df["taker_sell_vol"] > _vol_min) & - df["oi_up"] + df["oi_active"] ) cooldown_vol_short = sell_spike_strong.rolling(10, min_periods=1).sum().shift(1).fillna(0) == 0 df["vol_short_signal"] = sell_spike_strong & cooldown_vol_short @@ -355,7 +356,7 @@ def compute_signals(df, interval="5m"): (df["buy_net"] > buy_net_avg * 2) & (df["buy_net"] > 0) & (df["taker_buy_vol"] > _vol_min) & - df["oi_up"] + df["oi_active"] ) cooldown_vol_long = buy_spike_strong.rolling(10, min_periods=1).sum().shift(1).fillna(0) == 0 df["vol_long_signal"] = buy_spike_strong & cooldown_vol_long