From 10944ae907e686500fe6f5cbce2164dc0167d12e Mon Sep 17 00:00:00 2001 From: ILSEON-RYU Date: Fri, 1 May 2026 09:55:22 +0900 Subject: [PATCH] =?UTF-8?q?=EC=95=8C=EB=A6=BC=20=EC=8B=A0=ED=98=B8=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?(3=EA=B1=B4=20=EB=AC=B6=EC=9D=8C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 문제 대시보드 차트에는 진입 신호가 정상 표기되지만 텔레그램 알림이 전혀 발송되지 않거나 일부 신호 종류가 영구적으로 누락되는 현상. ## 변경 사항 1. 알림 스레드 캔들 50 -> 200 - MA99(99 SMA) 가 50 캔들에서는 항상 NaN 이라 bull_ma / bear_ma 가 False 가 되고, strong_long_signal / strong_short_signal 이 영원히 발화하지 않던 문제. UI 와 동일한 200 캔들로 맞춰 신호 일관성 확보. - OI 도 50 -> 200 으로 정렬해 lookback 보강. 2. 알림 스레드에 fundingRate fetch + merge 추가 - 기존 스레드 df 에 fundingRate 컬럼이 없어 short_caution_signal ('fundingRate' in df.columns 분기) 가 항상 False 였음. - UI 와 동일한 패턴(get_funding_rate -> floor('1h') merge -> ffill) 으로 fundingRate 합류, short_caution_signal 정상 발화. 3. check_and_alert 1캔들 -> 3캔들 체크 - df.iloc[-1] (현재 형성 중 캔들)만 보던 로직을 df.tail(3) 으로 확장. - 30s 폴링 사이 닫혀버린 캔들의 신호 누락 방지. cooldown 은 그대로 유지되므로 중복 알림은 발생하지 않음. ## 부가 - streamlit.log / streamlit.err.log 를 .gitignore 에 추가 (런타임 산출물 — 6.9MB까지 커지는 상황 발생). Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitignore | 3 +++ app_streamlit.py | 18 ++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e59efd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.claude/settings.local.json +streamlit.log +streamlit.err.log diff --git a/app_streamlit.py b/app_streamlit.py index 82d320e..5b39c6a 100644 --- a/app_streamlit.py +++ b/app_streamlit.py @@ -66,7 +66,7 @@ def send_telegram(message: str): def check_and_alert(df, symbol, interval): now = time.time() - last = df.iloc[-1] + recent = df.tail(3) for sig, key, msg in [ ("strong_long_signal", "strong_long", f"🟢 강한 롱 진입 신호\n{symbol} {interval}"), ("strong_short_signal", "strong_short", f"🔴 강한 숏 진입 신호\n{symbol} {interval}"), @@ -76,7 +76,7 @@ def check_and_alert(df, symbol, interval): ("vol_short_signal", "vol_short", f"🔽 볼륨급등 숏 신호\n{symbol} {interval}"), ("short_caution_signal","short_caution",f"⚠️ 숏 진입 주의 신호\n{symbol} {interval}"), ]: - if last.get(sig, False) and now - _last_alert[key] > ALERT_COOLDOWN: + if sig in recent.columns and recent[sig].fillna(False).any() and now - _last_alert[key] > ALERT_COOLDOWN: send_telegram(msg) _last_alert[key] = now @@ -542,10 +542,10 @@ def _alert_loop(): with _alert_lock: symbol = _alert_symbol interval = _alert_interval - df = get_klines(symbol, interval, 50) + df = get_klines(symbol, interval, 200) oi_period = interval if interval in ["5m","15m","30m","1h","4h","12h","1d","3d","1M"] else "5m" try: - oi = get_open_interest_history(symbol, oi_period, 50) + oi = get_open_interest_history(symbol, oi_period, 200) if not oi.empty: oi_m = oi[["timestamp","sumOpenInterest"]].rename(columns={"timestamp":"open_time"}) df["open_time_r"] = df["open_time"].dt.floor(_to_floor_freq(oi_period)) @@ -554,6 +554,16 @@ def _alert_loop(): df = df.drop(columns=["open_time_r","open_time_oi"], errors="ignore") df["sumOpenInterest"] = df["sumOpenInterest"].ffill() except: pass + try: + fr = get_funding_rate(symbol, 200) + if not fr.empty: + fr_m = fr[["fundingTime","fundingRate"]].rename(columns={"fundingTime":"open_time"}) + fr_m["open_time"] = fr_m["open_time"].dt.floor(_to_floor_freq("1h")) + df["open_time_r2"] = df["open_time"].dt.floor(_to_floor_freq("1h")) + df = df.merge(fr_m, left_on="open_time_r2", right_on="open_time", how="left", suffixes=("","_fr")) + df = df.drop(columns=["open_time_r2","open_time_fr"], errors="ignore") + df["fundingRate"] = df["fundingRate"].ffill().fillna(0) + except: pass df = compute_indicators(df, interval) check_and_alert(df, symbol, interval) except Exception as e: