feat: 前端温区表过滤改qualification[rg]——策略在它达标的每个温区表显示(多温区适应),资格徽章/基准适配per-regime
This commit is contained in:
+16
-13
@@ -2195,11 +2195,14 @@ async function loadStrategyList() {
|
||||
else if (mkt === 'a') strats = strats.filter(s => (s.market || 'all') !== 'hk');
|
||||
// 2026-08-16 大盘基准(从任一策略 qualification 提取,供温区表头显示)
|
||||
for (const s of strats) {
|
||||
if (s.qualification && s.qualification.bench_1y != null) {
|
||||
window._bench1y = s.qualification.bench_1y;
|
||||
window._bench2y = s.qualification.bench_2y;
|
||||
window._bench10y = s.qualification.bench_10y;
|
||||
break;
|
||||
if (s.qualification) {
|
||||
const anyQ = Object.values(s.qualification)[0];
|
||||
if (anyQ && anyQ.bench_1y != null) {
|
||||
window._bench1y = anyQ.bench_1y;
|
||||
window._bench2y = anyQ.bench_2y;
|
||||
window._bench10y = anyQ.bench_10y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
renderStrategyTable(strats);
|
||||
@@ -2314,7 +2317,7 @@ async function toggleAvail(version, checked) {
|
||||
}
|
||||
async function batchAvail(rg, available) {
|
||||
const list = (window._strats || [])
|
||||
.filter(s => s.best_regime === rg && (s.market || 'all') !== 'hk')
|
||||
.filter(s => s.qualification && s.qualification[rg] && (s.market || 'all') !== 'hk')
|
||||
.map(s => s.version);
|
||||
if (!list.length) return;
|
||||
try {
|
||||
@@ -2543,10 +2546,10 @@ function renderStrategyTable(strategies) {
|
||||
'<td class="px-2 py-1.5 font-mono font-bold ' + (isActive ? 'text-emerald-400' : 'text-blue-400') + '">' + s.version + (isActive ? ' <span class="text-[10px] bg-emerald-500/20 text-emerald-300 px-1 rounded">激活</span>' : '') + ((s.market && s.market !== 'all') ? ' <span class="text-[10px] bg-cyan-500/20 text-cyan-300 px-1 rounded">' + (s.market === 'hk' ? '港' : 'A') + '</span>' : '') + '</td>' +
|
||||
'<td class="px-2 py-1.5 whitespace-normal break-words" title="' + (s.hypothesis || s.summary || '').replace(/"/g, '"') + '">' + (s.name || '') + (smallSample ? ' <span class="text-amber-500" title="样本<40笔">⚠️</span>' : '') + '</td>' +
|
||||
// 2026-08-16 资格列:长期/近期/当下 三项达标徽章
|
||||
'<td class="text-center px-1 py-1.5 whitespace-nowrap" onclick="event.stopPropagation()">' + (s.qualification ? (
|
||||
'<span title="长期10y年化' + (s.qualification.cagr_10y != null ? s.qualification.cagr_10y + '%' : '?') + ' vs 大盘' + (s.qualification.bench_10y != null ? s.qualification.bench_10y + '%' : '?') + '">' + (s.qualification.long_ok ? '✅' : '❌') + '</span>' +
|
||||
'<span title="近期2y年化' + (s.qualification.cagr_2y != null ? s.qualification.cagr_2y + '%' : '?') + ' vs 大盘' + (s.qualification.bench_2y != null ? s.qualification.bench_2y + '%' : '?') + '">' + (s.qualification.mid_ok ? '✅' : '❌') + '</span>' +
|
||||
'<span title="当下1y年化' + (s.qualification.cagr_1y != null ? s.qualification.cagr_1y + '%' : '?') + ' vs 大盘' + (s.qualification.bench_1y != null ? s.qualification.bench_1y + '%' : '?') + '">' + (s.qualification.short_ok ? '✅' : '❌') + '</span>'
|
||||
'<td class="text-center px-1 py-1.5 whitespace-nowrap" onclick="event.stopPropagation()">' + (s.qualification && s.qualification[rg] ? (
|
||||
'<span title="长期10y年化' + (s.qualification[rg].cagr_10y != null ? s.qualification[rg].cagr_10y + '%' : '?') + ' vs 大盘' + (s.qualification[rg].bench_10y != null ? s.qualification[rg].bench_10y + '%' : '?') + '">' + (s.qualification[rg].long_ok ? '✅' : '❌') + '</span>' +
|
||||
'<span title="近期2y年化' + (s.qualification[rg].cagr_2y != null ? s.qualification[rg].cagr_2y + '%' : '?') + ' vs 大盘' + (s.qualification[rg].bench_2y != null ? s.qualification[rg].bench_2y + '%' : '?') + '">' + (s.qualification[rg].mid_ok ? '✅' : '❌') + '</span>' +
|
||||
'<span title="当下1y年化' + (s.qualification[rg].cagr_1y != null ? s.qualification[rg].cagr_1y + '%' : '?') + ' vs 大盘' + (s.qualification[rg].bench_1y != null ? s.qualification[rg].bench_1y + '%' : '?') + '">' + (s.qualification[rg].short_ok ? '✅' : '❌') + '</span>'
|
||||
) : '<span class="text-slate-600">—</span>') +
|
||||
(s.qual_warning ? '<div class="text-[9px] ' + (s.qual_warning.indexOf('回升') >= 0 ? 'text-green-400' : 'text-amber-400') + '">' + s.qual_warning + '</div>' : '') +
|
||||
'</td>' +
|
||||
@@ -2568,10 +2571,10 @@ function renderStrategyTable(strategies) {
|
||||
'<td class="text-center px-2 py-1.5" onclick="event.stopPropagation()"><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>';
|
||||
};
|
||||
const renderRegimeTable = (strats, rg, isCur, marketLabel, tempHtml) => {
|
||||
// 2026-08-15 方案A:策略只在适应温区(best_regime)表显示一行——所有列都是该策略在适应温区的数据
|
||||
// 2026-08-16 温区感知排序:尊重 window._sortKey(点列头排序),字段从 regime_winrates[rg] 取
|
||||
// 2026-08-16 温区表显示该温区下【资格达标】的策略(qualification[rg] 存在 = 有10y数据+长期合格)
|
||||
// 策略可适应多个温区:在它达标的每个温区表都显示一行(不再局限单个 best_regime)
|
||||
const metas = strats
|
||||
.filter(s => s.best_regime === rg && (s.regime_winrates || {})[rg] && (s.regime_winrates || {})[rg].trades != null);
|
||||
.filter(s => s.qualification && s.qualification[rg] && (s.regime_winrates || {})[rg] && (s.regime_winrates || {})[rg].trades != null);
|
||||
const regimeGet = (s, key) => {
|
||||
const rw = (s.regime_winrates || {})[rg] || {};
|
||||
const pf = rw.portfolio || {};
|
||||
|
||||
Reference in New Issue
Block a user