feat: live monitoring dashboard — Bloomberg-terminal UI for all advanced modules

live/monitor_service.py (LiveMonitorService):
  Background service running all 6 advanced monitors plus microstructure.
  Polls Hyperliquid REST API every 4s for prices, books, funding.
  Exposes unified state() method for the live dashboard API.

dashboard/server.py:
  Added /api/monitors/status?coin=BTC — combined state of all monitors
  Added /api/monitors/hlp — HLP vault state
  Added /api/monitors/funding — funding whipsaw signal
  Added /api/monitors/spoof — spoof detector summary
  Added /live route serving the live dashboard
  Monitor service auto-starts on first API request

dashboard/static/live.html:
  Professional dark-themed live monitoring dashboard.
  Three-column grid layout with real-time polling:
  - Price panel: mid, mark, oracle, premium, spread, funding
  - Microstructure panel: OBI, VPIN/toxicity bar, bid/ask depths
  - Composite signal panel: HLP signal, funding whipsaw signal,
    term structure signal, spoof probability bar, branching ratio
  - HLP Vault panel: total delta, assets tracked, toxicity %,
    overextended assets, per-coin rebalancing signals
  - Bottom row: Spoof Detector, Liquidation Waterfall,
    Term Structure
  - Coin selector (BTC/ETH) with color-coded signal rows
  - Auto-refreshes every 3s with live indicator

Access: http://localhost:9175/live
This commit is contained in:
ramseshk
2026-08-07 18:00:48 +08:00
parent 5304534e38
commit 27c096dc9e
3 changed files with 532 additions and 0 deletions
+61
View File
@@ -214,6 +214,67 @@ async def get_metrics_v2():
pass
return JSONResponse({"status": "no_data"})
# ═══════════════════════════════════════════════════════════
# Live monitor service & API
# ═══════════════════════════════════════════════════════════
_monitor_service = None
def _get_or_start_monitor():
global _monitor_service
if _monitor_service is None or not _monitor_service._running:
try:
from live.monitor_service import LiveMonitorService
_monitor_service = LiveMonitorService(coins=["BTC", "ETH"], testnet=True, poll_interval=4.0)
_monitor_service.start()
except Exception:
return None
return _monitor_service
@app.get("/api/monitors/status")
async def get_monitors_status(coin: str = "BTC"):
"""Full state of all live microstructure monitors."""
svc = _get_or_start_monitor()
if svc is None:
return JSONResponse({"error": "monitor_service_unavailable"}, status_code=503)
return JSONResponse(svc.state(coin))
@app.get("/api/monitors/hlp")
async def get_hlp_status():
"""HLP vault summary only."""
svc = _get_or_start_monitor()
if svc is None:
return JSONResponse({"error": "unavailable"}, status_code=503)
return JSONResponse(svc._hlp.summary())
@app.get("/api/monitors/funding")
async def get_funding_status():
"""Funding whipsaw signal."""
svc = _get_or_start_monitor()
if svc is None:
return JSONResponse({"error": "unavailable"}, status_code=503)
return JSONResponse(svc._funding_whipsaw.signal() if svc._funding_whipsaw._mark_px > 0 else {"action": "no_data"})
@app.get("/api/monitors/spoof")
async def get_spoof_status():
"""Spoof detector summary."""
svc = _get_or_start_monitor()
if svc is None:
return JSONResponse({"error": "unavailable"}, status_code=503)
return JSONResponse(svc._spoof_detector.summary())
@app.get("/live")
async def live_dashboard():
return FileResponse(STATIC_DIR / "live.html")
@app.get("/api/metrics/paper")
async def get_paper_metrics_rest():
return JSONResponse(read_paper_metrics())