@@ -27,11 +27,11 @@ function outcomeBadge(outcome?: string) {
2727 if ( ! outcome ) return < Badge variant = "default" > --</ Badge > ;
2828 switch ( outcome ) {
2929 case 'win' :
30- return < Badge variant = "success" glow > WIN </ Badge > ;
30+ return < Badge variant = "success" glow > 盈利 </ Badge > ;
3131 case 'loss' :
32- return < Badge variant = "danger" glow > LOSS </ Badge > ;
32+ return < Badge variant = "danger" glow > 亏损 </ Badge > ;
3333 case 'neutral' :
34- return < Badge variant = "warning" > NEUTRAL </ Badge > ;
34+ return < Badge variant = "warning" > 持平 </ Badge > ;
3535 default :
3636 return < Badge variant = "default" > { outcome } </ Badge > ;
3737 }
@@ -40,12 +40,12 @@ function outcomeBadge(outcome?: string) {
4040function statusBadge ( status : string ) {
4141 switch ( status ) {
4242 case 'completed' :
43- return < Badge variant = "success" > completed </ Badge > ;
43+ return < Badge variant = "success" > 已完成 </ Badge > ;
4444 case 'insufficient' :
4545 case 'insufficient_data' :
46- return < Badge variant = "warning" > insufficient </ Badge > ;
46+ return < Badge variant = "warning" > 数据不足 </ Badge > ;
4747 case 'error' :
48- return < Badge variant = "danger" > error </ Badge > ;
48+ return < Badge variant = "danger" > 错误 </ Badge > ;
4949 default :
5050 return < Badge variant = "default" > { status } </ Badge > ;
5151 }
@@ -54,11 +54,11 @@ function statusBadge(status: string) {
5454function actualMovementBadge ( movement ?: string | null ) {
5555 switch ( movement ) {
5656 case 'up' :
57- return < Badge variant = "success" > UP </ Badge > ;
57+ return < Badge variant = "success" > 上涨 </ Badge > ;
5858 case 'down' :
59- return < Badge variant = "danger" > DOWN </ Badge > ;
59+ return < Badge variant = "danger" > 下跌 </ Badge > ;
6060 case 'flat' :
61- return < Badge variant = "warning" > FLAT </ Badge > ;
61+ return < Badge variant = "warning" > 横盘 </ Badge > ;
6262 default :
6363 return < Badge variant = "default" > --</ Badge > ;
6464 }
@@ -116,15 +116,15 @@ const PerformanceCard: React.FC<{ metrics: PerformanceMetrics; title: string }>
116116 < div className = "mb-3" >
117117 < span className = "label-uppercase" > { title } </ span >
118118 </ div >
119- < MetricRow label = "Direction Accuracy " value = { pct ( metrics . directionAccuracyPct ) } accent />
120- < MetricRow label = "Win Rate " value = { pct ( metrics . winRatePct ) } accent />
121- < MetricRow label = "Avg Sim. Return " value = { pct ( metrics . avgSimulatedReturnPct ) } />
122- < MetricRow label = "Avg Stock Return " value = { pct ( metrics . avgStockReturnPct ) } />
123- < MetricRow label = "SL Trigger Rate " value = { pct ( metrics . stopLossTriggerRate ) } />
124- < MetricRow label = "TP Trigger Rate " value = { pct ( metrics . takeProfitTriggerRate ) } />
125- < MetricRow label = "Avg Days to Hit " value = { metrics . avgDaysToFirstHit != null ? metrics . avgDaysToFirstHit . toFixed ( 1 ) : '--' } />
119+ < MetricRow label = "方向准确率 " value = { pct ( metrics . directionAccuracyPct ) } accent />
120+ < MetricRow label = "胜率 " value = { pct ( metrics . winRatePct ) } accent />
121+ < MetricRow label = "平均模拟收益 " value = { pct ( metrics . avgSimulatedReturnPct ) } />
122+ < MetricRow label = "平均股价收益 " value = { pct ( metrics . avgStockReturnPct ) } />
123+ < MetricRow label = "止损触发率 " value = { pct ( metrics . stopLossTriggerRate ) } />
124+ < MetricRow label = "止盈触发率 " value = { pct ( metrics . takeProfitTriggerRate ) } />
125+ < MetricRow label = "平均触发天数 " value = { metrics . avgDaysToFirstHit != null ? metrics . avgDaysToFirstHit . toFixed ( 1 ) : '--' } />
126126 < div className = "backtest-metric-footer" >
127- < span className = "text-xs text-muted-text" > Evaluations </ span >
127+ < span className = "text-xs text-muted-text" > 评估数 </ span >
128128 < span className = "text-xs text-secondary-text font-mono" >
129129 { Number ( metrics . completedCount ) } / { Number ( metrics . totalEvaluations ) }
130130 </ span >
@@ -146,12 +146,12 @@ const PerformanceCard: React.FC<{ metrics: PerformanceMetrics; title: string }>
146146
147147const RunSummary : React . FC < { data : BacktestRunResponse } > = ( { data } ) => (
148148 < div className = "backtest-summary animate-fade-in" >
149- < span className = "label" > Processed: < span className = "value" > { data . processed } </ span > </ span >
150- < span className = "label" > Saved: < span className = "value primary" > { data . saved } </ span > </ span >
151- < span className = "label" > Completed: < span className = "value success" > { data . completed } </ span > </ span >
152- < span className = "label" > Insufficient: < span className = "value warning" > { data . insufficient } </ span > </ span >
149+ < span className = "label" > 已处理: < span className = "value" > { data . processed } </ span > </ span >
150+ < span className = "label" > 已保存: < span className = "value primary" > { data . saved } </ span > </ span >
151+ < span className = "label" > 已完成: < span className = "value success" > { data . completed } </ span > </ span >
152+ < span className = "label" > 数据不足: < span className = "value warning" > { data . insufficient } </ span > </ span >
153153 { data . errors > 0 && (
154- < span className = "label" > Errors: < span className = "value danger" > { data . errors } </ span > </ span >
154+ < span className = "label" > 错误: < span className = "value danger" > { data . errors } </ span > </ span >
155155 ) }
156156 </ div >
157157) ;
@@ -337,7 +337,7 @@ const BacktestPage: React.FC = () => {
337337 value = { codeFilter }
338338 onChange = { ( e ) => setCodeFilter ( e . target . value . toUpperCase ( ) ) }
339339 onKeyDown = { handleKeyDown }
340- placeholder = "Filter by stock code (leave empty for all) "
340+ placeholder = "按股票代码筛选(留空查全部) "
341341 disabled = { isRunning }
342342 className = { BACKTEST_INPUT_CLASS }
343343 />
@@ -348,10 +348,10 @@ const BacktestPage: React.FC = () => {
348348 disabled = { isLoadingResults }
349349 className = "btn-secondary flex items-center gap-1.5 whitespace-nowrap"
350350 >
351- Filter
351+ 筛选
352352 </ button >
353353 < div className = "flex items-center gap-2 whitespace-nowrap lg:w-40 lg:justify-between" >
354- < span className = "text-xs text-muted-text" > Window </ span >
354+ < span className = "text-xs text-muted-text" > 窗口 </ span >
355355 < input
356356 type = "number"
357357 min = { 1 }
@@ -364,10 +364,10 @@ const BacktestPage: React.FC = () => {
364364 />
365365 </ div >
366366 < div className = "flex items-center gap-2 whitespace-nowrap" >
367- < span className = "text-xs text-muted-text" > From </ span >
367+ < span className = "text-xs text-muted-text" > 起始 </ span >
368368 < input
369369 type = "date"
370- aria-label = "Analysis date from "
370+ aria-label = "分析起始日 "
371371 value = { analysisDateFrom }
372372 onChange = { ( e ) => setAnalysisDateFrom ( e . target . value ) }
373373 onKeyDown = { handleKeyDown }
@@ -376,10 +376,10 @@ const BacktestPage: React.FC = () => {
376376 />
377377 </ div >
378378 < div className = "flex items-center gap-2 whitespace-nowrap" >
379- < span className = "text-xs text-muted-text" > To </ span >
379+ < span className = "text-xs text-muted-text" > 截止 </ span >
380380 < input
381381 type = "date"
382- aria-label = "Analysis date to "
382+ aria-label = "分析截止日 "
383383 value = { analysisDateTo }
384384 onChange = { ( e ) => setAnalysisDateTo ( e . target . value ) }
385385 onKeyDown = { handleKeyDown }
@@ -394,7 +394,7 @@ const BacktestPage: React.FC = () => {
394394 className = { `backtest-force-btn ${ isNextDayValidation ? 'active' : '' } ` }
395395 >
396396 < span className = "dot" />
397- 1D Validation
397+ 次日验证
398398 </ button >
399399 < button
400400 type = "button"
@@ -403,7 +403,7 @@ const BacktestPage: React.FC = () => {
403403 className = { `backtest-force-btn ${ forceRerun ? 'active' : '' } ` }
404404 >
405405 < span className = "dot" />
406- Force
406+ 强制重跑
407407 </ button >
408408 < button
409409 type = "button"
@@ -417,10 +417,10 @@ const BacktestPage: React.FC = () => {
417417 < circle className = "opacity-25" cx = "12" cy = "12" r = "10" stroke = "currentColor" strokeWidth = "4" />
418418 < path className = "opacity-75" fill = "currentColor" d = "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
419419 </ svg >
420- Running ...
420+ 运行中 ...
421421 </ >
422422 ) : (
423- 'Run Backtest '
423+ '运行回测 '
424424 ) }
425425 </ button >
426426 </ div >
@@ -434,8 +434,8 @@ const BacktestPage: React.FC = () => {
434434 ) }
435435 < p className = "mt-2 text-xs text-muted-text" >
436436 { isNextDayValidation
437- ? 'Next-day validation mode compares AI predictions with the next trading day close. '
438- : 'Use window = 1 to review AI predictions against the next trading day close. ' }
437+ ? '次日验证模式:将 AI 预测与下一交易日收盘价对比。 '
438+ : '将窗口设为 1 可对照次日收盘价复核 AI 预测。 ' }
439439 </ p >
440440 </ header >
441441
@@ -448,11 +448,11 @@ const BacktestPage: React.FC = () => {
448448 < div className = "backtest-spinner sm" />
449449 </ div >
450450 ) : overallPerf ? (
451- < PerformanceCard metrics = { overallPerf } title = "Overall Performance " />
451+ < PerformanceCard metrics = { overallPerf } title = "整体表现 " />
452452 ) : (
453453 < EmptyState
454- title = "No Metrics Yet "
455- description = "Run a backtest to generate portfolio-level performance metrics. "
454+ title = "暂无指标 "
455+ description = "运行回测以生成组合级表现指标。 "
456456 className = "h-full min-h-[12rem] border-dashed bg-card/45 shadow-none"
457457 />
458458 ) }
@@ -470,12 +470,12 @@ const BacktestPage: React.FC = () => {
470470 { isLoadingResults ? (
471471 < div className = "flex flex-col items-center justify-center h-64" >
472472 < div className = "backtest-spinner md" />
473- < p className = "mt-3 text-secondary-text text-sm" > Loading results ...</ p >
473+ < p className = "mt-3 text-secondary-text text-sm" > 加载结果中 ...</ p >
474474 </ div >
475475 ) : results . length === 0 ? (
476476 < EmptyState
477- title = "No Results "
478- description = "Run a backtest to evaluate historical analysis accuracy "
477+ title = "暂无结果 "
478+ description = "运行回测以评估历史分析准确度 "
479479 className = "backtest-empty-state border-dashed"
480480 icon = { (
481481 < svg className = "h-6 w-6" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
@@ -487,31 +487,31 @@ const BacktestPage: React.FC = () => {
487487 < div className = "animate-fade-in" >
488488 < div className = "backtest-table-toolbar" >
489489 < div className = "backtest-table-toolbar-meta" >
490- < span className = "label-uppercase" > { isNextDayValidation ? 'Next-Day Validation ' : 'Result Set ' } </ span >
490+ < span className = "label-uppercase" > { isNextDayValidation ? '次日验证 ' : '结果集 ' } </ span >
491491 < span className = "text-xs text-secondary-text" >
492- { codeFilter . trim ( ) ? `Filtered by ${ codeFilter . trim ( ) } ` : 'All stocks ' }
493- { evalDays ? ` · ${ evalDays } day window ` : '' }
494- { analysisDateFrom ? ` · from ${ analysisDateFrom } ` : '' }
495- { analysisDateTo ? ` · to ${ analysisDateTo } ` : '' }
492+ { codeFilter . trim ( ) ? `已按 ${ codeFilter . trim ( ) } 筛选 ` : '全部股票 ' }
493+ { evalDays ? ` · ${ evalDays } 日窗口 ` : '' }
494+ { analysisDateFrom ? ` · 起 ${ analysisDateFrom } ` : '' }
495+ { analysisDateTo ? ` · 至 ${ analysisDateTo } ` : '' }
496496 </ span >
497497 </ div >
498- < span className = "backtest-table-scroll-hint" > Scroll horizontally on small screens </ span >
498+ < span className = "backtest-table-scroll-hint" > 小屏幕请左右滚动 </ span >
499499 </ div >
500500 < div className = "backtest-table-wrapper" >
501501 < table className = "backtest-table min-w-[840px] w-full text-sm" >
502502 < thead className = "backtest-table-head" >
503503 < tr className = "text-left" >
504- < th className = "backtest-table-head-cell" > Stock </ th >
505- < th className = "backtest-table-head-cell" > Analysis Date </ th >
506- < th className = "backtest-table-head-cell" > AI Prediction </ th >
504+ < th className = "backtest-table-head-cell" > 股票 </ th >
505+ < th className = "backtest-table-head-cell" > 分析日期 </ th >
506+ < th className = "backtest-table-head-cell" > AI 预测 </ th >
507507 < th className = "backtest-table-head-cell" >
508- { showNextDayActualColumns ? 'Actual ' : 'Window Return ' }
508+ { showNextDayActualColumns ? '实际 ' : '区间收益 ' }
509509 </ th >
510510 < th className = "backtest-table-head-cell" >
511- { showNextDayActualColumns ? 'Accuracy ' : 'Direction Match ' }
511+ { showNextDayActualColumns ? '准确度 ' : '方向匹配 ' }
512512 </ th >
513- < th className = "backtest-table-head-cell" > Outcome </ th >
514- < th className = "backtest-table-head-cell" > Status </ th >
513+ < th className = "backtest-table-head-cell" > 结果 </ th >
514+ < th className = "backtest-table-head-cell" > 状态 </ th >
515515 </ tr >
516516 </ thead >
517517 < tbody >
@@ -578,7 +578,7 @@ const BacktestPage: React.FC = () => {
578578 </ div >
579579
580580 < p className = "text-xs text-muted-text text-center mt-2" >
581- { totalResults } result { totalResults !== 1 ? 's' : '' } total · page { currentPage } of { Math . max ( totalPages , 1 ) }
581+ 共 { totalResults } 条 · 第 { currentPage } / { Math . max ( totalPages , 1 ) } 页
582582 </ p >
583583 </ div >
584584 ) }
0 commit comments