diff --git a/dashboard/server.py b/dashboard/server.py
index 82b8785..9f076e9 100644
--- a/dashboard/server.py
+++ b/dashboard/server.py
@@ -32,6 +32,7 @@ import uvicorn
# ═══════════════════════════════════════════════════════════
METRICS_FILE = "/tmp/ftdt-metrics.json"
+PAPER_METRICS_FILE = "/tmp/ftdt-paper-metrics.json"
BACKTEST_DIR = "/home/debian/ftdt-quant-lab/backtests/results"
STATIC_DIR = Path(__file__).parent / "static"
@@ -44,6 +45,7 @@ os.makedirs(BACKTEST_DIR, exist_ok=True)
app = FastAPI(title="FTDT Quant Lab Dashboard")
connected_clients: set[WebSocket] = set()
+paper_clients: set[WebSocket] = set()
loop: Optional[asyncio.AbstractEventLoop] = None
@@ -76,6 +78,17 @@ def _empty_metrics() -> dict:
}
+def read_paper_metrics() -> dict:
+ """Read paper trading metrics file."""
+ try:
+ if os.path.exists(PAPER_METRICS_FILE):
+ with open(PAPER_METRICS_FILE) as f:
+ return json.load(f)
+ except (json.JSONDecodeError, IOError):
+ pass
+ return {"status": "waiting", "mode": "paper", "strategies": {}, "trades": [], "equity_history": [], "total_pnl": 0, "total_equity": 5000}
+
+
# ═══════════════════════════════════════════════════════════
# Background broadcaster
# ═══════════════════════════════════════════════════════════
@@ -93,13 +106,21 @@ def broadcast_loop():
time.sleep(1)
data = read_metrics()
payload = json.dumps(data, default=str)
-
for ws in list(connected_clients):
if loop:
asyncio.run_coroutine_threadsafe(
broadcast_to_client(ws, payload), loop
)
+ # Also broadcast paper metrics
+ paper_data = read_paper_metrics()
+ paper_payload = json.dumps(paper_data, default=str)
+ for ws in list(paper_clients):
+ if loop:
+ asyncio.run_coroutine_threadsafe(
+ broadcast_to_client(ws, paper_payload), loop
+ )
+
# ═══════════════════════════════════════════════════════════
# WebSocket
@@ -119,6 +140,19 @@ async def websocket_endpoint(websocket: WebSocket):
connected_clients.discard(websocket)
+@app.websocket("/ws/paper")
+async def paper_websocket_endpoint(websocket: WebSocket):
+ await websocket.accept()
+ paper_clients.add(websocket)
+ try:
+ data = read_paper_metrics()
+ await websocket.send_text(json.dumps(data, default=str))
+ while True:
+ await asyncio.sleep(30)
+ except WebSocketDisconnect:
+ paper_clients.discard(websocket)
+
+
# ═══════════════════════════════════════════════════════════
# Backtest endpoints
# ═══════════════════════════════════════════════════════════
diff --git a/dashboard/static/index.html b/dashboard/static/index.html
index 5169029..f3d17d1 100644
--- a/dashboard/static/index.html
+++ b/dashboard/static/index.html
@@ -7,217 +7,205 @@
-
-
FTDT Quant Lab
connecting… · —
-
-
-
+
+
FTDT Quant Lab
connecting… · —
+
+
+
+
+
+
+
-
-
-
-
Equity Curve real-time · all strategies
-
-
-
+
+
+
+
Equity Curve real-time · Hyperliquid Testnet
+
+
+
-
-
-
-
Saved Backtests click to view
-
-
+
+
+
+
Equity Curve real-time · Hyperliquid Mainnet (simulated fills)
+
+
+
+
+
+
+
+
Saved Backtests click to view
+
+