From b9bba95b551198fb43af31f3249d0b3f0ba753a6 Mon Sep 17 00:00:00 2001 From: ILSEON-RYU Date: Fri, 1 May 2026 10:01:32 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B0=99=EC=9D=80=20=EC=BA=94=EB=93=A4?= =?UTF-8?q?=EC=97=90=20=EB=8C=80=ED=95=9C=20=EC=A4=91=EB=B3=B5=20=EC=95=8C?= =?UTF-8?q?=EB=A6=BC=20=EB=B0=A9=EC=A7=80=20(per-candle=20dedup)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 문제 30s 폴링 × 3캔들 윈도우 × 600s 쿨다운이 맞물려, 동일 캔들에 대한 알림이 한 번 발송된 뒤 쿨다운(10분)이 풀리는 시점에 같은 캔들이 여전히 tail(3) 윈도우 안에 남아있으면(5m 기준 최대 15분 머무름) 두 번째 알림이 다시 발송 되는 현상. ## 변경 사항 - 시그널별로 마지막 발화 캔들의 open_time 을 추적하는 _last_fired_candle dict 추가. - check_and_alert 에서 tail(3) 중 신호가 True 인 가장 최신 캔들의 open_time 을 키로 잡고, 직전 발화와 동일하면 스킵. - 기존 ALERT_COOLDOWN(시간 기반) 가드는 그대로 유지 — 다른 캔들로 신호가 연속 발생할 때의 과다 알림은 여전히 차단. 결과적으로 한 캔들당 시그널 종류별로 1회만 알림이 발송됨. Co-Authored-By: Claude Opus 4.7 (1M context) --- app_streamlit.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/app_streamlit.py b/app_streamlit.py index 5b39c6a..f15b7c1 100644 --- a/app_streamlit.py +++ b/app_streamlit.py @@ -53,6 +53,7 @@ BASE = "https://fapi.binance.com" KST = timedelta(hours=9) _last_alert = {"strong_long": 0, "strong_short": 0, "long": 0, "short": 0, "vol_long": 0, "vol_short": 0, "short_caution": 0} +_last_fired_candle = {"strong_long": None, "strong_short": None, "long": None, "short": None, "vol_long": None, "vol_short": None, "short_caution": None} # ────────────────────────────────────────────── # 텔레그램 @@ -76,9 +77,19 @@ 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 sig in recent.columns and recent[sig].fillna(False).any() and now - _last_alert[key] > ALERT_COOLDOWN: - send_telegram(msg) - _last_alert[key] = now + if sig not in recent.columns: + continue + triggered = recent[recent[sig].fillna(False)] + if triggered.empty: + continue + candle_time = triggered.iloc[-1]["open_time"] + if candle_time == _last_fired_candle.get(key): + continue + if now - _last_alert[key] <= ALERT_COOLDOWN: + continue + send_telegram(msg) + _last_alert[key] = now + _last_fired_candle[key] = candle_time # ────────────────────────────────────────────── # 데이터 수집