Current drawdown
{s.drawdown}%
/ {maxDD}% kill
Daily loss budget
= dailyMax * 0.7 ? "var(--warn)" : "var(--text)", fontWeight: 600 }}>−{dailyUsed.toFixed(2)}%
/ −{dailyMax}% cap
= dailyMax * 0.7 ? "linear-gradient(90deg, var(--warn), var(--loss))" : "linear-gradient(90deg, var(--profit), var(--accent))",
borderRadius: 999, transition: "width .5s",
}} />
resets 00:00 UTC · in 11h 42m
);
}
function Metric({ label, value, hint }) {
return (
{label}
{value}
{hint &&
{hint}
}
);
}
// =================== /health endpoint preview ===================
function HealthEndpointCard({ activeExchange = "binance", scenario, mode = "testnet" }) {
const ex = EXCHANGES[activeExchange] || EXCHANGES.binance;
const s = SCENARIOS[scenario] || SCENARIOS.winning;
return (
200 OK}>
{"{\n"}
{" "}"status" : "ok" ,{"\n"}
{" "}"uptime_seconds" : 184302 ,{"\n"}
{" "}"active_exchange" : "{ex.id}" ,{"\n"}
{" "}"exchange_connected" : true ,{"\n"}
{" "}"last_signal_time" : "2026-05-15T08:14:32Z" ,{"\n"}
{" "}"open_positions" : 1 ,{"\n"}
{" "}"daily_pnl_pct" : = 0 ? "var(--profit)" : "var(--loss)" }}>{s.changePct.toFixed(2)} ,{"\n"}
{" "}"trading_mode" : "{mode}" {"\n"}
{"}"}
} style={{ flex: 1, justifyContent: "center" }}>Copy curl
} style={{ flex: 1, justifyContent: "center" }}>Probe now
);
}
// =================== Exchange comparison + picker ===================
function ExchangeComparisonCard({ activeExchange = "binance", onSelect }) {
const rows = [
["CCXT id", (ex) =>
{ex.ccxtId} ],
["Native symbol", (ex) =>
{ex.nativeSymbol} ],
["Maker / Taker", (ex) =>
{ex.fees.maker.toFixed(2)}% / {ex.fees.taker.toFixed(2)}% ],
["Rate limit", (ex) =>
{ex.rateLimit} ],
["Stop loss", (ex) =>
{ex.stopLoss}],
["Testnet", (ex) => ex.testnet ?
● available :
paper-trade only ],
["Round-trip", (ex) =>
{ex.rttMs}ms ],
];
return (
{["binance", "kraken"].map((k) => {
const ex = EXCHANGES[k];
const isActive = k === activeExchange;
return (
onSelect && onSelect(k)} className="focus-ring"
style={{
padding: "12px 14px", border: 0, textAlign: "left",
background: isActive ? "var(--accent-soft)" : "rgba(255,255,255,0.02)",
borderRight: k === "binance" ? "1px solid var(--line)" : 0,
borderBottom: "1px solid var(--line)",
color: "var(--text)", cursor: "pointer",
display: "flex", alignItems: "center", gap: 10,
}}>
{isActive
? ● ACTIVE
: switch → }
);
})}
{rows.map(([label, render], i) => (
{label}
{["binance", "kraken"].map((k) => {
const ex = EXCHANGES[k];
const isActive = k === activeExchange;
return (
{render(ex)}
);
})}
))}
);
}
// =================== System health card ===================
function SystemHealthCard({ activeExchange = "binance" }) {
const ex = EXCHANGES[activeExchange] || EXCHANGES.binance;
const services = [
{ name: "FastAPI", status: "ok", val: "200 OK", sub: "8000/health · 12ms" },
{ name: ex.name + " API", status: "ok", val: "Connected", sub: "spot · " + (ex.testnet ? "testnet" : "paper") + " · ccxt:" + ex.ccxtId },
{ name: "TradingView", status: "ok", val: "Listening", sub: "/webhook · 10/min limit" },
{ name: "Telegram", status: "ok", val: "Bot active", sub: "@AutoTraderBot" },
{ name: "SQLite", status: "ok", val: "WAL mode", sub: "trades.db · 1.4 MB" },
];
return (
{services.map((s) => (
))}
);
}
// =================== Dashboard page composition ===================
function DashboardPage({ scenario, accent, livePrices, activeExchange = "binance", setActiveExchange, mode = "testnet" }) {
const s = SCENARIOS[scenario] || SCENARIOS.winning;
const ex = EXCHANGES[activeExchange] || EXCHANGES.binance;
const isUp = s.change24h >= 0;
const [equity, dir] = livePrices
? useTicker(s.equity, { volatility: 0.0004, intervalMs: 2000, bias: isUp ? 0.0002 : -0.0002 })
: [s.equity, 0];
const animEquity = useCountUp(equity, 600);
const modeTone = mode === "live" ? "loss" : mode === "paper" ? "accent" : "warn";
return (
{/* KPI strip */}
}
/>
} />
} />
} />
} />
{/* Open position */}
{/* Equity + side col */}
{/* Daily PnL bars + signal feed */}
{/* Exchange routing + health endpoint (new in v3) */}
{/* Bot config + system health */}
setActiveExchange && setActiveExchange(activeExchange === "binance" ? "kraken" : "binance")} />
);
}
Object.assign(window, {
DashboardPage, Kpi, OpenPositionCard, EquityAndDailyCard, DailyPnLCard,
SignalFeedCard, BotConfigCard, RiskOverviewCard, SystemHealthCard, Metric,
HealthEndpointCard, ExchangeComparisonCard,
});