From 5cf0e3035c4c0906d3732da974283e5f9ccde479 Mon Sep 17 00:00:00 2001 From: hmo Date: Tue, 11 Aug 2026 12:09:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=A0=94=E7=A9=B6Tab=E7=AD=96=E7=95=A5?= =?UTF-8?q?=E5=AD=90Tab=E6=8B=86=E5=88=86=E5=BD=93=E5=89=8D/=E5=8E=86?= =?UTF-8?q?=E5=8F=B2=E5=8C=BA=E5=9F=9F=E2=80=94=E2=80=94=E5=BD=93=E5=89=8D?= =?UTF-8?q?=E4=BD=BF=E7=94=A8(=E5=AE=9E=E7=9B=98/=E6=96=B0=E7=AD=96?= =?UTF-8?q?=E7=95=A5)=E5=B1=95=E5=BC=80+=E5=8E=86=E5=8F=B2=E7=AD=96?= =?UTF-8?q?=E7=95=A5=E9=BB=98=E8=AE=A4=E6=8A=98=E5=8F=A0,=E6=8C=89s.curren?= =?UTF-8?q?t=E5=AD=97=E6=AE=B5=E5=88=86=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/index.html | 115 ++++++++++++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 45 deletions(-) diff --git a/static/index.html b/static/index.html index a12d4be0..ed9687af 100644 --- a/static/index.html +++ b/static/index.html @@ -2467,52 +2467,77 @@ function renderStrategyTable(strategies) { const arrow = window._sortKey === key ? (window._sortDir === 'desc' ? '▼' : '▲') : ''; return `${label}${arrow ? ' ' + arrow : ''}`; }; - let html = '
' + - th('version', '版本', 'text-left') + th('name', '名称', 'text-left') + - th('sizing_slots', '仓位', 'text-center') + - '' + - th('composite', '综合', 'text-right') + - th('universality', '普适', 'text-right') + - th('full_return', '全参与', 'text-right') + - th('capital_final', '最终资产', 'text-right') + - th('cagr', '年化', 'text-right') + - th('trades', '执行数', 'text-right', '实际参与组合模拟的交易笔数;信号总数=为鼠标悬停查看') + - th('hold', '均持仓', 'text-right') + - th('win_rate', '胜率', 'text-right') + - th('avg_profit', '平均收益', 'text-right') + th('sharpe', '夏普', 'text-right') + - th('profit_factor', '盈亏比', 'text-right') + th('max_dd', '资产回撤', 'text-right') + - ''; - for (const s of strategies) { - const st = s.summary_stats || {}; - const pf = st.portfolio || {}; - const hasResult = st.total_trades != null; - const smallSample = hasResult && st.total_trades < 40; - const isCurrent = (s.version === CURRENT_STRATEGY || CURRENT_FAMILY.has(s.version)) && (s.market || 'all') !== 'hk'; - const deprecatedReason = DEPRECATED[s.version]; - const rowCls = 'border-b border-slate-800/50 hover:bg-slate-800/30 cursor-pointer' + (isCurrent ? ' bg-emerald-900/20 border-l-2 border-l-emerald-400' : ''); - html += '' + - '' + - '' + - '' + - '' + - cell('composite', s._composite, v => v + (s._confidence != null && s._confidence < 1 ? '×' + s._confidence.toFixed(2) + '' : ''), 'font-bold text-amber-300') + - cell('universality_score', (st.universality || {}).score, v => v + '/' + (st.universality || {}).months + '月') + - cell('full_return_pct', (st.portfolio_full || {}).total_return_pct, v => v + '%' + ((st.portfolio_full||{}).std ? '±' + (st.portfolio_full||{}).std + '' : ''), 'font-bold text-amber-300') + - cell('capital_final', (st.portfolio_full||pf).capital_final, v => '¥' + (v/10000).toFixed(0) + '万') + - cell('cagr_pct', (st.portfolio_full||pf).cagr_pct, v => v + '%', hl((st.portfolio_full||pf).cagr_pct, best.cagr_pct)) + - cell('total_trades', st.total_trades, v => ((st.portfolio_full||{}).positions_taken ?? (pf.positions_taken||0)) + '/' + (v > 999 ? Math.round(v/1000) + 'k' : v), '', false) + - cell('avg_hold_days', st.avg_hold_days, v => v + 'd') + - cell('win_rate', st.win_rate, v => v + '%', hl(st.win_rate, best.win_rate)) + - cell('avg_profit_pct', st.avg_profit_pct, v => v + '%', (st.avg_profit_pct || 0) >= 0 ? 'text-green-400' : 'text-red-400') + - cell('sharpe_ratio', st.sharpe_ratio, v => v, hl(st.sharpe_ratio, best.sharpe_ratio)) + - cell('profit_factor', st.profit_factor, v => v, hl(st.profit_factor, best.profit_factor)) + - cell('portfolio_max_dd_pct', (st.portfolio_full||pf).portfolio_max_dd_pct, v => v + '%', hl((st.portfolio_full||pf).portfolio_max_dd_pct, best.portfolio_max_dd_pct, true), true) + - ''; + // 2026-08-11 新增:拆分当前/历史区域(老莫需求) + // 当前 = current=true(实盘/新策略);历史 = 其余,默认折叠 + const currentStrats = strategies.filter(s => s.current === true); + const historyStrats = strategies.filter(s => s.current !== true); + const renderGroup = (groupStrats, groupTitle, groupIcon, collapsed) => { + let ghtml = '
说明操作
' + s.version + (isCurrent ? ' 当前' : '') + (deprecatedReason ? ' 已证伪' : '') + ((s.market && s.market !== 'all') ? ' ' + (s.market === 'hk' ? '港' : 'A') + '' : '') + '' + (s.name || '') + (smallSample ? ' ⚠️' : '') + '' + (st.sizing_slots ? st.sizing_slots + '仓' : '10仓') + (st.conviction_model ? '' : '') + '' + ((s.description && s.description.title) ? '' : '') + '' + - '' + - '
' + + th('version', '版本', 'text-left') + th('name', '名称', 'text-left') + + th('sizing_slots', '仓位', 'text-center') + + '' + + th('composite', '综合', 'text-right') + + th('universality', '普适', 'text-right') + + th('full_return', '全参与', 'text-right') + + th('capital_final', '最终资产', 'text-right') + + th('cagr', '年化', 'text-right') + + th('trades', '执行数', 'text-right', '实际参与组合模拟的交易笔数;信号总数=为鼠标悬停查看') + + th('hold', '均持仓', 'text-right') + + th('win_rate', '胜率', 'text-right') + + th('avg_profit', '平均收益', 'text-right') + th('sharpe', '夏普', 'text-right') + + th('profit_factor', '盈亏比', 'text-right') + th('max_dd', '资产回撤', 'text-right') + + ''; + for (const s of groupStrats) { + const st = s.summary_stats || {}; + const pf = st.portfolio || {}; + const hasResult = st.total_trades != null; + const smallSample = hasResult && st.total_trades < 40; + const isCurrent = s.current === true; + const deprecatedReason = DEPRECATED[s.version]; + const rowCls = 'border-b border-slate-800/50 hover:bg-slate-800/30 cursor-pointer' + (isCurrent ? ' bg-emerald-900/20 border-l-2 border-l-emerald-400' : ''); + ghtml += '' + + '' + + '' + + '' + + '' + + cell('composite', s._composite, v => v + (s._confidence != null && s._confidence < 1 ? '×' + s._confidence.toFixed(2) + '' : ''), 'font-bold text-amber-300') + + cell('universality_score', (st.universality || {}).score, v => v + '/' + (st.universality || {}).months + '月') + + cell('full_return_pct', (st.portfolio_full || {}).total_return_pct, v => v + '%' + ((st.portfolio_full||{}).std ? '±' + (st.portfolio_full||{}).std + '' : ''), 'font-bold text-amber-300') + + cell('capital_final', (st.portfolio_full||pf).capital_final, v => '¥' + (v/10000).toFixed(0) + '万') + + cell('cagr_pct', (st.portfolio_full||pf).cagr_pct, v => v + '%', hl((st.portfolio_full||pf).cagr_pct, best.cagr_pct)) + + cell('total_trades', st.total_trades, v => ((st.portfolio_full||{}).positions_taken ?? (pf.positions_taken||0)) + '/' + (v > 999 ? Math.round(v/1000) + 'k' : v), '', false) + + cell('avg_hold_days', st.avg_hold_days, v => v + 'd') + + cell('win_rate', st.win_rate, v => v + '%', hl(st.win_rate, best.win_rate)) + + cell('avg_profit_pct', st.avg_profit_pct, v => v + '%', (st.avg_profit_pct || 0) >= 0 ? 'text-green-400' : 'text-red-400') + + cell('sharpe_ratio', st.sharpe_ratio, v => v, hl(st.sharpe_ratio, best.sharpe_ratio)) + + cell('profit_factor', st.profit_factor, v => v, hl(st.profit_factor, best.profit_factor)) + + cell('portfolio_max_dd_pct', (st.portfolio_full||pf).portfolio_max_dd_pct, v => v + '%', hl((st.portfolio_full||pf).portfolio_max_dd_pct, best.portfolio_max_dd_pct, true), true) + + ''; + } + ghtml += '
说明操作
' + s.version + (isCurrent ? ' 当前' : '') + (deprecatedReason ? ' 已证伪' : '') + ((s.market && s.market !== 'all') ? ' ' + (s.market === 'hk' ? '港' : 'A') + '' : '') + '' + (s.name || '') + (smallSample ? ' ⚠️' : '') + '' + (st.sizing_slots ? st.sizing_slots + '仓' : '10仓') + (st.conviction_model ? '' : '') + '' + ((s.description && s.description.title) ? '' : '') + '' + + '' + + '
'; + return ghtml; + }; + // 当前区域(展开)+ 历史区域(默认折叠) + let html = ''; + if (currentStrats.length) { + html += '
' + + '
🟢 当前使用(' + currentStrats.length + '个)
' + + renderGroup(currentStrats, '当前', '🟢', false) + + '
'; } - html += '' + - '
总收益/最终资产 = 100万本金·最多10等分仓位·24个月组合模拟 · ⚠️样本<40笔 · 绿色=该列最优 · 悬停名称查看改进假设
'; + if (historyStrats.length) { + html += '
' + + '' + + '' + + '
'; + } + if (!currentStrats.length && !historyStrats.length) { + html = '
暂无策略版本
'; + } + html += '
总收益/最终资产 = 100万本金·最多10等分仓位·24个月组合模拟 · ⚠️样本<40笔 · 绿色=该列最优 · 悬停名称查看改进假设
'; el.innerHTML = html; }