feat(vol_breakout): 15m 현물 롱 라이브·모니터·cron 운영 추가

vol_breakout 멀티종목 tick, vol_live HTML 모니터, 마감 봉만 저장하는 캔들 다운로드,
텔레그램 체결 알림, cron/watch 감시 스크립트 및 테스트를 포함한다.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dsyoon
2026-06-29 08:31:14 +09:00
parent 8413bbd536
commit 72de8d534e
58 changed files with 6008 additions and 1286 deletions

View File

@@ -0,0 +1,87 @@
#!/usr/bin/env python3
"""vol_breakout 현물 롱 — TRX/NEAR/WLD 멀티 tick (Binance 15m ATR 이식)."""
from __future__ import annotations
import argparse
import logging
import sys
import time
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.vol_breakout_runner import VolBreakoutRunner
def _configure_logging(verbose: bool) -> None:
level = logging.DEBUG if verbose else logging.INFO
logging.basicConfig(
level=level,
format="%(asctime)s [%(levelname)s] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
def main() -> int:
"""CLI."""
parser = argparse.ArgumentParser(description="Bithumb vol_breakout 현물 롱 tick")
parser.add_argument("--mode", choices=("paper", "live"), default=None)
parser.add_argument("--loop", type=int, default=0, metavar="SEC")
parser.add_argument("-v", "--verbose", action="store_true")
args = parser.parse_args()
_configure_logging(args.verbose)
if args.mode:
import os
os.environ["OPS_MODE"] = args.mode
settings = load_settings()
if not settings.ops_symbols:
print("OPS_SYMBOLS 또는 DOWNLOAD_SYMBOLS(BTC 제외)가 필요합니다.", file=sys.stderr)
return 1
if settings.ops_mode == "live":
if not settings.bithumb_access_key or not settings.bithumb_secret_key:
print("live: BITHUMB_ACCESS_KEY / BITHUMB_SECRET_KEY 필요", file=sys.stderr)
return 1
print("경고: live — 실제 주문 가능")
print(
f"vol_breakout {settings.ops_mode} | symbols={settings.ops_symbols} | "
f"lookback={settings.vol_lookback} atr={settings.vol_atr_mult} "
f"buy_split={settings.vol_buy_split or settings.vol_wallet_pct} "
f"exit={settings.vol_exit_enabled}"
)
def _once() -> dict:
runner = VolBreakoutRunner(settings)
report = runner.tick()
for row in report.get("results") or []:
print(
f" {row.get('symbol')}: fills={row.get('fills')} "
f"note={row.get('note')}"
)
return report
if args.loop <= 0:
_once()
return 0
while True:
try:
_once()
except KeyboardInterrupt:
print("\n종료")
return 0
except Exception:
logging.exception("vol loop tick failed")
time.sleep(args.loop)
if __name__ == "__main__":
raise SystemExit(main())