// frontend/src/components/WalkForwardPanel.tsx import React, { useState } from 'react'; import { API_BASE } from '../config'; interface WalkForwardPanelProps { activeTicker: string; } interface OOSResult { window: number; train_period: string; test_period: string; best_params: { strategy_mode: string; trailing_stop_atr_mult: number; rsi_threshold_buy: number; stop_loss_pct: number; profit_target_pct: number; }; is_sharpe: number; oos_sharpe: number; net_pnl: number; max_drawdown: number; round_trips: number; win_rate: number; commission: number; } interface WFResult { success: boolean; ticker: string; interval: string; period: string; oos_results: OOSResult[]; correlation: number; is_overfitted: boolean; static_control: { net_pnl: number; pnl_pct: number; round_trips: number; commission: number; max_drawdown: number; sharpe: number; }; summary: { total_wf_pnl: number; total_wf_commission: number; avg_wf_drawdown: number; total_wf_trades: number; avg_is_sharpe: number; avg_oos_sharpe: number; }; } export const WalkForwardPanel: React.FC = ({ activeTicker }) => { const [ticker, setTicker] = useState(activeTicker.toUpperCase()); const [interval, setIntervalVal] = useState('1d'); const [period, setPeriod] = useState('1y'); const [trainSize, setTrainSize] = useState(120); const [testSize, setTestSize] = useState(40); const [isLoading, setIsLoading] = useState(false); const [errorMsg, setErrorMsg] = useState(''); const [result, setResult] = useState(null); const handleRunWF = async () => { setIsLoading(true); setErrorMsg(''); setResult(null); try { const response = await fetch(`${API_BASE}/api/walk_forward`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ticker: ticker.toUpperCase().trim(), interval, period, train_size: trainSize, test_size: testSize, }), }); const data = await response.json(); if (data.success) { setResult(data); } else { setErrorMsg(data.error || '运行 Walk-Forward 优化失败'); } } catch (err) { setErrorMsg(`无法连接到后端服务器 (${API_BASE})。`); } finally { setIsLoading(false); } }; return (
{/* 顶部配置卡片 */}

🔄 Walk-Forward 滚动参数优化

样本外滚动优化 (Walk-Forward Optimization) 可以避免回测的“后视镜”偏差。系统使用历史的一段区间寻找最佳参数,并在接下来的区间进行真实样本外检验。

setTicker(e.target.value)} />
setTrainSize(Number(e.target.value))} />
setTestSize(Number(e.target.value))} />
{errorMsg && (
⚠️ {errorMsg}
)}
{/* 结果显示 */} {result && (
{/* 过拟合警告 */} {result.is_overfitted && (

⚠️ 参数过拟合警报 (Overfitting Risk Alert)

优化算法检测到训练集平均 Sharpe ({result.summary.avg_is_sharpe}) 表现优秀,但在样本外测试集中表现急剧退化 (平均 Sharpe: {result.summary.avg_oos_sharpe})。 且 IS 与 OOS Sharpe 的相关性为 {result.correlation}。这高度说明当前优化的策略参数在过度拟合历史噪声,建议增加过滤器、减少网格参数或放宽滑点控制。

)} {/* 并排对比卡片 */}
{/* Walk Forward Summary */}

🧪 Walk-Forward 滚动外表现

样本外总盈亏
= 0 ? 'var(--color-green)' : 'var(--color-red)' }}> ${result.summary.total_wf_pnl.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
平均滚动最大回撤
{(result.summary.avg_wf_drawdown * 100).toFixed(2)}%
总交易笔数
{result.summary.total_wf_trades} 笔
平均 OOS Sharpe
= 0.5 ? 'var(--color-green)' : 'inherit' }}> {result.summary.avg_oos_sharpe.toFixed(2)}
{/* Static Control */}

📉 静态默认参数 (全历史对照组)

累计净利润
= 0 ? 'var(--color-green)' : 'var(--color-red)' }}> ${result.static_control.net_pnl.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
全历史最大回撤
{(result.static_control.max_drawdown * 100).toFixed(2)}%
总交易笔数
{result.static_control.round_trips} 笔
静态 Sharpe 比率
{result.static_control.sharpe.toFixed(2)}
{/* 表格 */}

滚动时间窗口明细 (Rolling Windows Details)

{result.oos_results.map((row) => ( ))}
窗口 训练时间段 (In-Sample) 测试时间段 (Out-of-Sample) 最佳优化参数 IS Sharpe OOS Sharpe 样本外盈亏 样本外最大回撤
#{row.window} {row.train_period} {row.test_period} {row.best_params.strategy_mode} (ATR:{row.best_params.trailing_stop_atr_mult}x, RSI:{row.best_params.rsi_threshold_buy}) {row.is_sharpe.toFixed(2)} = 0.5 ? 'var(--color-green)' : (row.oos_sharpe < 0 ? 'var(--color-red)' : 'inherit'), fontWeight: 700 }}> {row.oos_sharpe.toFixed(2)} = 0 ? 'var(--color-green)' : 'var(--color-red)' }}> ${row.net_pnl.toFixed(2)} {(row.max_drawdown * 100).toFixed(2)}%
)}
); };