diff --git a/scripts/ui-drift-audit.sh b/scripts/ui-drift-audit.sh index 35fa680..beb87a2 100755 --- a/scripts/ui-drift-audit.sh +++ b/scripts/ui-drift-audit.sh @@ -23,7 +23,7 @@ excluded_parts = {"test", "assets"} patterns = [ ("raw interactive controls outside approved primitives", "Raw Interactive Controls", re.compile(r"<(button|input|textarea|select)(\s|>)"), True), - ("legacy global surface classes", "Legacy Global Surface Classes", re.compile(r"\b(surface-card|surface-muted|badge|input-shell)\b"), False), + ("legacy global surface classes", "Legacy Global Surface Classes", re.compile(r"(?; +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; @@ -57,61 +58,58 @@ interface SymbolCardProps { 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' -}; - + 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 signalColor = data.signal === 'BUY' ? '#00ff88' : data.signal === 'SELL' ? '#ff3366' : '#888'; 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'} + + 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 - + )}
@@ -120,13 +118,6 @@ export const SymbolCard = ({ symbol, data }: SymbolCardProps) => {

Profile Signals

{profileSignalEntries.map(([profileId, profileSignal]) => { - const badgeClass = profileSignal.signal === 'BUY' - ? 'passed' - : profileSignal.signal === 'SELL' - ? 'failed' - : profileSignal.signal === 'MIXED' - ? 'pending' - : 'skipped'; const executionState = profileSignal.execution?.status; const executionClass = executionState === 'EXECUTED' ? 'executed' @@ -135,12 +126,16 @@ export const SymbolCard = ({ symbol, data }: SymbolCardProps) => { : 'skipped'; return (
-
+ {(profileSignal.profileName || profileId).slice(0, 18)} {profileSignal.signal} -
+ {profileSignal.execution && (
@@ -156,113 +151,114 @@ export const SymbolCard = ({ symbol, data }: SymbolCardProps) => {
)} - - {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()} -
- )} -
-
-
- ); -}; + + {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()} +
+ )} +
+
+
+ ); +};