ui: 研究Tab列表加回交易数列+新增均持仓周期列(周转率核心指标),表格横向可滚动
This commit is contained in:
+6
-2
@@ -1974,11 +1974,13 @@ function renderStrategyTable(strategies) {
|
|||||||
const isBest = invert ? (val === bestVal && bestVal !== 999) : (val === bestVal && bestVal !== -999);
|
const isBest = invert ? (val === bestVal && bestVal !== 999) : (val === bestVal && bestVal !== -999);
|
||||||
return isBest ? 'text-green-400 font-bold' : '';
|
return isBest ? 'text-green-400 font-bold' : '';
|
||||||
};
|
};
|
||||||
let html = '<table class="w-full text-xs"><thead><tr class="text-slate-500 border-b border-slate-700">' +
|
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-left px-2 py-1.5">版本</th><th class="text-left 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 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 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>' +
|
||||||
@@ -1995,6 +1997,8 @@ function renderStrategyTable(strategies) {
|
|||||||
'<td class="text-right px-2 py-1.5 font-mono font-bold ' + retClass + ' ' + hl(pf.total_return_pct, best.total_return_pct) + '">' + (pf.total_return_pct != null ? pf.total_return_pct + '%' : '—') + '</td>' +
|
'<td class="text-right px-2 py-1.5 font-mono font-bold ' + retClass + ' ' + hl(pf.total_return_pct, best.total_return_pct) + '">' + (pf.total_return_pct != null ? pf.total_return_pct + '%' : '—') + '</td>' +
|
||||||
'<td class="text-right px-2 py-1.5 font-mono ' + (pf.capital_final != null ? '' : 'text-slate-600') + '">' + (pf.capital_final != null ? '¥' + (pf.capital_final/10000).toFixed(0) + '万' : '—') + '</td>' +
|
'<td class="text-right px-2 py-1.5 font-mono ' + (pf.capital_final != null ? '' : 'text-slate-600') + '">' + (pf.capital_final != null ? '¥' + (pf.capital_final/10000).toFixed(0) + '万' : '—') + '</td>' +
|
||||||
'<td class="text-right px-2 py-1.5 font-mono ' + hl(pf.cagr_pct, best.cagr_pct) + '">' + (pf.cagr_pct != null ? pf.cagr_pct + '%' : '—') + '</td>' +
|
'<td class="text-right px-2 py-1.5 font-mono ' + hl(pf.cagr_pct, best.cagr_pct) + '">' + (pf.cagr_pct != null ? pf.cagr_pct + '%' : '—') + '</td>' +
|
||||||
|
'<td class="text-right px-2 py-1.5 font-mono">' + (st.total_trades != null ? st.total_trades : '—') + '</td>' +
|
||||||
|
'<td class="text-right px-2 py-1.5 font-mono">' + (st.avg_hold_days != null ? st.avg_hold_days + 'd' : '—') + '</td>' +
|
||||||
'<td class="text-right px-2 py-1.5 font-mono ' + hl(st.win_rate, best.win_rate) + '">' + (st.win_rate != null ? st.win_rate + '%' : '—') + '</td>' +
|
'<td class="text-right px-2 py-1.5 font-mono ' + hl(st.win_rate, best.win_rate) + '">' + (st.win_rate != null ? st.win_rate + '%' : '—') + '</td>' +
|
||||||
'<td class="text-right px-2 py-1.5 font-mono ' + ((st.avg_profit_pct || 0) >= 0 ? 'text-green-400' : 'text-red-400') + '">' + (st.avg_profit_pct != null ? st.avg_profit_pct + '%' : '—') + '</td>' +
|
'<td class="text-right px-2 py-1.5 font-mono ' + ((st.avg_profit_pct || 0) >= 0 ? 'text-green-400' : 'text-red-400') + '">' + (st.avg_profit_pct != null ? st.avg_profit_pct + '%' : '—') + '</td>' +
|
||||||
'<td class="text-right px-2 py-1.5 font-mono ' + hl(st.sharpe_ratio, best.sharpe_ratio) + '">' + (st.sharpe_ratio != null ? st.sharpe_ratio : '—') + '</td>' +
|
'<td class="text-right px-2 py-1.5 font-mono ' + hl(st.sharpe_ratio, best.sharpe_ratio) + '">' + (st.sharpe_ratio != null ? st.sharpe_ratio : '—') + '</td>' +
|
||||||
@@ -2004,7 +2008,7 @@ function renderStrategyTable(strategies) {
|
|||||||
'<button onclick="runStrategyBacktest(\'' + s.version + '\')" class="px-2 py-0.5 bg-blue-600/60 hover:bg-blue-500 rounded text-xs">▶回测</button>' +
|
'<button onclick="runStrategyBacktest(\'' + s.version + '\')" class="px-2 py-0.5 bg-blue-600/60 hover:bg-blue-500 rounded text-xs">▶回测</button>' +
|
||||||
'</td></tr>';
|
'</td></tr>';
|
||||||
}
|
}
|
||||||
html += '</tbody></table>' +
|
html += '</tbody></table></div>' +
|
||||||
'<div class="text-xs text-slate-600 mt-2">总收益/最终资产 = 100万本金·最多10等分仓位·24个月组合模拟 · ⚠️样本<40笔 · 绿色=该列最优 · 悬停名称查看改进假设</div>';
|
'<div class="text-xs text-slate-600 mt-2">总收益/最终资产 = 100万本金·最多10等分仓位·24个月组合模拟 · ⚠️样本<40笔 · 绿色=该列最优 · 悬停名称查看改进假设</div>';
|
||||||
el.innerHTML = html;
|
el.innerHTML = html;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -852,6 +852,7 @@ def calc_summary(trades, capital):
|
|||||||
'avg_profit_pct': round(avg_p, 2),
|
'avg_profit_pct': round(avg_p, 2),
|
||||||
'avg_win_pct': round(avg_w, 2),
|
'avg_win_pct': round(avg_w, 2),
|
||||||
'avg_loss_pct': round(avg_l, 2),
|
'avg_loss_pct': round(avg_l, 2),
|
||||||
|
'avg_hold_days': round(sum(t['hold_days'] for t in trades) / len(trades), 1),
|
||||||
'sharpe_ratio': round(sharpe, 2),
|
'sharpe_ratio': round(sharpe, 2),
|
||||||
'max_drawdown_pct': round(max_dd, 2),
|
'max_drawdown_pct': round(max_dd, 2),
|
||||||
'profit_factor': round(abs(avg_w/avg_l), 2) if avg_l != 0 else None,
|
'profit_factor': round(abs(avg_w/avg_l), 2) if avg_l != 0 else None,
|
||||||
|
|||||||
Reference in New Issue
Block a user