fix: 组合Tab突出成员盈利率 + 手工可行性标注
- 前端: 成员卡片盈利率/年化/10年收益提为大字醒目显示(原10px小字用户看不到) - 前端: v_mr卡片加实盘链路说明(22k信号→组合执行628→每日扫描仅3候选→人工确认) - 前端: 标注毛利vs扣费口径(单笔均收益=毛利, 组合年化/收益=已扣0.2%费用) - 后端: members补充组合模拟实际执行笔数(5槽/36槽), 用于年均笔数展示
This commit is contained in:
@@ -119,6 +119,7 @@ def get_combo_dashboard():
|
||||
res = json.loads(r[0])
|
||||
s = res.get("summary", {})
|
||||
pf = s.get("portfolio_full", {})
|
||||
p5 = s.get("portfolio", {})
|
||||
members[v] = {
|
||||
"role": "趋势市主战" if v == "v_next4" else "震荡/下跌市接管",
|
||||
"trades": s.get("total_trades"),
|
||||
@@ -129,6 +130,9 @@ def get_combo_dashboard():
|
||||
"return_pct": pf.get("total_return_pct"),
|
||||
"max_dd_pct": pf.get("portfolio_max_dd_pct"),
|
||||
"universality": s.get("universality", {}),
|
||||
# 组合模拟实际执行笔数(扣费后) + 年均(手工可行性参考)
|
||||
"positions_taken_5slot": p5.get("positions_taken"),
|
||||
"positions_taken_full": pf.get("positions_taken"),
|
||||
}
|
||||
|
||||
conn.close()
|
||||
|
||||
+17
-9
@@ -2084,20 +2084,28 @@ async function renderResearchCombo() {
|
||||
// ── 2. 组合成员策略指标 ──
|
||||
const members = d.members || {};
|
||||
if (Object.keys(members).length) {
|
||||
h += '<div class="text-sm font-bold text-slate-300 mb-1.5">成员策略(10年回测)</div>' +
|
||||
h += '<div class="text-sm font-bold text-slate-300 mb-1.5">成员策略(10年回测,组合收益已扣费)</div>' +
|
||||
'<div class="grid grid-cols-2 gap-2 mb-3">';
|
||||
for (const [v, m] of Object.entries(members)) {
|
||||
const u = m.universality || {};
|
||||
h += '<div class="bg-slate-800/50 rounded-lg p-2.5">' +
|
||||
'<div class="flex items-center justify-between"><span class="font-mono font-bold text-' + (v === 'v_next4' ? 'emerald-400' : 'amber-300') + '">' + v + '</span>' +
|
||||
const yearly5 = m.positions_taken_5slot && m.positions_taken_5slot > 0 ? Math.round(m.positions_taken_5slot / 10) : '—';
|
||||
h += '<div class="bg-slate-800/50 rounded-lg p-3">' +
|
||||
'<div class="flex items-center justify-between mb-1.5"><span class="font-mono font-bold text-base text-' + (v === 'v_next4' ? 'emerald-400' : 'amber-300') + '">' + v + '</span>' +
|
||||
'<span class="text-[10px] text-slate-500">' + (m.role || '') + '</span></div>' +
|
||||
'<div class="grid grid-cols-4 gap-1 mt-1.5 text-center text-xs">' +
|
||||
'<div><div class="text-slate-500 text-[10px]">年化</div><div class="font-mono text-amber-200">' + (m.cagr_pct != null ? m.cagr_pct + '%' : '—') + '</div></div>' +
|
||||
'<div><div class="text-slate-500 text-[10px]">胜率</div><div class="font-mono">' + (m.win_rate != null ? m.win_rate + '%' : '—') + '</div></div>' +
|
||||
'<div><div class="text-slate-500 text-[10px]">笔数</div><div class="font-mono">' + (m.trades != null ? (m.trades > 999 ? Math.round(m.trades/1000) + 'k' : m.trades) : '—') + '</div></div>' +
|
||||
'<div><div class="text-slate-500 text-[10px]">覆盖</div><div class="font-mono">' + (u.months || '—') + '月</div></div>' +
|
||||
// 盈利率大字突出(用户关注的核心指标)
|
||||
'<div class="flex items-end gap-4 mb-2">' +
|
||||
'<div><div class="text-[10px] text-slate-500">单笔均收益(毛利)</div><div class="font-mono font-bold text-lg ' + ((m.avg_profit_pct || 0) >= 0 ? 'text-green-400' : 'text-red-400') + '">' + (m.avg_profit_pct != null ? m.avg_profit_pct + '%' : '—') + '</div></div>' +
|
||||
'<div><div class="text-[10px] text-slate-500">组合年化(扣费)</div><div class="font-mono font-bold text-lg text-amber-200">' + (m.cagr_pct != null ? m.cagr_pct + '%' : '—') + '</div></div>' +
|
||||
'<div><div class="text-[10px] text-slate-500">组合10年收益</div><div class="font-mono font-bold text-lg text-amber-200">' + (m.return_pct != null ? m.return_pct + '%' : '—') + '</div></div>' +
|
||||
'</div>' +
|
||||
'<div class="text-[10px] text-slate-500 mt-1">均持' + (m.avg_hold_days != null ? m.avg_hold_days + '天' : '—') + ' · 均收益' + (m.avg_profit_pct != null ? m.avg_profit_pct + '%' : '—') + ' · 回撤' + (m.max_dd_pct != null ? m.max_dd_pct + '%' : '—') + '</div>' +
|
||||
'<div class="grid grid-cols-4 gap-1 mb-1 text-center text-xs">' +
|
||||
'<div><div class="text-slate-500 text-[10px]">胜率</div><div class="font-mono">' + (m.win_rate != null ? m.win_rate + '%' : '—') + '</div></div>' +
|
||||
'<div><div class="text-slate-500 text-[10px]">信号总数</div><div class="font-mono">' + (m.trades != null ? (m.trades > 999 ? Math.round(m.trades/1000) + 'k' : m.trades) : '—') + '</div></div>' +
|
||||
'<div><div class="text-slate-500 text-[10px]">组合执行</div><div class="font-mono">' + (m.positions_taken_5slot != null ? m.positions_taken_5slot + '笔' : '—') + '</div></div>' +
|
||||
'<div><div class="text-slate-500 text-[10px]">覆盖月</div><div class="font-mono">' + (u.months || '—') + '</div></div>' +
|
||||
'</div>' +
|
||||
'<div class="text-[10px] text-slate-500">均持' + (m.avg_hold_days != null ? m.avg_hold_days + '天' : '—') + ' · 回撤' + (m.max_dd_pct != null ? m.max_dd_pct + '%' : '—') + ' · 组合年均' + yearly5 + '笔(人工可操作)</div>' +
|
||||
(v === 'v_mr' ? '<div class="text-[10px] text-slate-600 mt-1.5 border-t border-slate-800 pt-1">📋 实盘链路:22k信号 → 组合模拟只执行' + (m.positions_taken_5slot || 0) + '笔 → 每日扫描器只挑最超跌少数候选(2026-08-02首跑仅3只)→ 人工确认建仓。22k是候选池,不是操作量。</div>' : '') +
|
||||
'</div>';
|
||||
}
|
||||
h += '</div>';
|
||||
|
||||
Reference in New Issue
Block a user