'use client'; import { useState, useEffect } from 'react'; const GREEN = '#16A34A'; const RED = '#DC2626'; const BLUE = '#2563EB'; const AMBER = '#D97706'; export default function LiveDashboard() { const [data, setData] = useState(null); const [trades, setTrades] = useState([]); const [loading, setLoading] = useState(true); const [toggling, setToggling] = useState(null); const [activeTrade, setActiveTrade] = useState(null); useEffect(() => { const fetchState = async () => { try { const res = await fetch('/api/live-state'); const json = await res.json(); setData(json); setLoading(false); } catch (e) { console.error('State fetch error:', e); } }; fetchState(); const interval = setInterval(fetchState, 2000); return () => clearInterval(interval); }, []); useEffect(() => { const fetchTrades = async () => { try { const res = await fetch('/api/live-trades'); const json = await res.json(); setTrades(json.trades || []); } catch (e) { console.error('Trades fetch error:', e); } }; fetchTrades(); const interval = setInterval(fetchTrades, 10000); return () => clearInterval(interval); }, []); const sendCommand = async (action, strategy = null) => { setToggling(strategy || action); try { await fetch('/api/live-toggle', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action, strategy }) }); } catch (e) { console.error('Command error:', e); } setTimeout(() => setToggling(null), 1500); }; if (loading) { return (
Loading Live Trading...
); } const market = data?.market; const live = data?.live || {}; const strategies = data?.strategies || []; const enabledSet = new Set(live.enabledStrategies || []); return (
{/* Header */}

Kalbot

LIVE
📝 Paper
{data?.lastUpdate ? 'Live' : 'Offline'}
{/* Kill Switch + Balance */}

Kalshi Balance

{live.balance != null ? `$${live.balance.toFixed(2)}` : '—'}

{live.portfolioValue != null && (

Portfolio: ${live.portfolioValue.toFixed(2)}

)}
= 0 ? '+' : ''}$${live.totalPnL?.toFixed(2) || '0.00'}`} color={live.totalPnL >= 0 ? GREEN : RED} dark /> = 50 ? GREEN : RED} dark /> 0 ? AMBER : null} dark />
{live.paused && (
⚠️ TRADING PAUSED — No new orders will be placed
)}
Per-trade cap: ${live.maxPerTrade?.toFixed(2) || '5.00'} Daily limit: ${live.maxDailyLoss?.toFixed(2) || '20.00'}
{/* Market Card */} {/* Strategy Toggles */}

⚡ Strategy Controls

{strategies.map((s, i) => { const isEnabled = enabledSet.has(s.name); const isToggling = toggling === s.name; return (

{s.name}

{s.config && (

${s.config.betSize || 1}/trade • {s.config.cooldownMs ? `${(s.config.cooldownMs/1000).toFixed(0)}s cd` : ''}

)}
); })} {strategies.length === 0 && (

No strategies loaded yet.

)}
{/* Open Orders */} {live.openOrders?.length > 0 && (

Open Orders ({live.openOrders.length})

{live.openOrders.map((o, i) => ( ))}
)} {/* Kalshi Positions */} {live.positions?.length > 0 && (

Kalshi Positions ({live.positions.length})

{live.positions.map((p, i) => (
{p.market_ticker || p.ticker} {p.position_fp || p.position || 0} contracts
{p.realized_pnl_dollars && (

Realized PnL: = 0 ? 'text-green-400' : 'text-red-400'}> ${Number(p.realized_pnl_dollars).toFixed(2)}

)}
))}
)} {/* Trade History */}

Trade History ({trades.length})

{trades.length === 0 ? (

No settled trades yet. Enable a strategy to start.

) : ( trades.map((t, i) => ) )}
{/* Footer */}
Worker: {formatUptime(data?.workerUptime)} {data?.lastUpdate ? new Date(data.lastUpdate).toLocaleTimeString() : 'never'}
); } function MarketCard({ market }) { if (!market) { return (

No active market — waiting...

); } const timeLeft = market.closeTime ? getTimeLeft(market.closeTime) : null; return (

BTC Up or Down

15 min

{timeLeft && ( ⏱ {timeLeft} )}
Up {market.yesPct}%
Down {market.noPct}%
${(market.volume || 0).toLocaleString()} vol {market.ticker}
); } function LiveOrderRow({ order, isOpen }) { const won = order.result && order.side?.toLowerCase() === order.result?.toLowerCase(); const isNeutral = order.result === 'cancelled' || order.result === 'expired'; const rawPnl = order?.pnl != null ? Number(order.pnl) : null; const pnlVal = Number.isFinite(rawPnl) ? (Number.isInteger(rawPnl) ? rawPnl / 100 : rawPnl) : null; const pnlColor = pnlVal == null ? 'text-gray-600' : pnlVal > 0 ? 'text-green-400' : pnlVal < 0 ? 'text-red-400' : 'text-gray-400'; return (
{isOpen ? ( ) : ( {isNeutral ? '➖' : won ? '✅' : '❌'} )} {order.side} @ {order.priceCents || order.price}¢ {order.contracts || 1}x
{pnlVal != null ? `${pnlVal >= 0 ? '+' : ''}$${pnlVal.toFixed(2)}` : 'open'}
{order.reason} {order.strategy}
{order.result && !isOpen && (
Result: {order.result} {order.settleTime ? new Date(order.settleTime).toLocaleTimeString() : order.createdAt ? new Date(order.createdAt).toLocaleTimeString() : ''}
)}
); } function StatBox({ label, value, color, dark }) { return (

{label}

{value}

); } function getTimeLeft(closeTime) { const diff = new Date(closeTime).getTime() - Date.now(); if (diff <= 0) return 'Closing...'; const mins = Math.floor(diff / 60000); const secs = Math.floor((diff % 60000) / 1000); return `${mins}:${secs.toString().padStart(2, '0')}`; } function formatUptime(seconds) { if (!seconds) return '0s'; const h = Math.floor(seconds / 3600); const m = Math.floor((seconds % 3600) / 60); const s = Math.floor(seconds % 60); if (h > 0) return `${h}h ${m}m`; if (m > 0) return `${m}m ${s}s`; return `${s}s`; }