import React, { useState } from 'react' import { FlaskConical, TrendingUp, TrendingDown, Minus, CheckCircle, XCircle, Loader2 } from 'lucide-react' import { BacktestResult, BacktestTrade } from '../api/stockApi' interface BacktestPanelProps { stockNo: string onRun: (months: number) => Promise result: BacktestResult | null loading: boolean error: string | null currency?: string } const StatCard: React.FC<{ label: string value: string sub?: string color?: string }> = ({ label, value, sub, color = 'text-white' }) => (

{label}

{value}

{sub &&

{sub}

}
) const SignalBadge: React.FC<{ signal: string }> = ({ signal }) => { const styles: Record = { BUY: 'bg-green-900/50 text-green-400', SELL: 'bg-red-900/50 text-red-400', HOLD: 'bg-slate-700 text-slate-400', } return ( {signal} ) } export const BacktestPanel: React.FC = ({ stockNo, onRun, result, loading, error, currency = 'NT$' }) => { const [months, setMonths] = useState(12) const [showAll, setShowAll] = useState(false) const s = result?.stats const trades = result?.trades ?? [] const displayed = showAll ? trades : trades.slice(-30).reverse() return (
{/* Header */}

歷史回測

Walk-Forward(滾動訓練,無未來偷看)
{error && (
{error}
)} {loading && (
正在套用模型到歷史資料...
)} {s && !loading && ( <> {/* Stats cards */}
= 50 ? 'text-green-400' : 'text-red-400'} /> = 50 ? 'text-green-400' : 'text-red-400'} /> 0 ? '+' : ''}${s.avg_return_on_buy}%`} sub="每次買入信號後5日" color={s.avg_return_on_buy >= 0 ? 'text-green-400' : 'text-red-400'} /> 0 ? '+' : ''}${s.total_return_if_followed}%`} sub={`${result?.months}個月 · ${s.total_days} 交易日`} color={s.total_return_if_followed >= 0 ? 'text-green-400' : 'text-red-400'} />
{/* Signal distribution */}
信號分布: BUY {s.buy_signals} SELL {s.sell_signals} HOLD {s.hold_signals}
{/* Trade history table */} {trades.length > 0 && (

交易紀錄(最近 {displayed.length} 筆)

{displayed.map((t: BacktestTrade) => ( ))}
日期 信號 入場價 5日後 漲跌 結果
{t.date} {t.close.toFixed(2)} {t.future_close.toFixed(2)} 0 ? 'text-green-400' : t.actual_return_pct < 0 ? 'text-red-400' : 'text-slate-400' }`}> {t.actual_return_pct > 0 ? '+' : ''}{t.actual_return_pct.toFixed(2)}% {t.signal === 'HOLD' ? ( ) : t.correct ? ( ) : ( )}
)} )}
) }