#!/usr/bin/env python3 """ledger backlog 신호 조회·일괄 처리 (dry-run / execute).""" from __future__ import annotations import argparse import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] SRC = ROOT / "src" if str(SRC) not in sys.path: sys.path.insert(0, str(SRC)) from bithumb.config import load_settings from bithumb.operations.reconcile import inspect_ops_backlog from bithumb.operations.runner import OperationsRunner def main() -> int: """CLI 진입점.""" parser = argparse.ArgumentParser(description="운영 backlog 신호 reconcile") parser.add_argument( "--dry-run", action="store_true", help="pending 목록만 출력 (기본)", ) parser.add_argument( "--execute", action="store_true", help="OperationsRunner tick 1회로 backlog 처리", ) parser.add_argument( "--no-sync", action="store_true", help="execute 시 캔들 sync 생략", ) args = parser.parse_args() settings = load_settings() info = inspect_ops_backlog(settings) merged = info["merged_pending"] summary = info["summary"] print("=== backlog inspect ===") print(f"signal_refresh: {info.get('signal_refresh')}") print(f"force_tail_refresh: {info.get('force_tail_refresh')}") print(f"ledger_pending: {len(info['ledger_pending'])}") print(f"catchup_pending: {len(info['catchup_pending'])}") print(f"merged_pending: {len(merged)}") print(f"backlog_signal_count: {summary['backlog_signal_count']}") print(f"backlog_oldest: {summary['backlog_oldest_datetime']}") print(f"backlog_dropped (per tick limit): {info['backlog_dropped']}") for sig in merged[:50]: print(f" {sig['datetime']} {sig['side']} bar={sig.get('bar_index')}") if len(merged) > 50: print(f" ... 외 {len(merged) - 50}건") if args.execute: from bithumb.operations.runner import OperationsRunner as OpsRunner if settings.ops_mode == "live": print("\n경고: live execute — 실제 주문이 발생할 수 있습니다.") runner = OpsRunner(settings) report = runner.tick(sync_candles=not args.no_sync) print(f"\nexecute 완료: 체결 {len(report.get('executions', []))}건") print(f"ledger_pending_count: {report.get('ledger_pending_count')}") print(f"backlog_dropped_count: {report.get('backlog_dropped_count')}") return 0 if not args.dry_run and not args.execute: print("\n(--dry-run 기본, --execute 로 처리)") return 0 if __name__ == "__main__": raise SystemExit(main())