diff --git a/static/index.html b/static/index.html
index a8c8cfbd..34a53f89 100644
--- a/static/index.html
+++ b/static/index.html
@@ -2193,6 +2193,15 @@ async function loadStrategyList() {
// 市场语义:'all'=未分市场的A股回测(港股回填前跑的),'hk'=港股宇宙,'a'=显式A股
if (mkt === 'hk') strats = strats.filter(s => (s.market || 'all') === 'hk');
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;
+ }
+ }
renderStrategyTable(strats);
} catch(e) {
listEl.innerHTML = '
加载失败: ' + e.message + '
';
@@ -2509,6 +2518,19 @@ function renderStrategyTable(strategies) {
return '' +
'| ' + s.version + (isActive ? ' 激活' : '') + ((s.market && s.market !== 'all') ? ' ' + (s.market === 'hk' ? '港' : 'A') + '' : '') + ' | ' +
'' + (s.name || '') + (smallSample ? ' ⚠️' : '') + ' | ' +
+ // 2026-08-16 资格列:长期/近期/当下 三项达标徽章
+ '' + (s.qualification ? (
+ '' + (s.qualification.long_ok ? '✅' : '❌') + '' +
+ '' + (s.qualification.mid_ok ? '✅' : '❌') + '' +
+ '' + (s.qualification.short_ok ? '✅' : '❌') + ''
+ ) : '—') +
+ (s.qual_warning ? ' ' + s.qual_warning + ' ' : '') +
+ ' | ' +
+ // 2026-08-16 可用性开关(手动把关)
+ '' +
+ '' +
+ ' | ' +
cell('win_rate', wr, v => v + '%', wr != null && wr >= 50 ? 'text-green-400' : 'text-red-400') +
cell('avg_profit_pct', pnl, v => v + '%', (pnl || 0) >= 0 ? 'text-green-400' : 'text-red-400') +
cell('total_trades', tr, v => v, '', false) +
@@ -2521,6 +2543,30 @@ function renderStrategyTable(strategies) {
cell('portfolio_max_dd_pct', ddV, v => v + '%', '') +
' |
';
};
+ // 2026-08-16 手动可用性:切换单个策略(激活只能是可用的策略)
+ async function toggleAvail(version, checked) {
+ try {
+ await fetch('/api/research/availability', {
+ method: 'POST', headers: {'Content-Type': 'application/json'},
+ body: JSON.stringify({version: version, available: checked, note: '手动切换'})
+ });
+ loadStrategyList(); // 刷新(state 可能变化)
+ } catch(e) { console.error('toggleAvail failed', e); }
+ }
+ // 2026-08-16 批量设置可用性(当前温区表全部)
+ async function batchAvail(rg, available) {
+ const list = (window._strats || [])
+ .filter(s => s.best_regime === rg && (s.market || 'all') !== 'hk')
+ .map(s => s.version);
+ if (!list.length) return;
+ try {
+ await fetch('/api/research/availability?batch=1', {
+ method: 'POST', headers: {'Content-Type': 'application/json'},
+ body: JSON.stringify({versions: list, available: available, note: '批量' + (available ? '可用' : '不可用')})
+ });
+ loadStrategyList();
+ } catch(e) { console.error('batchAvail failed', e); }
+ }
const renderRegimeTable = (strats, rg, isCur, marketLabel, tempHtml) => {
// 2026-08-15 方案A:策略只在适应温区(best_regime)表显示一行——所有列都是该策略在适应温区的数据
// 2026-08-16 温区感知排序:尊重 window._sortKey(点列头排序),字段从 regime_winrates[rg] 取
@@ -2572,9 +2618,17 @@ function renderStrategyTable(strategies) {
'' +
marketLabel + ' · ' + meta.icon + ' ' + meta.name + (isCur ? ' 当前温区' : '') + (tempHtml || '') +
'(' + metas.length + '个策略)' +
- '' + (isCur ? '当前温区匹配即激活' : '策略适应温区(best_regime)') + '
' +
+ '' + (isCur ? '当前温区匹配即激活' : '策略适应温区(best_regime)') + '' +
+ '大盘基准: 1y' + (window._bench1y != null ? window._bench1y + '%' : '?') +
+ ' 2y' + (window._bench2y != null ? window._bench2y + '%' : '?') +
+ ' 10y' + (window._bench10y != null ? window._bench10y + '%' : '?') + '' +
+ '' +
+ '' +
+ '' +
'' +
th('version', '版本', 'text-left') + th('name', '名称', 'text-left') +
+ '| 资格 | ' +
+ '可用 | ' +
th('win_rate', '胜率', 'text-right') + th('avg_profit', '平均收益', 'text-right') + th('trades', '笔数', 'text-right') +
th('hold', '均持仓', 'text-right') + th('cagr', '年化', 'text-right') + th('composite', '综合', 'text-right') +
th('sharpe', '夏普', 'text-right') + th('profit_factor', '盈亏比', 'text-right') +