diff --git a/static/index.html b/static/index.html
index d13e942d..63a37fe5 100644
--- a/static/index.html
+++ b/static/index.html
@@ -2595,7 +2595,8 @@ function renderStrategyTable(strategies) {
(rw && rw.trades != null ? ' ' + rw.trades + '笔' : '') +
'' +
'
' + s.version + (rgActive ? ' 激活' : '') + (s.state === 'available' && !rgActive ? ' 可用' : '') + (deprecatedReason ? ' 已证伪' : '') + ((s.market && s.market !== 'all') ? ' ' + (s.market === 'hk' ? '港' : 'A') + '' : '') + ' | ' +
- '' + (s.name || '') + (smallSample ? ' ⚠️' : '') + ' | ' +
+ '' + (s.name || '') + (smallSample ? ' ⚠️' : '') + ' ' +
+ (rGrade ? '' + GRADE_STD[rGrade].label + '' : '') + ' | ' +
'' + (st.sizing_slots ? st.sizing_slots + '仓' : '10仓') + (st.conviction_model ? '' : '') + ' | ' +
'' + ((s.description && s.description.title) ? '' : '—') + ' | ' +
cell('composite', compositeShow, v => v + (s._confidence != null && s._confidence < 1 ? '×' + s._confidence.toFixed(2) + '' : ''), 'font-bold text-amber-300') +
@@ -2623,6 +2624,29 @@ function renderStrategyTable(strategies) {
// ── 2026-08-15 按温区分组:当前温区激活区块改为温区优先(当前温区排最前高亮),
// 每个温区下列出所有在该温区有数据的策略(按该温区胜率降序)──
const REGIME_ORDER = ['trend_up', 'choppy', 'trend_down'];
+
+ // ── 2026-08-17 策略评分分级(老莫):基于资格叉数 + 综合分排名 ──
+ // 不合格=≥2个叉 / 待观察=1个叉 / 合格/良好/优秀=3勾+综合分区间
+ const GRADE_STD = {
+ poor: {label: '不合格', cls: 'bg-red-500/20 text-red-300', need: '叉≥2'},
+ watch: {label: '待观察', cls: 'bg-amber-500/20 text-amber-300', need: '叉=1'},
+ ok: {label: '合格', cls: 'bg-slate-500/20 text-slate-300', need: '3勾+综合60-74'},
+ good: {label: '良好', cls: 'bg-emerald-500/25 text-emerald-200', need: '3勾+综合75-84'},
+ great: {label: '优秀', cls: 'bg-emerald-400/30 text-emerald-100', need: '3勾+综合≥85'},
+ };
+ const gradeOf = (qg, comp) => {
+ if (!qg) return null;
+ const ok3 = qg.long_ok && qg.mid_ok && qg.short_ok;
+ const xCount = [qg.long_ok, qg.mid_ok, qg.short_ok].filter(x => !x).length;
+ if (!ok3) {
+ if (xCount >= 2) return 'poor';
+ if (xCount === 1) return 'watch';
+ return null;
+ }
+ if (comp >= 85) return 'great';
+ if (comp >= 75) return 'good';
+ return 'ok';
+ };
const renderRegimeRow = (s, rg) => {
// 2026-08-15 行级激活按策略自身(后端已按所属市场温区算好 s.current),不再按表格 isCur
const rw = (s.regime_winrates || {})[rg] || {};
@@ -2660,15 +2684,27 @@ function renderStrategyTable(strategies) {
const r3 = rLong && rMid && rShort; // 三项全过
const rNearOk = rMid || rShort; // 近期有亮点(含长期不过但近期过:❌❌✅/❌✅✅)
const rManual = s.manual_available !== false;
- let rState, rStateCls, rStateBadge, rRowBg;
- if (!rManual) { rState = 'manual_off'; rStateCls = 'text-slate-500'; rStateBadge = '手动停用'; rRowBg = 'opacity-50'; }
- else if (r3) { rState = 'ok3'; rStateCls = 'text-emerald-400'; rStateBadge = (s.current === true) ? '已激活' : '可激活'; rRowBg = 'bg-emerald-900/10'; }
- else if (rNearOk) { rState = 'ok2'; rStateCls = 'text-blue-400'; rStateBadge = '可用'; rRowBg = ''; }
- else { rState = 'bad'; rStateCls = 'text-red-400/80'; rStateBadge = '不合格'; rRowBg = 'opacity-60'; }
- const isActive = rState === 'ok3';
+ // ── 2026-08-17 状态与评分分离(老莫):
+ // 状态 = 已激活(current=true,实盘跑)/未激活(current=false,不跑)
+ // 评分 = 不合格(≥2叉)/待观察(1叉)/合格/良好/优秀(3勾+综合分区间)
+ const rGrade = gradeOf(qg, comp);
+ let rStateCls, rStateBadge, rRowBg;
+ if (!rManual) { rStateCls = 'text-slate-500'; rStateBadge = '手动停用'; rRowBg = 'opacity-50'; }
+ else if (s.current === true) {
+ rStateCls = 'text-emerald-400';
+ rStateBadge = '已激活';
+ rRowBg = 'bg-emerald-900/15';
+ } else {
+ rStateCls = 'text-blue-400';
+ rStateBadge = '未激活';
+ rRowBg = '';
+ }
+ const rGradeBadge = rGrade && rGrade !== 'ok' && rGrade !== 'good' && rGrade !== 'great' ? '' : '';
+ const isActive = s.current === true;
return '' +
'| ' + s.version + ' ' + rStateBadge + ((s.market && s.market !== 'all') ? ' ' + (s.market === 'hk' ? '港' : 'A') + '' : '') + ' | ' +
- '' + (s.name || '') + (smallSample ? ' ⚠️' : '') + ' | ' +
+ '' + (s.name || '') + (smallSample ? ' ⚠️' : '') + ' ' +
+ (rGrade ? '' + GRADE_STD[rGrade].label + '' : '') + ' | ' +
// 2026-08-16 资格列:长期/近期/当下 三项达标徽章
'' + (s.qualification && s.qualification[rg] ? (
'' + (s.qualification[rg].long_ok ? '✅' : '❌') + '' +
@@ -2724,7 +2760,11 @@ function renderStrategyTable(strategies) {
const rn = rw.trades || 0;
const rm = rw.universality ? (rw.universality.months || 0) : 0;
const rconf = Math.min(1, rn / 40) * (rm > 0 ? Math.min(1, rm / 6) : 1);
- return Math.round((ret + w + sh + pfc + dd) * rconf);
+ // 2026-08-17 效率惩罚(与 renderRegimeRow 一致)——否则排序分≠显示分,排名错乱
+ const _sig = rn, _pos = rw.positions_taken || 0;
+ const _ratio = _pos > 0 ? _sig / _pos : 99;
+ const _eff = _ratio <= 2 ? 1.0 : _ratio <= 5 ? 0.9 : _ratio <= 10 ? 0.75 : 0.5;
+ return Math.round((ret + w + sh + pfc + dd) * rconf * _eff);
}
case 'universality': return (rw.universality || {}).score || 0;
case 'max_dd': return pf.portfolio_max_dd_pct != null ? pf.portfolio_max_dd_pct : 999;
@@ -2762,9 +2802,38 @@ function renderStrategyTable(strategies) {
th('hold', '均持仓', 'text-right', '平均持仓天数', 'hold') + th('cagr', '年化', 'text-right', '年化收益率', 'cagr') + th('composite', '综合', 'text-right', '多维度综合评分', 'composite') +
th('sharpe', '夏普', 'text-right', '每单位波动超额收益', 'sharpe') + th('profit_factor', '盈亏比', 'text-right', '总盈利/总亏损', 'profit_factor') +
th('universality', '普适', 'text-right', '跨独立年份有效性(非特例)', 'universality') + th('max_dd', '回撤', 'text-right', '组合模拟最大回撤', 'max_dd') +
- ' | 操作 |
' +
- metas.map(s => renderRegimeRow(s, rg)).join('') +
- '';
+ '操作 | ' +
+ // ── 2026-08-17 分区(老莫):上区=已激活,下区=备选(资格达标未激活),默认折叠 ──
+ (() => {
+ const active = metas.filter(s => s.current === true);
+ const backup = metas.filter(s => s.current !== true);
+ let html = '';
+ if (active.length) {
+ html += '| ✅ 已激活 (' + active.length + ') |
';
+ html += active.map(s => renderRegimeRow(s, rg)).join('');
+ }
+ if (backup.length) {
+ html += '| ' +
+ ' |
';
+ html += '' +
+ '' +
+ '' + backup.map(s => renderRegimeRow(s, rg)).join('') + ' ' +
+ ' |
';
+ }
+ html += '';
+ return html;
+ })();
+ };
+ // ── 2026-08-17 备选区展开/折叠(老莫)──
+ window.toggleBackup = function(key) {
+ const body = document.getElementById('bk-body-' + key);
+ const arrow = document.getElementById('bk-arrow-' + key);
+ if (body) {
+ const hidden = body.classList.contains('hidden');
+ body.classList.toggle('hidden');
+ if (arrow) arrow.textContent = hidden ? '▼' : '▶';
+ }
};
// ── 2026-08-15 按市场×温区展示:6表格 = A股当前市 → 港股当前市 → A股其他2市 → 港股其他2市,
// 每表格列出该市场在该温区有数据的所有可用策略(含未激活,按该温区胜率降序),激活策略高亮;温度并入当前市标题尾部