feat: Discord 알림, 포지션 복구, 설정 개선 및 docs 추가
Made-with: Cursor
This commit is contained in:
63
src/notifier.py
Normal file
63
src/notifier.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import httpx
|
||||
from loguru import logger
|
||||
|
||||
|
||||
class DiscordNotifier:
|
||||
"""Discord 웹훅으로 거래 알림을 전송하는 노티파이어."""
|
||||
|
||||
def __init__(self, webhook_url: str):
|
||||
self.webhook_url = webhook_url
|
||||
self._enabled = bool(webhook_url)
|
||||
|
||||
def _send(self, content: str) -> None:
|
||||
if not self._enabled:
|
||||
logger.debug("Discord 웹훅 URL 미설정 - 알림 건너뜀")
|
||||
return
|
||||
try:
|
||||
resp = httpx.post(
|
||||
self.webhook_url,
|
||||
json={"content": content},
|
||||
timeout=10,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
except Exception as e:
|
||||
logger.warning(f"Discord 알림 전송 실패: {e}")
|
||||
|
||||
def notify_open(
|
||||
self,
|
||||
symbol: str,
|
||||
side: str,
|
||||
entry_price: float,
|
||||
quantity: float,
|
||||
leverage: int,
|
||||
stop_loss: float,
|
||||
take_profit: float,
|
||||
signal_data: dict = None,
|
||||
) -> None:
|
||||
rsi = (signal_data or {}).get("rsi", 0)
|
||||
macd = (signal_data or {}).get("macd_hist", 0)
|
||||
atr = (signal_data or {}).get("atr", 0)
|
||||
msg = (
|
||||
f"**[{symbol}] {side} 진입**\n"
|
||||
f"진입가: `{entry_price:.4f}` | 수량: `{quantity}` | 레버리지: `{leverage}x`\n"
|
||||
f"SL: `{stop_loss:.4f}` | TP: `{take_profit:.4f}`\n"
|
||||
f"RSI: `{rsi:.2f}` | MACD Hist: `{macd:.6f}` | ATR: `{atr:.6f}`"
|
||||
)
|
||||
self._send(msg)
|
||||
|
||||
def notify_close(
|
||||
self,
|
||||
symbol: str,
|
||||
side: str,
|
||||
exit_price: float,
|
||||
pnl: float,
|
||||
) -> None:
|
||||
emoji = "✅" if pnl >= 0 else "❌"
|
||||
msg = (
|
||||
f"{emoji} **[{symbol}] {side} 청산**\n"
|
||||
f"청산가: `{exit_price:.4f}` | PnL: `{pnl:+.4f} USDT`"
|
||||
)
|
||||
self._send(msg)
|
||||
|
||||
def notify_info(self, message: str) -> None:
|
||||
self._send(f"ℹ️ {message}")
|
||||
Reference in New Issue
Block a user