refactor(ui): tokenize trade profile metrics
This commit is contained in:
parent
c935f15943
commit
931a3cde1d
@ -80,13 +80,13 @@ export interface ProfileTradeStats {
|
||||
|
||||
// --- CONSTANTS ---
|
||||
const AVAILABLE_RULES = [
|
||||
{ id: 'TrendBiasRule', name: 'Trend Bias', desc: 'EMA50/200 direction check on 4H timeframe', icon: TrendingUp, color: '#3b82f6', defaultParams: { fastPeriod: 50, slowPeriod: 200 } },
|
||||
{ id: 'MomentumRule', name: 'Momentum', desc: 'RSI overbought/oversold confirmation', icon: Activity, color: '#06b6d4', defaultParams: { rsiPeriod: 14, overbought: 70, oversold: 30 } },
|
||||
{ id: 'ZoneRule', name: 'Zone Proximity', desc: 'Price relative to EMA value zones', icon: Target, color: '#a855f7', defaultParams: { zonePercent: 1.5 } },
|
||||
{ id: 'SessionRule', name: 'Session Filter', desc: 'Trade only during major sessions', icon: Clock, color: '#f59e0b', defaultParams: { sessions: 'LDN,NY' } },
|
||||
{ id: 'EntryTriggerRule', name: 'Entry Trigger', desc: 'Pattern-based precise entry logic', icon: Play, color: '#10b981', defaultParams: { showPatterns: true } },
|
||||
{ id: 'RiskManagementRule', name: 'Risk Guard', desc: 'ATR-based stop loss & position sizing', icon: Shield, color: '#ef4444', defaultParams: { maxRisk: 2.0 } },
|
||||
{ id: 'AIAnalysisRule', name: 'AI Sentiment', desc: 'LLM-powered market analysis', icon: Cpu, color: '#8b5cf6', defaultParams: { minConfidence: 70 } }
|
||||
{ id: 'TrendBiasRule', name: 'Trend Bias', desc: 'EMA50/200 direction check on 4H timeframe', icon: TrendingUp, color: 'var(--bl-info-strong)', defaultParams: { fastPeriod: 50, slowPeriod: 200 } },
|
||||
{ id: 'MomentumRule', name: 'Momentum', desc: 'RSI overbought/oversold confirmation', icon: Activity, color: 'var(--bl-attention)', defaultParams: { rsiPeriod: 14, overbought: 70, oversold: 30 } },
|
||||
{ id: 'ZoneRule', name: 'Zone Proximity', desc: 'Price relative to EMA value zones', icon: Target, color: 'var(--bl-emphasis)', defaultParams: { zonePercent: 1.5 } },
|
||||
{ id: 'SessionRule', name: 'Session Filter', desc: 'Trade only during major sessions', icon: Clock, color: 'var(--bl-warning)', defaultParams: { sessions: 'LDN,NY' } },
|
||||
{ id: 'EntryTriggerRule', name: 'Entry Trigger', desc: 'Pattern-based precise entry logic', icon: Play, color: 'var(--bl-success)', defaultParams: { showPatterns: true } },
|
||||
{ id: 'RiskManagementRule', name: 'Risk Guard', desc: 'ATR-based stop loss & position sizing', icon: Shield, color: 'var(--bl-danger)', defaultParams: { maxRisk: 2.0 } },
|
||||
{ id: 'AIAnalysisRule', name: 'AI Sentiment', desc: 'LLM-powered market analysis', icon: Cpu, color: 'var(--bl-emphasis)', defaultParams: { minConfidence: 70 } }
|
||||
];
|
||||
|
||||
const SESSION_PRESET_OPTIONS = [
|
||||
@ -137,6 +137,8 @@ const panelClass = 'rounded-xl border border-[var(--border)] bg-[var(--card-elev
|
||||
const subtlePanelClass = 'rounded-xl border border-[var(--border)] bg-[var(--muted)]/35';
|
||||
const iconButtonClass = 'h-8 w-8 rounded-xl';
|
||||
const accentTextClass = 'text-[var(--accent)]';
|
||||
const statSuccessClass = 'text-emerald-600 dark:text-emerald-400';
|
||||
const statDangerClass = 'text-red-600 dark:text-red-400';
|
||||
|
||||
export const normalizeSessionPresetValue = (raw: unknown): string => {
|
||||
if (raw === undefined || raw === null) return 'LDN,NY';
|
||||
@ -580,10 +582,10 @@ export const TradeProfileManager = ({ botState = DEFAULT_BOT_STATE }: TradeProfi
|
||||
|
||||
{/* Aggregate stats */}
|
||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
|
||||
<StatPill icon={Layers} label="Total Profiles" value={`${activeCount} / ${profiles.length}`} color="#00ff88" />
|
||||
<StatPill icon={DollarSign} label="Total Capital" value={`$${totalCapital.toLocaleString()}`} color="#3b82f6" />
|
||||
<StatPill icon={BarChart3} label="Realized P&L" value={`${totalPnl >= 0 ? '+' : ''}$${totalPnl.toFixed(2)}`} color={totalPnl >= 0 ? '#00ff88' : '#ef4444'} />
|
||||
<StatPill icon={Activity} label="Total Trades" value={`${totalTrades}`} color="#a855f7" />
|
||||
<StatPill icon={Layers} label="Total Profiles" value={`${activeCount} / ${profiles.length}`} color="var(--bl-success)" />
|
||||
<StatPill icon={DollarSign} label="Total Capital" value={`$${totalCapital.toLocaleString()}`} color="var(--bl-info-strong)" />
|
||||
<StatPill icon={BarChart3} label="Realized P&L" value={`${totalPnl >= 0 ? '+' : ''}$${totalPnl.toFixed(2)}`} color={totalPnl >= 0 ? 'var(--bl-success)' : 'var(--bl-danger)'} />
|
||||
<StatPill icon={Activity} label="Total Trades" value={`${totalTrades}`} color="var(--bl-emphasis)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -724,15 +726,15 @@ export const TradeProfileManager = ({ botState = DEFAULT_BOT_STATE }: TradeProfi
|
||||
{/* Stats header row */}
|
||||
<div className="grid grid-cols-3">
|
||||
{[
|
||||
{ icon: DollarSign, label: 'Capital', val: `$${p.allocated_capital.toLocaleString()}`, color: '#3b82f6', valClass: 'text-[var(--foreground)]' },
|
||||
{ icon: BarChart3, label: 'Realized', val: `${stats.totalPnl >= 0 ? '+' : ''}${stats.totalPnl.toFixed(2)}`, color: stats.totalPnl >= 0 ? '#16a34a' : '#dc2626', valClass: stats.totalPnl >= 0 ? 'text-emerald-600 dark:text-emerald-400' : 'text-red-600 dark:text-red-400' },
|
||||
{ icon: AlertTriangle, label: 'Risk', val: `${p.risk_per_trade_percent}%`, color: '#f59e0b', valClass: 'text-[var(--foreground)]' },
|
||||
{ icon: DollarSign, label: 'Capital', val: `$${p.allocated_capital.toLocaleString()}`, color: 'var(--bl-info-strong)', valClass: 'text-[var(--foreground)]' },
|
||||
{ icon: BarChart3, label: 'Realized', val: `${stats.totalPnl >= 0 ? '+' : ''}${stats.totalPnl.toFixed(2)}`, color: stats.totalPnl >= 0 ? 'var(--bl-success)' : 'var(--bl-danger)', valClass: stats.totalPnl >= 0 ? statSuccessClass : statDangerClass },
|
||||
{ icon: AlertTriangle, label: 'Risk', val: `${p.risk_per_trade_percent}%`, color: 'var(--bl-warning)', valClass: 'text-[var(--foreground)]' },
|
||||
].map((item, i) => (
|
||||
<div key={item.label} className={cn('relative px-4 py-4 text-center', i < 2 && 'border-r border-[var(--border)]')}>
|
||||
<div className="relative">
|
||||
<div className="flex items-center justify-center gap-1.5 mb-1.5">
|
||||
<div className="flex h-4 w-4 items-center justify-center rounded" style={{
|
||||
background: `${item.color}15`,
|
||||
background: `color-mix(in oklab, ${item.color} 15%, transparent)`,
|
||||
}}>
|
||||
<item.icon size={9} style={{ color: item.color }} />
|
||||
</div>
|
||||
@ -768,10 +770,10 @@ export const TradeProfileManager = ({ botState = DEFAULT_BOT_STATE }: TradeProfi
|
||||
style={{
|
||||
width: `${Math.max(stats.winRate, 2)}%`,
|
||||
background: stats.winRate >= 50
|
||||
? '#16a34a'
|
||||
? 'var(--bl-success)'
|
||||
: stats.winRate >= 30
|
||||
? '#f59e0b'
|
||||
: '#dc2626',
|
||||
? 'var(--bl-warning)'
|
||||
: 'var(--bl-danger)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@ -1026,11 +1028,11 @@ export const TradeProfileManager = ({ botState = DEFAULT_BOT_STATE }: TradeProfi
|
||||
<div
|
||||
className="w-8 h-8 rounded-lg flex items-center justify-center transition-all"
|
||||
style={{
|
||||
background: active ? `${rule.color}15` : 'rgba(255,255,255,0.02)',
|
||||
border: `1px solid ${active ? `${rule.color}30` : 'rgba(255,255,255,0.04)'}`,
|
||||
background: active ? `color-mix(in oklab, ${rule.color} 15%, transparent)` : 'color-mix(in oklab, var(--foreground) 2%, transparent)',
|
||||
border: `1px solid ${active ? `color-mix(in oklab, ${rule.color} 30%, transparent)` : 'color-mix(in oklab, var(--foreground) 4%, transparent)'}`,
|
||||
}}
|
||||
>
|
||||
<Icon size={14} style={{ color: active ? rule.color : '#52525b' }} />
|
||||
<Icon size={14} style={{ color: active ? rule.color : 'var(--bl-text-faint)' }} />
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center gap-2 mb-0.5">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user