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') +
资格可用