import './SymbolCard.css'; import { PriceChart } from './PriceChart'; import { Badge, ProductStatusBadge } from './ui/Primitives'; interface SymbolCardProps { symbol: string; data: { price: number; change24h: number; changeToday: number; session: string; volatility: string; signal: string; signalTime?: number; tradingMode?: 'Paper' | 'Live' | 'Alerts'; activePosition?: { side: 'BUY' | 'SELL'; entryPrice: number; size: number; stopLoss: number; takeProfit: number; unrealizedPnl?: number; unrealizedPnlPercent?: number; marketValue?: number; } | null; priceHistory: Array<{ timestamp: number; price: number }>; rules: { [ruleName: string]: { passed: boolean; reason: string; isPending?: boolean; isSkipped?: boolean; metadata?: any; }; }; profileSignals?: { [profileId: string]: { profileName?: string; signal: string; passed: boolean; reason?: string; execution?: { status: 'EXECUTED' | 'BLOCKED' | 'SKIPPED'; code: string; reason: string; orderId?: string; }; rules?: { [ruleName: string]: { passed: boolean; reason: string; metadata?: any; }; }; }; }; indicators: { ema20_1h?: number; ema20_15m?: number; ema50_4h?: number; ema200_4h?: number; rsi_1h?: number; rsi_15m?: number; }; }; } const ruleDisplayNames: { [key: string]: string } = { 'TrendBiasRule': 'Trend', 'SessionRule': 'Session', 'ZoneRule': 'Zone', 'MomentumRule': 'Momentum', 'EntryTriggerRule': 'Entry', 'AIAnalysisRule': 'AI', 'RiskManagementRule': 'Risk' }; export const SymbolCard = ({ symbol, data }: SymbolCardProps) => { const profileSignalEntries = Object.entries(data.profileSignals || {}); return (

{symbol}

{data.tradingMode} {data.session} {data.volatility} Vol
${data.price.toLocaleString()}
= 0 ? 'up' : 'down'}`}> Today: {data.changeToday >= 0 ? '+' : ''}{data.changeToday.toFixed(2)}%
= 0 ? 'up' : 'down'}`}> 24h: {data.change24h >= 0 ? '+' : ''}{data.change24h.toFixed(2)}%
{data.signal || 'NONE'} {data.signalTime && ( {Math.floor((Date.now() - data.signalTime) / 60000)}m ago )}
{profileSignalEntries.length > 0 && (

Profile Signals

{profileSignalEntries.map(([profileId, profileSignal]) => { const executionState = profileSignal.execution?.status; const executionClass = executionState === 'EXECUTED' ? 'executed' : executionState === 'BLOCKED' ? 'blocked' : 'skipped'; return (
{(profileSignal.profileName || profileId).slice(0, 18)} {profileSignal.signal} {profileSignal.execution && (
{profileSignal.execution.status} {profileSignal.execution.code}
{profileSignal.execution.reason}
)}
); })}
)} {data.activePosition && (
ACTIVE {data.activePosition.side} {data.activePosition.size.toFixed(4)} Units
Entry ${data.activePosition.entryPrice.toLocaleString()}
= 0 ? 'up' : 'down'}`}> P/L ($) {data.activePosition.unrealizedPnl! >= 0 ? '+' : ''} {data.activePosition.unrealizedPnl!.toFixed(2)}
= 0 ? 'up' : 'down'}`}> Return {data.activePosition.unrealizedPnlPercent! >= 0 ? '+' : ''} {data.activePosition.unrealizedPnlPercent!.toFixed(2)}%
Value ${data.activePosition.marketValue?.toLocaleString()}
SL ${data.activePosition.stopLoss.toLocaleString()}
TP ${data.activePosition.takeProfit.toLocaleString()}
)}

Rules

{Object.entries(data.rules).map(([ruleName, ruleData]) => { const isAI = ruleName === 'AIAnalysisRule'; const aiData = isAI ? ruleData.metadata : null; return (
{ruleData.isSkipped ? '➖' : (ruleData.isPending ? '⏳' : (ruleData.passed ? '✓' : '✗'))} {ruleDisplayNames[ruleName] || ruleName} {isAI && aiData && (
{aiData.confidence !== undefined && (
Confidence: {aiData.confidence}%
)} {aiData.reasoning && (
{aiData.reasoning}
)}
)}
); })}

Indicators

{data.indicators.rsi_15m !== undefined && (
RSI 15m: {data.indicators.rsi_15m.toFixed(1)}
)} {data.indicators.rsi_1h !== undefined && (
RSI 1h: {data.indicators.rsi_1h.toFixed(1)}
)} {data.indicators.ema20_15m !== undefined && (
EMA20 15m: ${data.indicators.ema20_15m.toLocaleString()}
)} {data.indicators.ema20_1h !== undefined && (
EMA20 1h: ${data.indicators.ema20_1h.toLocaleString()}
)}
); };