""" 05 규칙 알림 텔레그램 메시지 포맷. """ from __future__ import annotations from typing import Any from config import COIN_NAME, MONITOR_ALERT_KRW_AMOUNT, SYMBOL def _fmt_krw(value: float) -> str: """원화 금액 표시.""" if value >= 100: return f"₩{value:,.0f}" if value >= 1: return f"₩{value:,.2f}" return f"₩{value:,.4f}" def _fmt_price(value: float) -> str: """코인 단가 표시.""" if value >= 100: return f"₩{value:,.0f}" if value >= 10: return f"₩{value:,.2f}" if value >= 1: return f"₩{value:,.3f}" return f"₩{value:,.4f}" def _holding_qty(balances: dict[str, dict[str, float]], symbol: str) -> float: """ 잔고 dict에서 코인 보유 수량을 반환합니다. Args: balances: load_balances_dict() 결과. symbol: 통화 코드 (예: WLD). Returns: 보유 수량 (없으면 0). """ info = balances.get(symbol) or {} return float(info.get("balance") or 0.0) def build_rule_alert_message( hit: dict[str, Any], balances: dict[str, dict[str, float]] | None = None, ) -> str: """ 규칙 발화 알림 본문을 만듭니다. 매수: MONITOR_ALERT_KRW_AMOUNT 기준 수량·금액. 매도: 보유 수량(잔고 조회 가능 시) × 가격 = 금액, 없으면 참고 금액 기준. Args: hit: evaluate_live_rules 항목 (side, rule_id, dt, close). balances: 빗썸 잔고 dict. None이면 매도도 참고 금액 기준. Returns: 텔레그램 메시지 문자열. """ side = str(hit.get("side", "")).upper() close = float(hit["close"]) rule_id = hit.get("rule_id", "") dt = hit.get("dt", "") qty_basis = "" if side == "SELL" and balances is not None: qty = _holding_qty(balances, SYMBOL) amount = qty * close qty_basis = "보유 기준" elif side == "BUY": amount = float(MONITOR_ALERT_KRW_AMOUNT) qty = amount / close if close > 0 else 0.0 qty_basis = "참고 매수 규모" else: amount = float(MONITOR_ALERT_KRW_AMOUNT) qty = amount / close if close > 0 else 0.0 qty_basis = "참고 규모(잔고 미조회)" lines = [ f"[DeepCoin {side}] {COIN_NAME}", f"규칙: {rule_id}", f"시각: {dt}", f"가격: {_fmt_price(close)}", f"수량: {qty:,.4f} {SYMBOL} ({qty_basis})", f"금액: {_fmt_krw(amount)}", "※ 알림만 전송, 자동 주문 없음", ] return "\n".join(lines)