feat: 研究Tab两个子Tab加温区横幅——策略子Tab(顶部当前市场温区+激活策略) + 组合子Tab(Section1.5温区自适应+激活/观察策略列表), 数据源/api/overview regime_weights

This commit is contained in:
hmo
2026-08-13 11:08:41 +08:00
parent dec30896c3
commit c013e35ca3
+79
View File
@@ -2117,6 +2117,7 @@ function renderResearch() {
'</div>' +
'<div id="rsub-strategy">' +
'<div id="evo-box" class="mb-3 bg-slate-800/60 border border-slate-700 rounded-lg p-3"><div class="text-xs text-slate-500">🧬 进化模块加载中...</div></div>' +
'<div id="strategyRegimeBanner" class="mb-3"></div>' +
'<div class="flex gap-2 items-center mb-3 flex-wrap">' +
'<h2 class="text-lg font-bold">📋 策略研究 — 版本迭代对比</h2>' +
'<select id="btPeriod" onchange="saveBtPeriod()" class="bg-slate-800 text-sm rounded-lg px-2 py-1 border border-slate-700">' +
@@ -2224,6 +2225,45 @@ async function loadEvolutionBox() {
// 研究Tab活跃时加载进化模块
new MutationObserver(()=>{if(!document.getElementById('tab-research')?.classList?.contains('hidden'))loadEvolutionBox();}).observe(document.body,{attributes:true,subtree:true});
// ── 策略子Tab 温区横幅(2026-08-13)──
async function loadStrategyRegimeBanner() {
const box = document.getElementById('strategyRegimeBanner');
if (!box) return;
try {
const d = await fetchJSON('/api/overview');
const rw = d.regime_weights || null;
if (!rw || !rw.state) { box.innerHTML = ''; return; }
const regIcon = {trend_up:'📈', choppy:'〰️', trend_down:'📉'}[rw.state] || '🌐';
const regName = {trend_up:'趋势市', choppy:'震荡市', trend_down:'下跌市'}[rw.state] || rw.state;
const regColor = rw.state==='trend_up' ? 'text-emerald-400' : rw.state==='choppy' ? 'text-amber-400' : 'text-red-400';
const bandIcon = {panic:'🔴', fear:'🟠', neutral:'🟡', greed:'🟢', euphoria:'🔵'}[rw.temp_band] || '⚪';
const bandName = {panic:'恐慌', fear:'偏冷', neutral:'中性', greed:'偏热', euphoria:'亢奋'}[rw.temp_band] || rw.temp_band;
const activeList = (rw.active || []).slice(0, 8);
let h = '<div class="bg-indigo-900/25 border border-indigo-500/40 rounded-lg p-3">' +
'<div class="flex items-center justify-between flex-wrap gap-2 mb-2">' +
'<span class="text-sm font-semibold text-indigo-300">🌡️ 当前市场温区</span>' +
'<span class="text-sm">' + regIcon + ' <span class="font-bold ' + regColor + '">' + regName + '</span>' +
' · 温度: <b>' + bandIcon + ' ' + bandName + '</b>' +
(rw.temp_rsi ? ' <span class="text-slate-500 text-xs">RSI=' + rw.temp_rsi + '</span>' : '') + '</span>' +
'</div>' +
'<div class="text-xs text-slate-400 mb-1.5">以下策略在当前温区激活(适用温区由实测胜率动态决定):</div>' +
'<div class="flex flex-wrap gap-1.5">';
if (activeList.length) {
for (const n of activeList) {
const w = rw.weights && rw.weights[n];
const wr = w && w.best_win_rate != null ? w.best_win_rate + '%' : '';
h += '<span class="text-xs bg-emerald-500/15 text-emerald-300 border border-emerald-500/30 rounded px-2 py-0.5">' +
'<span class="font-mono font-bold">' + n + '</span> ' + wr + '</span>';
}
} else {
h += '<span class="text-xs text-slate-500">当前温区无激活策略</span>';
}
h += '</div></div>';
box.innerHTML = h;
} catch(e) { box.innerHTML = ''; }
}
new MutationObserver(()=>{if(!document.getElementById('tab-research')?.classList?.contains('hidden'))loadStrategyRegimeBanner();}).observe(document.body,{attributes:true,subtree:true});
// ══════════════════════════════════════════════════════
// 组合方案子Tab2026-08-02 新增)
// 展示: 当前组合方案(v_next4趋势+v_mr超跌, regime分工) + 组合回测版本 + 组合自我进化
@@ -2261,6 +2301,45 @@ async function renderResearchCombo() {
}
h += '</div></div>';
// ── 1.5 温区自适应横幅(2026-08-13)──
const rw = d.regime_weights || null;
if (rw && rw.state) {
const bandIcon = {panic:'🔴', fear:'🟠', neutral:'🟡', greed:'🟢', euphoria:'🔵'}[rw.temp_band] || '⚪';
const bandName = {panic:'恐慌', fear:'偏冷', neutral:'中性', greed:'偏热', euphoria:'亢奋'}[rw.temp_band] || rw.temp_band;
const activeList = (rw.active || []).slice(0, 10);
const allList = Object.entries(rw.weights || {});
h += '<div class="bg-indigo-900/25 border border-indigo-500/40 rounded-lg p-3 mb-3">' +
'<div class="flex items-center justify-between flex-wrap gap-2 mb-2">' +
'<span class="text-sm font-semibold text-indigo-300">🌡️ 温区自适应 · 当前激活</span>' +
'<span class="text-sm">平滑温区: <span class="font-bold ' + regColor + '">' + regName + '</span>' +
' · 温度: <b>' + bandIcon + ' ' + bandName + '</b>' +
(rw.temp_rsi ? ' <span class="text-slate-500 text-xs">RSI=' + rw.temp_rsi + '</span>' : '') +
(rw.state_date ? ' <span class="text-slate-600 text-xs">(' + rw.state_date + ')</span>' : '') + '</span>' +
'</div>' +
'<div class="text-xs text-slate-400 mb-2">策略全温区发信号,适用温区由实测胜率动态决定(strategy_regime_perf);组合按当前温区自动激活,选股/买卖/重评已温区感知</div>' +
'<div class="flex flex-wrap gap-1.5 mb-2">';
if (activeList.length) {
for (const n of activeList) {
const w = rw.weights && rw.weights[n];
const wr = w && w.best_win_rate != null ? w.best_win_rate + '%' : '';
h += '<span class="text-xs bg-emerald-500/15 text-emerald-300 border border-emerald-500/30 rounded px-2 py-0.5">' +
'<span class="font-mono font-bold">' + n + '</span> ' + wr + ' <span class="text-emerald-500/70">✓</span></span>';
}
} else {
h += '<span class="text-xs text-slate-500">当前温区无激活策略</span>';
}
h += '</div>';
// 观察中策略(权重<0.5 或未匹配)
const obsList = allList.filter(([k,v]) => !v.matched).slice(0, 8);
if (obsList.length) {
h += '<div class="flex flex-wrap gap-1.5">' + obsList.map(([k,v]) =>
'<span class="text-[11px] bg-slate-800 text-slate-500 border border-slate-700 rounded px-2 py-0.5">' +
'<span class="font-mono">' + k + '</span> ' + (v.best_win_rate != null ? v.best_win_rate + '%' : '') + ' 观察</span>'
).join('') + '</div>';
}
h += '</div>';
}
// ── 2. 组合成员策略指标 ──
const members = d.members || {};
if (Object.keys(members).length) {