feat: 자산웹 실시간 시세·평가손익 (키움 WebSocket)

- realtime_hub.py: 키움 WS 허브(0B 체결가·1h VI), behive_web 데몬 스레드 + 메모리 상태
- /api/realtime/quotes 엔드포인트 (허브 메모리만, 키움 호출 0)
- 보유행 현재가·평가손익·평가금액·등락률(NXT종가 기준)·비중 실시간
- KPI 총평가금액·총평가손익·순자산·당일평가손익 실시간 (owner 탭 합계→자산정보 탭 카드 연동)
- fill_watcher 체결 시 fill_signal 기록 → 자산웹 패널 자동 새로고침(수량·예수금·당일정산)
- 감시종목 탭 자동갱신 카운트다운 활성화
- 안전: kill-switch BEHIVE_REALTIME=0, 허브 콜드/실패 시 REST 폴백, 매매 경로 무관

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
hyowons
2026-06-08 14:30:19 +09:00
parent 020ac27bd0
commit 925014dfd8
3 changed files with 608 additions and 18 deletions
@@ -61,6 +61,17 @@ _STATE_DIR = _WORKSPACE_ROOT / 'state'
QUEUE_FILE = _STATE_DIR / 'fill_pending.jsonl'
QUEUE_LOCK = _STATE_DIR / 'fill_pending.jsonl.lock'
PID_FILE = _STATE_DIR / 'fill_watcher.pid'
# 체결 발생 신호 파일 — behive_web(별도 프로세스)이 /api/realtime/quotes 응답에 값을 실어주고,
# 브라우저가 값 변화 감지 시 자산웹 패널을 자동 새로고침(수량·예수금·당일정산 반영). file 기반 IPC.
FILL_SIGNAL_FILE = _STATE_DIR / 'fill_signal'
def _bump_fill_signal() -> None:
"""체결(전량/부분) 시 신호파일 갱신 → behive_web 패널 자동 새로고침 트리거. 실패 무시."""
try:
FILL_SIGNAL_FILE.write_text(str(time.time()), encoding='utf-8')
except Exception:
pass
# ---------- Tracked entry ----------
@@ -330,6 +341,7 @@ class _FillWatcher:
cntr_qty, cntr_uv, t.ord_no))
# 전량 체결 → 자산웹 거래내역 즉시 갱신 (별도 스레드, 추적 블로킹 X)
_spawn_journal_collect()
_bump_fill_signal() # 자산웹 패널 자동 새로고침(수량·예수금·당일정산)
else:
ledger.append('partial', {'card_id': t.card_id, 'ord_no': t.ord_no,
'account': t.account, 'symbol': t.symbol,
@@ -337,6 +349,7 @@ class _FillWatcher:
'price': cntr_uv, 'new_fill': new_fill})
self._send(card.format_partial(t.card_id, t.side, t.symbol_name,
cntr_qty, t.order_qty, cntr_uv, t.ord_no))
_bump_fill_signal() # 부분체결도 수량·예수금 변동 → 패널 새로고침
def _handle_timeout(self, t: Tracked) -> None:
with self._lock: