import { useState } from 'react'; import { Link } from '@tanstack/react-router'; import { useTradingConfig, useSetTradingMode, usePendingApprovals, useReviewApproval, useActiveLockouts, useCreateLockout, useDeleteLockout, useMacroStatus, useToggleMacro, useCompetitiveStatus, useToggleCompetitive, useApprovalConfig, useUpdateApprovalConfig, } from '../api/hooks'; import { useResetPaperTrading, useTradingStatus, useUpdateTradingConfig } from '../api/tradingHooks'; import { StatusBadge, LoadingSpinner, Card } from '../components/ui'; export function TradingPage() { const { data: config, isLoading: configLoading } = useTradingConfig(); const { data: approvals } = usePendingApprovals(); const { data: lockouts } = useActiveLockouts(); const { data: macroStatus } = useMacroStatus(); const { data: competitiveStatus } = useCompetitiveStatus(); const setMode = useSetTradingMode(); const resetTrading = useResetPaperTrading(); const { data: tradingStatus } = useTradingStatus(); const updateConfig = useUpdateTradingConfig(); const reviewApproval = useReviewApproval(); const toggleMacro = useToggleMacro(); const toggleCompetitive = useToggleCompetitive(); const { data: approvalConfig } = useApprovalConfig(); const updateApprovalConfig = useUpdateApprovalConfig(); const createLockout = useCreateLockout(); const deleteLockout = useDeleteLockout(); const [lockoutTicker, setLockoutTicker] = useState(''); const [lockoutReason, setLockoutReason] = useState(''); const [lockoutDuration, setLockoutDuration] = useState(60); // Normalize API field names (API returns macro_enabled/competitive_enabled, not enabled) const macroEnabled = macroStatus?.enabled ?? macroStatus?.macro_enabled ?? false; const competitiveEnabled = competitiveStatus?.enabled ?? competitiveStatus?.competitive_enabled ?? false; const autoApprovePaper = approvalConfig?.auto_approve_paper ?? true; const [confirmMode, setConfirmMode] = useState(null); const [confirmMacroToggle, setConfirmMacroToggle] = useState(false); const [confirmCompetitiveToggle, setConfirmCompetitiveToggle] = useState(false); const [confirmApprovalToggle, setConfirmApprovalToggle] = useState(false); if (configLoading) return ; const currentMode = config?.trading_mode ?? 'paper'; return (

Trading Controls

{/* Trading Mode */}

Trading Mode

{['paper', 'live', 'disabled'].map((mode) => ( ))} Override Trade
{/* Confirmation dialog for live mode */} {confirmMode && (

Are you sure you want to switch to {confirmMode} mode? This enables real order execution.

)}
{/* Paper Trading Reset */} resetTrading.mutate(0)} isResetting={resetTrading.isPending} /> {/* Risk Tier */}

Risk Tier

Controls confidence gates, position sizing, and portfolio heat limits for the trading engine.

{(['conservative', 'moderate', 'aggressive'] as const).map((tier) => { const currentTier = tradingStatus?.risk_tier ?? 'moderate'; const descriptions: Record = { conservative: 'Min confidence 0.75, max 5% position, 10% heat', moderate: 'Min confidence 0.55, max 10% position, 20% heat', aggressive: 'Min confidence 0.40, max 15% position, 30% heat', }; return ( ); })}
{/* Macro Signal Layer Toggle */}

Macro Signal Layer

{macroEnabled ? 'Enabled' : 'Disabled'} {macroStatus?.toggled_at && ( Last changed: {new Date(macroStatus.toggled_at).toLocaleString()} {macroStatus.toggled_by && ` by ${macroStatus.toggled_by}`} )}
{/* Confirmation dialog for macro toggle */} {confirmMacroToggle && (

Are you sure you want to {macroEnabled ? 'disable' : 'enable'} the macro signal layer? {macroEnabled ? ' Disabling will exclude macro signals from trend summaries and recommendations.' : ' Enabling will include global event macro signals in trend summaries and recommendations.'}

)}
{/* Competitive Signal Layer Toggle */}

Competitive Signal Layer

{competitiveEnabled ? 'Enabled' : 'Disabled'} {competitiveStatus?.toggled_at && ( Last changed: {new Date(competitiveStatus.toggled_at).toLocaleString()} {competitiveStatus.toggled_by && ` by ${competitiveStatus.toggled_by}`} )}
{/* Confirmation dialog for competitive toggle */} {confirmCompetitiveToggle && (

Are you sure you want to {competitiveEnabled ? 'disable' : 'enable'} the competitive signal layer? {competitiveEnabled ? ' Disabling will exclude historical pattern and competitive signals from trend summaries and recommendations.' : ' Enabling will include historical pattern and competitive signals in trend summaries and recommendations.'}

)}
{/* Paper Order Approval Toggle */}

Paper Order Approval

{autoApprovePaper ? 'Auto-approve paper orders' : 'Require approval for paper orders'}
{/* Confirmation dialog for approval toggle */} {confirmApprovalToggle && (

Are you sure you want to {autoApprovePaper ? 'require approval for' : 'auto-approve'} paper orders? {autoApprovePaper ? ' Enabling approval requirements will hold all paper orders for manual review before execution.' : ' Disabling approval requirements will allow paper orders to execute automatically.'}

)}
{/* Pending Approvals */}

Pending Approvals ({approvals?.length ?? 0})

{!approvals?.length ? (

No pending approvals

) : (
{approvals.map((a) => ( reviewApproval.mutate({ id: a.id, approved, review_note: note })} /> ))}
)}
{/* Active Lockouts */}

Active Lockouts ({lockouts?.length ?? 0})

{/* Lockout Creation Form */}
{ e.preventDefault(); if (!lockoutTicker.trim()) return; createLockout.mutate( { ticker: lockoutTicker.trim().toUpperCase(), reason: lockoutReason.trim(), duration_minutes: lockoutDuration }, { onSuccess: () => { setLockoutTicker(''); setLockoutReason(''); setLockoutDuration(60); }, }, ); }} >
setLockoutTicker(e.target.value.toUpperCase())} className="w-24 rounded-md border border-surface-700 bg-surface-950 px-2 py-1 text-xs font-mono text-gray-200 uppercase placeholder-gray-600" required />
setLockoutReason(e.target.value)} className="rounded-md border border-surface-700 bg-surface-950 px-2 py-1 text-xs text-gray-200 placeholder-gray-600" required />
setLockoutDuration(Number(e.target.value))} className="w-20 rounded-md border border-surface-700 bg-surface-950 px-2 py-1 text-xs text-gray-200" required />
{!lockouts?.length ? (

No active lockouts

) : (
{lockouts.map((l) => { const expiresIn = l.expires_at ? Math.max(0, Math.round((new Date(l.expires_at).getTime() - Date.now()) / 60000)) : 0; return (
{l.ticker} {l.reason}
{expiresIn > 0 ? `${expiresIn}m remaining` : 'expired'}
); })}
)}
); } function ApprovalRow({ approval, onReview }: { approval: { id: string; ticker: string; side: string; quantity: number; estimated_value: number | null; requested_at: string }; onReview: (approved: boolean, note: string) => void; }) { const [note, setNote] = useState(''); return (
{approval.ticker} qty: {approval.quantity} {approval.estimated_value != null && ( ${approval.estimated_value.toFixed(2)} )}
{new Date(approval.requested_at).toLocaleString()}
setNote(e.target.value)} className="flex-1 rounded-md border border-surface-700 bg-surface-900 px-2 py-1 text-xs text-gray-200 placeholder-gray-500" aria-label="Review note" />
); } function ResetCard({ onReset, isResetting }: { onReset: () => void; isResetting: boolean; }) { const [showConfirm, setShowConfirm] = useState(false); return (

Paper Trading Account

Full Reset

Liquidates all broker positions, cancels open orders, wipes local trading history, and syncs capital from the broker account.

{showConfirm && (

This will permanently delete all positions, orders, trading decisions, stop levels, portfolio snapshots, and backtest data. All broker positions will be liquidated and capital will be set from the broker's account balance.

)}
); }