diff --git a/app_streamlit.py b/app_streamlit.py index 8029aad..3e4ea86 100644 --- a/app_streamlit.py +++ b/app_streamlit.py @@ -54,9 +54,6 @@ ALERT_COOLDOWN = 600 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} - STOP_LOSS_PCT = 0.02 LONG_SIGNALS = {"strong_long_signal", "long_signal", "vol_long_signal"} SHORT_SIGNALS = {"strong_short_signal", "short_signal", "vol_short_signal"} @@ -66,8 +63,16 @@ TF_LABEL_MAP = { "1h": "1시간봉", "4h": "4시간봉", "12h": "12시간봉", "1d": "1일봉", "3d": "3일봉", "1M": "1개월봉", } -_long_entry = None -_short_entry = None + +# Streamlit 은 매 페이지 rerun 마다 모듈 최상단 코드를 재실행한다. 알림용 mutable +# 상태 (dedup, 진입 추적, 스레드 기동 플래그 등)는 한 번만 초기화되어야 하므로 +# globals() 검사로 일회성 초기화를 보장한다. +if "_alert_state_initialized" not in globals(): + _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} + _long_entry = None + _short_entry = None + _alert_state_initialized = True # ────────────────────────────────────────────── # 텔레그램 @@ -626,11 +631,13 @@ def build_chart(symbol, interval, candle_limit=200): # ────────────────────────────────────────────── # 알림 스레드 # ────────────────────────────────────────────── -_alert_symbol = "BTCUSDT" -_alert_interval = "5m" -_alert_lock = threading.Lock() -_alert_started = False -_daily_report_started = False +if "_alert_thread_state_initialized" not in globals(): + _alert_symbol = "BTCUSDT" + _alert_interval = "5m" + _alert_lock = threading.Lock() + _alert_started = False + _daily_report_started = False + _alert_thread_state_initialized = True def _build_signal_df(symbol, interval, klines_limit=200): df = get_klines(symbol, interval, klines_limit) @@ -750,7 +757,8 @@ def send_daily_report(symbol="BTCUSDT"): msg_2x = _build_daily_report_lines(dfs, cutoff_kst, now_kst, symbol, offset=2, header_suffix="2배 시간 (2번째 봉 검증)") send_telegram(msg_2x) -_last_report_date = None +if "_last_report_date" not in globals(): + _last_report_date = None def _daily_report_loop(): global _last_report_date