feat: 策略列表全列可点击排序(升降切换+方向箭头)
This commit is contained in:
+62
-12
@@ -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 = '<div class="text-slate-500">暂无策略版本</div>'; 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 `<td class="${cls}" style="${sty}">${v != null ? fmt(v) : '—'}</td>`;
|
||||
};
|
||||
const th = (key, label, cls, title) => {
|
||||
const arrow = window._sortKey === key ? (window._sortDir === 'desc' ? '▼' : '▲') : '';
|
||||
return `<th class="${cls || 'text-right'} px-2 py-1.5 cursor-pointer hover:text-slate-300 select-none" onclick="sortBy('${key}')" title="${title || '点击排序'}">${label}${arrow ? ' ' + arrow : ''}</th>`;
|
||||
};
|
||||
let html = '<div class="overflow-x-auto"><table class="w-full text-xs whitespace-nowrap"><thead><tr class="text-slate-500 border-b border-slate-700">' +
|
||||
'<th class="text-left px-2 py-1.5">版本</th><th class="text-left px-2 py-1.5">名称</th>' +
|
||||
'<th class="text-center px-2 py-1.5" title="该策略实证最优的仓位模型:波段/结构出场适合大仓少股,固定出场适合小仓多股">仓位</th>' +
|
||||
'<th class="text-right px-2 py-1.5 text-amber-300">综合</th>' +
|
||||
'<th class="text-right px-2 py-1.5">普适</th>' +
|
||||
'<th class="text-right px-2 py-1.5 text-amber-400">总收益</th>' +
|
||||
'<th class="text-right px-2 py-1.5 text-amber-400">最终资产</th>' +
|
||||
'<th class="text-right px-2 py-1.5">年化</th>' +
|
||||
'<th class="text-right px-2 py-1.5">交易数</th>' +
|
||||
'<th class="text-right px-2 py-1.5">均持仓</th>' +
|
||||
'<th class="text-right px-2 py-1.5">胜率</th>' +
|
||||
'<th class="text-right px-2 py-1.5">平均收益</th><th class="text-right px-2 py-1.5">夏普</th>' +
|
||||
'<th class="text-right px-2 py-1.5">盈亏比</th><th class="text-right px-2 py-1.5">资产回撤</th>' +
|
||||
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') +
|
||||
'<th class="text-center px-2 py-1.5">操作</th></tr></thead><tbody>';
|
||||
for (const s of strategies) {
|
||||
const st = s.summary_stats || {};
|
||||
|
||||
Reference in New Issue
Block a user