From c570fb9aab4b55ffaadc719f39e4e475ba92c6c8 Mon Sep 17 00:00:00 2001 From: hmo Date: Wed, 29 Jul 2026 14:48:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=AD=96=E7=95=A5=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E5=85=A8=E5=88=97=E5=8F=AF=E7=82=B9=E5=87=BB=E6=8E=92=E5=BA=8F?= =?UTF-8?q?(=E5=8D=87=E9=99=8D=E5=88=87=E6=8D=A2+=E6=96=B9=E5=90=91?= =?UTF-8?q?=E7=AE=AD=E5=A4=B4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/index.html | 74 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 12 deletions(-) diff --git a/static/index.html b/static/index.html index 1cfadec2..ca735faf 100644 --- a/static/index.html +++ b/static/index.html @@ -1959,9 +1959,55 @@ async function loadStrategyList() { } } +function sortBy(key) { + if (window._sortKey === key) { + window._sortDir = window._sortDir === 'desc' ? 'asc' : 'desc'; + } else { + window._sortKey = key; + window._sortDir = 'desc'; + } + renderStrategyTable(window._strats || []); +} + +function sortStrategies(strategies, key, dir) { + const get = (s) => { + const st = s.summary_stats || {}; const pf = st.portfolio || {}; + switch(key) { + case 'version': return s.version || ''; + case 'name': return s.name || ''; + case 'sizing_slots': return st.sizing_slots || 10; + case 'composite': return s._composite != null ? s._composite : -999; + case 'universality': return (st.universality || {}).score || 0; + case 'total_return': return pf.total_return_pct != null ? pf.total_return_pct : -999; + case 'capital_final': return pf.capital_final || 0; + case 'cagr': return pf.cagr_pct != null ? pf.cagr_pct : -999; + case 'trades': return st.total_trades || 0; + case 'hold': return st.avg_hold_days || 0; + case 'win_rate': return st.win_rate != null ? st.win_rate : -999; + case 'avg_profit': return st.avg_profit_pct != null ? st.avg_profit_pct : -999; + case 'sharpe': return st.sharpe_ratio != null ? st.sharpe_ratio : -999; + case 'profit_factor': return st.profit_factor != null ? st.profit_factor : -999; + case 'max_dd': return pf.portfolio_max_dd_pct != null ? pf.portfolio_max_dd_pct : 999; + default: return 0; + } + }; + const arr = [...strategies]; + arr.sort((a, b) => { + const va = get(a), vb = get(b); + let cmp = (typeof va === 'string') ? va.localeCompare(vb) : va - vb; + return dir === 'desc' ? -cmp : cmp; + }); + return arr; +} + function renderStrategyTable(strategies) { const el = document.getElementById('strategyList'); if (!strategies.length) { el.innerHTML = '
暂无策略版本
'; return; } + // 保存数据用于列排序 + window._strats = strategies; + if (window._sortKey) { + strategies = sortStrategies(strategies, window._sortKey, window._sortDir); + } // 非港股版本在前,港股分身沉底且同版本内非港在前(2026-07-29 老爸:v7.1身份不被港股分身混淆) strategies.sort((a, b) => { const am = (a.market || 'all') === 'hk' ? 1 : 0; @@ -2027,19 +2073,23 @@ function renderStrategyTable(strategies) { const sty = bar(c, v, invert); return `${v != null ? fmt(v) : '—'}`; }; + const th = (key, label, cls, title) => { + 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('total_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 || {};
版本名称仓位综合普适总收益最终资产年化交易数均持仓胜率平均收益夏普盈亏比资产回撤操作