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:
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user