신호 정의 재검증 (18:55+ 드롭 케이스 + 18:35 가짜 롱 케이스)
## 변경 사항 ### 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<MA7<MA25<MA99) -> 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) <noreply@anthropic.com>
This commit is contained in:
+11
-10
@@ -294,15 +294,13 @@ def compute_signals(df, interval="5m"):
|
|||||||
(df["close"] < df["MA7"]) & (df["MA7"] < df["MA25"])
|
(df["close"] < df["MA7"]) & (df["MA7"] < df["MA25"])
|
||||||
)
|
)
|
||||||
df["bull_ma"] = (
|
df["bull_ma"] = (
|
||||||
(df["close"] > df["MA7"]) & (df["MA7"] > df["MA25"]) &
|
(df["close"] > df["MA7"]) & (df["MA7"] > df["MA25"])
|
||||||
(df["MA25"] > df["MA99"])
|
|
||||||
)
|
)
|
||||||
df["bear_ma"] = (
|
df["bear_ma"] = (
|
||||||
(df["close"] < df["MA7"]) & (df["MA7"] < df["MA25"]) &
|
(df["close"] < df["MA7"]) & (df["MA7"] < df["MA25"])
|
||||||
(df["MA25"] < df["MA99"])
|
|
||||||
)
|
)
|
||||||
df["long_signal"] = df["bull_ma_2"] & (df["RSI"] < 60) & (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["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["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)
|
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_down"] = oi_series < oi_series.shift(1)
|
||||||
df["oi_up_2"] = df["oi_up"] & df["oi_up"].shift(1).fillna(False)
|
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)
|
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_buy_dom"] = df["taker_buy_vol"] > df["taker_sell_vol"]
|
||||||
df["taker_sell_dom"] = df["taker_sell_vol"] > df["taker_buy_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_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["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_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"] & (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_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_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)
|
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"] > sell_net_avg * 2) &
|
||||||
(df["sell_net"] > 0) &
|
(df["sell_net"] > 0) &
|
||||||
(df["taker_sell_vol"] > _vol_min) &
|
(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
|
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
|
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"] > buy_net_avg * 2) &
|
||||||
(df["buy_net"] > 0) &
|
(df["buy_net"] > 0) &
|
||||||
(df["taker_buy_vol"] > _vol_min) &
|
(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
|
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
|
df["vol_long_signal"] = buy_spike_strong & cooldown_vol_long
|
||||||
|
|||||||
Reference in New Issue
Block a user