feat: add position monitor logging with real-time price tracking
Log current price and unrealized PnL every 5 minutes while holding a position, using the existing kline WebSocket's unclosed candle data for real-time price updates. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
21
src/bot.py
21
src/bot.py
@@ -235,6 +235,26 @@ class TradingBot:
|
||||
self._entry_price = None
|
||||
self._entry_quantity = None
|
||||
|
||||
_MONITOR_INTERVAL = 300 # 5분
|
||||
|
||||
async def _position_monitor(self):
|
||||
"""포지션 보유 중일 때 5분마다 현재가·미실현 PnL을 로깅한다."""
|
||||
while True:
|
||||
await asyncio.sleep(self._MONITOR_INTERVAL)
|
||||
if self.current_trade_side is None:
|
||||
continue
|
||||
price = self.stream.latest_price
|
||||
if price is None or self._entry_price is None or self._entry_quantity is None:
|
||||
continue
|
||||
pnl = self._calc_estimated_pnl(price)
|
||||
cost = self._entry_price * self._entry_quantity
|
||||
pnl_pct = (pnl / cost * 100) if cost > 0 else 0.0
|
||||
logger.info(
|
||||
f"포지션 모니터 | {self.current_trade_side} | "
|
||||
f"현재가={price:.4f} | PnL={pnl:+.4f} USDT ({pnl_pct:+.2f}%) | "
|
||||
f"진입가={self._entry_price:.4f}"
|
||||
)
|
||||
|
||||
async def _close_position(self, position: dict):
|
||||
"""포지션 청산 주문만 실행한다. PnL 기록/알림은 _on_position_closed 콜백이 담당."""
|
||||
amt = abs(float(position["positionAmt"]))
|
||||
@@ -298,4 +318,5 @@ class TradingBot:
|
||||
api_key=self.config.api_key,
|
||||
api_secret=self.config.api_secret,
|
||||
),
|
||||
self._position_monitor(),
|
||||
)
|
||||
|
||||
@@ -116,6 +116,8 @@ class MultiSymbolStream:
|
||||
}
|
||||
# 첫 번째 심볼이 주 심볼 (XRP)
|
||||
self.primary_symbol = self.symbols[0]
|
||||
# 미종료 캔들 포함 최신 가격 (포지션 모니터링용)
|
||||
self.latest_price: float | None = None
|
||||
|
||||
def parse_kline(self, msg: dict) -> dict:
|
||||
k = msg["k"]
|
||||
@@ -142,6 +144,9 @@ class MultiSymbolStream:
|
||||
symbol = data["s"].lower()
|
||||
candle = self.parse_kline(data)
|
||||
|
||||
if symbol == self.primary_symbol:
|
||||
self.latest_price = candle["close"]
|
||||
|
||||
if candle["is_closed"] and symbol in self.buffers:
|
||||
self.buffers[symbol].append(candle)
|
||||
if symbol == self.primary_symbol and self.on_candle:
|
||||
|
||||
Reference in New Issue
Block a user