/** * PredictionCard Component * Displays ML prediction signal details in a card format */ import React from 'react'; import { ArrowTrendingUpIcon, ArrowTrendingDownIcon, ShieldCheckIcon, ClockIcon, ChartBarIcon, BoltIcon, } from '@heroicons/react/24/solid'; import type { MLSignal } from '../../../services/mlService'; import { AMDPhaseIndicator } from './AMDPhaseIndicator'; interface PredictionCardProps { signal: MLSignal; onExecuteTrade?: (signal: MLSignal) => void; showExecuteButton?: boolean; className?: string; } export const PredictionCard: React.FC = ({ signal, onExecuteTrade, showExecuteButton = true, className = '', }) => { // Calculate signal age const getSignalAge = () => { const created = new Date(signal.created_at); const now = new Date(); const diffMs = now.getTime() - created.getTime(); const diffMins = Math.floor(diffMs / 60000); if (diffMins < 60) return `${diffMins}m ago`; const diffHours = Math.floor(diffMins / 60); if (diffHours < 24) return `${diffHours}h ago`; const diffDays = Math.floor(diffHours / 24); return `${diffDays}d ago`; }; // Check if signal is still valid const isValid = new Date(signal.valid_until) > new Date(); // Calculate potential profit/loss percentages const calculatePnLPercentages = () => { const entryPrice = signal.entry_price; const profitPercent = ((signal.take_profit - entryPrice) / entryPrice) * 100; const lossPercent = ((entryPrice - signal.stop_loss) / entryPrice) * 100; return { profit: Math.abs(profitPercent), loss: Math.abs(lossPercent), }; }; const pnl = calculatePnLPercentages(); // Get confidence color const getConfidenceColor = (confidence: number) => { if (confidence >= 0.7) return 'text-green-400'; if (confidence >= 0.5) return 'text-yellow-400'; return 'text-red-400'; }; return (
{/* Header */}
{signal.direction === 'long' ? ( ) : ( )}

{signal.symbol}

{getSignalAge()}

{/* Direction and Confidence Badge */}
{signal.direction.toUpperCase()}
{Math.round(signal.confidence_score * 100)}%
{/* AMD Phase Indicator (compact) */}
{/* Price Levels */}

Entry

${signal.entry_price.toFixed(2)}

Stop Loss

${signal.stop_loss.toFixed(2)}

-{pnl.loss.toFixed(1)}%

Take Profit

${signal.take_profit.toFixed(2)}

+{pnl.profit.toFixed(1)}%

{/* Metrics Row */}

R:R

{signal.risk_reward_ratio.toFixed(1)}

P(TP)

{Math.round(signal.prob_tp_first * 100)}%

Vol

{signal.volatility_regime.substring(0, 3)}

{/* Valid Until */}

{isValid ? 'Valid until' : 'Expired at'}

{new Date(signal.valid_until).toLocaleString()}

{!isValid && ( EXPIRED )}
{/* Execute Trade Button */} {showExecuteButton && isValid && onExecuteTrade && ( )}
); }; export default PredictionCard;