Files
tradeing/alert_state.py
T
ILSEON-RYU b27e2fcf51 Forming candle 알림 + 마감 후 재검증 + [취소 알림] 패턴
## 동작
이전 커밋 8fd47d0 에서 forming candle 을 알림 대상에서 아예 제외했었지만,
이제 사용자 요청에 따라 "실시간 알림 + 잘못되면 취소 알림" 방식으로 변경.

흐름:
1. 알림 스레드는 매 polling 마다 df.tail(3) (forming candle 포함) 으로
   신호 검사 -> 알림 발사. 빠른 반응 유지.
2. forming candle 기반으로 발사된 알림은 alert_state.pending_groups 에
   등록 (interval, candle_time, msg, sig_cols, direction 보관).
3. 다음 polling 부터, 그 candle 이 더 이상 forming 이 아니면 (=닫힘)
   동일 candle 의 신호 컬럼들을 다시 확인:
   - 하나라도 True 로 살아있음 -> 확정, pending 에서 제거 (조용히)
   - 모두 False 로 바뀜          -> [취소 알림] 발송 + 진입 추적 클리어

## 메시지 예
원래:
  🔽 일반 숏 진입 신호
  BTCUSDT 30분봉
  시간: 2026-05-04 09:30
  진입가: 78,318.10
  손절가: 78,905.49

캔들 마감 후 신호 사라진 경우:
  [취소 알림]
  🔽 일반 숏 진입 신호
  BTCUSDT 30분봉
  시간: 2026-05-04 09:30
  진입가: 78,318.10
  손절가: 78,905.49

## 부가
- pending entry 중 long_entry/short_entry 와 open_time 이 일치하면
  같이 None 으로 클리어 -> 잘못된 손절가 알림 방지.
- 다른 시간봉으로 polling 가는 동안에는 pending 항목 그대로 보존
  (interval 매칭 시점까지 대기). 시간봉 다시 돌아오면 그때 검증 시도.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:14:11 +09:00

40 lines
1.3 KiB
Python

"""
Streamlit 의 매 rerun 마다 메인 스크립트는 새 namespace 에서 재실행되어
모듈 최상단의 mutable state 가 모두 초기화된다 (`globals()` 가드도 우회됨).
이 파일은 별도 모듈로 단 한 번만 import 되므로 (Python 의 sys.modules 캐싱)
state 가 process lifetime 동안 보존된다. 알림 dedup, 진입 추적, 스레드
기동 가드 등 다중 rerun 환경에서 살아남아야 하는 모든 mutable 상태는
여기에 둔다.
"""
import threading
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
# forming candle 에서 발사된 알림은 캔들 마감 후 신호 재검증을 받는다.
# 마감 시점에 신호가 사라졌으면 [취소 알림] 을 보낸다.
# 항목 형식: {"interval", "direction", "candle_time", "msg", "sig_cols"}
pending_groups = []
alert_symbol = "BTCUSDT"
alert_interval = "5m"
alert_lock = threading.Lock()
alert_started = False
daily_report_started = False
last_report_date = None