auto: 일일 백업 2026-08-28 02:00

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
hyowons
2026-08-28 02:00:06 +09:00
parent 5eb280201d
commit 9e5b1c211e
119 changed files with 2074 additions and 1331 deletions
@@ -151,6 +151,20 @@ def _notify_gone_batch(events: list) -> None:
remaining = min(e['remaining'] for e in evs)
any_filled = any(e['filled'] for e in evs)
unknown = any(not e['ok'] for e in evs)
# 재등록 버튼용 스냅샷 — 예약이 통째로 죽었고, 체결도 판정불가도 없을 때만.
# 체결분을 다시 걸면 이미 판 걸 또 파는 셈이고, 판정불가는 체결일 수도 있어 같은 위험이다.
# 판정 로직을 새로 쓰지 않고 여기서 같이 쓰는 이유 — 두 벌이 되면 한쪽만 고쳐진다.
if remaining == 0 and not any_filled and not unknown:
entry_steps = res.get('entry_steps')
# ⚠️ 이번 배치 이벤트 수 < 원래 계단 수 = **앞선 사이클에 이미 빠진 레그가 있다**
# (거의 항상 장중 체결). 이 배치엔 체결이 없어 위 조건을 통과하므로, 여기서
# 막지 않으면 "일부는 이미 판" 설정을 재등록 후보로 올리게 된다.
if entry_steps and len(evs) == len(entry_steps):
try:
trailing.push_recent(trailing.make_recent_entry(
'trailing', 'not_in_open_orders', res, entry_steps))
except Exception as e:
_log(f'재등록 기록 실패 {res["id"]}: {e!r}')
if any_filled:
icon = '✅'
word = '체결'
@@ -177,9 +191,14 @@ def _notify_gone_batch(events: list) -> None:
lines.append(f' 🎯 {head} → 체결 여부 판정 불가 (체결내역 조회 실패)')
if remaining > 0:
lines.append(f'남은 계단 {remaining}개 — 감시 계속합니다.')
else:
elif any_filled or unknown:
# 체결·판정불가는 재등록 목록에 올리지 않는다(_archive 조건과 동일) —
# 없는 목록으로 안내하면 안 되므로 여기서도 재등록 버튼을 언급하지 않는다.
lines.append('남은 계단 없음 — 계속 쓰시려면 자산웹에서 다시 등록해주세요 '
'(자동 재등록 안 함).')
else:
lines.append('남은 계단 없음 — 자산웹 [📋 진행중] → 최근 종료 에서 ↺ 재등록 '
'(같은 설정이 채워집니다 · 자동 재등록은 안 합니다).')
send_telegram('\n'.join(lines), parse_mode=None)
@@ -318,6 +337,15 @@ def _expire_arms(arms: list, dry_run: bool) -> list:
f'(등록 {a.get("created_at", "?")[:16]} · 발동가 {a["trigger_price"]:,})')
if not dry_run:
trailing.remove_arm(a['id'], 'expired_end_of_day')
# 재등록 버튼용 스냅샷. 삭제 뒤에 남긴다 — 앞에 남기고 죽으면 중복이 생긴다.
# ⚠️ firing_at 이 걸린 예약은 제외 — 주문이 나갔는지 모르는 상태라, 재등록을
# 권하면 이중 매도로 유도하는 셈이다(사람이 미체결부터 확인해야 한다).
if not a.get('firing_at'):
try:
trailing.push_recent(trailing.make_recent_entry(
'arm', 'expired_end_of_day', a, a.get('steps') or []))
except Exception as e:
_log(f'재등록 기록 실패 {a["id"]}: {e!r}')
if dry_run:
return alive
lines = [f'🗓 예약 트레일링 만료 취소 — {len(dead)}건',
@@ -325,7 +353,8 @@ def _expire_arms(arms: list, dry_run: bool) -> list:
for a in dead:
lines.append(f'· {a["symbol_name"]} ({a["symbol"]}) [{a["account"]}] '
f'{a["qty"]:,}주 · 발동가 {a["trigger_price"]:,}원 — 미발동')
lines.append('계속 노리시려면 자산웹에서 다시 등록해 주세요.')
lines.append('계속 노리시려면 자산웹 [📋 진행중] → 최근 종료 에서 ↺ 재등록 을 누르세요 '
'(같은 설정이 채워집니다 · PIN 은 평소대로).')
try:
send_telegram('\n'.join(lines), parse_mode=None)
except Exception as e: