"use client";
import { useQuery } from "@tanstack/react-query";
import Link from "next/link";
import { useRiskStatus, useSystemStatus } from "@/components/shell";
import { Badge, Card, Dot, Empty, ErrorBox, KV, PageHeader, Spinner, Table, Td, Th, Tile } from "@/components/ui";
import { api } from "@/lib/api";
import { fmtAge, fmtBps, fmtNum, fmtPct, fmtPctPlain, fmtPrice, fmtUsd, signClass } from "@/lib/format";
import type { OverviewSymbol, RunRow } from "@/lib/types";
export default function OverviewPage() {
const sys = useSystemStatus();
const risk = useRiskStatus();
const ov = useQuery({ queryKey: ["overview"], queryFn: () => api<{ symbols: OverviewSymbol[] }>("/api/market/overview"), refetchInterval: 5_000 });
const runs = useQuery({ queryKey: ["runs", 5], queryFn: () => api<{ items: RunRow[] }>("/api/backtests?limit=5"), refetchInterval: 10_000 });
const s = sys.data;
return (
<>
{s?.mode ?? "…"}} sub={s?.live_trading_enabled ? "live flag ON" : "live flag off"} tone={s?.mode === "live" ? "down" : "muted"} />
{ov.isLoading && }
{ov.error && }
{ov.data && (
| Symbol | Last | 24h | Bid / Ask | Spread | 24h volume | RV 7d (ann.) | 1h bars | Data |
{ov.data.symbols.map((r) => (
| {r.symbol} |
{fmtPrice(r.last)} |
{fmtPct(r.change_pct, 2, true)} |
{fmtPrice(r.bid)} / {fmtPrice(r.ask)} |
{fmtBps(r.spread_bps, 2)} |
{fmtNum(r.volume, 0)} |
{fmtPctPlain(r.rv_7d_annualized)} |
{r.hourly_bars} |
{r.stale ? stale {fmtAge(r.age_s)} : live {fmtAge(r.age_s)}} |
))}
)}
{sys.isLoading && }
{sys.error && }
{s && (
{s.kraken.status}{s.kraken.error ? ` — ${s.kraken.error}` : ""}],
["REST round-trip", s.kraken.rtt_ms != null ? `${s.kraken.rtt_ms} ms` : "—"],
["Clock drift", s.kraken.clock_drift_s != null ? `${s.kraken.clock_drift_s.toFixed(2)} s` : "—"],
["WebSocket", s.stream ? {s.stream.connected ? "connected" : "disconnected"} · {s.stream.messages.toLocaleString()} msgs · {s.stream.reconnects} reconnects · {s.stream.checksum_failures} checksum fails : "worker not reporting"],
["Last message", s.stream?.last_msg_age != null ? `${s.stream.last_msg_age}s ago` : "—"],
["Data key", s.credentials.data_key ? "configured" : "not configured"],
["Trade key", s.credentials.trade_key ? "configured" : "not configured"],
]} />
)}
Backtests run on demand from the Strategy Lab; there is no scheduled execution yet.
{risk.data && (
)}
Open Risk Center →
All runs →}>
{runs.data?.items.length ? (
| Status | Strategy | Symbol | Interval | Sharpe | Return | Max DD |
{runs.data.items.map((r) => (
|
{r.strategy} | {r.symbol} | {r.interval_min}m |
{fmtNum(r.sharpe)} | {fmtPct(r.total_return)} | {fmtPct(r.max_drawdown)} |
))}
) : Launch one from the Strategy Lab.}
>
);
}
export function StatusBadge({ status }: { status: string }) {
const tone = status === "done" ? "up" : status === "failed" ? "down" : status === "running" ? "accent" : "muted";
return {status};
}