취소 알림 forming candle 마감 대기 X — 신호 사라지면 즉시 취소

## 사례
2026-05-04 22:00 15분봉 강한 숏 진입 알림 발사 후 같은 캔들 마감
(22:15) 후 [취소 알림]. 사용자: "15분 봉을 15분 후에 취소하는 거냐"

## 원인
pending_groups 검증 로직이 forming candle 동안에는 검증 skip 하고,
candle 이 closed 된 다음에만 신호 재확인. forming 중 신호가 깜빡
False 로 바뀌어도 다음 polling 에서 알 수 없었음.

15분봉 의 경우 forming 기간이 15분 -> 취소 알림이 진입 알림 후 최대
15분 늦게 도착 (사용자 입장 ROI 마이너스 누적).

## 수정
forming/closed 구분 없이 매 polling (30s) 마다 pending 항목의 신호
상태 재확인. 사라졌으면 즉시 [취소 알림] 발송 + 진입 추적 클리어.

흐름:
- forming + 신호 살아있음 -> 계속 감시 (pending 유지)
- forming + 신호 사라짐  -> 즉시 취소 (~30초 이내)
- closed + 신호 살아있음 -> 확정, pending 에서 제거 (조용히)
- closed + 신호 사라짐  -> 즉시 취소 (기존 동작 유지)

per-candle dedup 으로 같은 캔들 재발사는 차단됨 -> 깜빡임 폭주 X.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
ILSEON-RYU
2026-05-04 22:22:35 +09:00
parent 2e916d48cb
commit a9ad52f3d7
+10 -6
View File
@@ -95,22 +95,26 @@ def check_and_alert(df, symbol, interval):
return
forming_ct = df.iloc[-1]["open_time"]
# Phase 1 — pending_groups 검증.
# Phase 1 — pending_groups 검증. forming candle 이라도 매 polling 마다 신호
# 상태 확인. 사라지면 즉시 [취소 알림] (캔들 마감까지 기다리지 않음).
new_pending = []
for p in alert_state.pending_groups:
if p["interval"] != interval:
new_pending.append(p)
continue
ct = p["candle_time"]
if ct == forming_ct:
new_pending.append(p)
continue
row_match = df[df["open_time"] == ct]
if row_match.empty:
continue
continue # 캔들이 df 윈도우 밖 — 검증 포기, drop
row = row_match.iloc[0]
any_still_true = any(bool(row.get(s, False)) for s in p["sig_cols"])
if not any_still_true:
if any_still_true:
if ct == forming_ct:
# forming 중 + 신호 살아있음 → 계속 감시
new_pending.append(p)
# closed + 신호 살아있음 → 확정, pending 에서 제거
else:
# 신호 사라짐 (forming/closed 무관) → 즉시 취소 알림
send_telegram(f"[취소 알림]\n{p['msg']}")
le = alert_state.long_entry.get(interval)
se = alert_state.short_entry.get(interval)