feat(dashboard): show unrealized PnL on position cards (5min update)

Parse position monitor logs (5min interval) to update current_price,
unrealized_pnl and unrealized_pnl_pct in bot_status. Position cards
now display USDT amount and percentage, colored green/red. Falls back
to entry/current price calculation if monitor data unavailable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
21in7
2026-03-09 20:55:53 +09:00
parent c6c60b274c
commit af91b36467
4 changed files with 170 additions and 4 deletions

View File

@@ -68,6 +68,12 @@ PATTERNS = {
r".*\[(?P<symbol>\w+)\] 오늘 누적 PnL: (?P<pnl>[+\-\d.]+) USDT"
),
"position_monitor": re.compile(
r"(?P<ts>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})"
r".*\[(?P<symbol>\w+)\] 포지션 모니터 \| (?P<direction>\w+) \| "
r"현재가=(?P<price>[\d.]+) \| PnL=(?P<pnl>[+\-\d.]+) USDT \((?P<pnl_pct>[+\-\d.]+)%\)"
),
"bot_start": re.compile(
r"(?P<ts>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})"
r".*\[(?P<symbol>\w+)\] 봇 시작, 레버리지 (?P<leverage>\d+)x"
@@ -272,6 +278,15 @@ class LogParser:
self._set_status("ml_threshold", m.group("threshold"))
return
# 포지션 모니터 (5분 간격 현재가·PnL 갱신)
m = PATTERNS["position_monitor"].search(line)
if m:
symbol = m.group("symbol")
self._set_status(f"{symbol}:current_price", m.group("price"))
self._set_status(f"{symbol}:unrealized_pnl", m.group("pnl"))
self._set_status(f"{symbol}:unrealized_pnl_pct", m.group("pnl_pct"))
return
# 포지션 복구 (재시작 시)
m = PATTERNS["position_recover"].search(line)
if m: