diff --git a/server.py b/server.py
index bdfafb4f..eaa4fbfe 100644
--- a/server.py
+++ b/server.py
@@ -540,9 +540,30 @@ def api_research_strategies():
from strategy_lab import list_strategies, STRATEGY_DESCRIPTIONS
pt = request.args.get('period_tag')
strats = list_strategies(period_tag=pt)
+ # 2026-08-13 温区自适应:为每个策略附加各温区表现(strategy_regime_perf)
+ # + 当前温区激活状态(regime_weights)。前端按"适应温区"展开多行。
+ _weights = _load_json(DATA_DIR / "strategy_weights.json", None) or {}
+ _active_set = set(_weights.get("active") or [])
+ _regime_winrates = {}
+ try:
+ import sqlite3 as _sq
+ _c = _sq.connect(str(DATA_DIR / "mofin.db"), timeout=10)
+ _c.execute("PRAGMA busy_timeout=10000")
+ for _r in _c.execute(
+ "SELECT strategy, regime, trades, win_rate, avg_pnl FROM strategy_regime_perf"
+ ).fetchall():
+ _regime_winrates.setdefault(_r[0], {})[_r[1]] = {
+ "trades": _r[2], "win_rate": _r[3], "avg_pnl": _r[4]
+ }
+ _c.close()
+ except Exception:
+ pass
for s in strats:
s['description'] = STRATEGY_DESCRIPTIONS.get(s['version'], {})
- return jsonify({'strategies': strats})
+ s['regime_winrates'] = _regime_winrates.get(s['version'], {})
+ # current = 当前温区激活(替代旧的 CURRENT_VERSIONS 硬编码)
+ s['current'] = s['version'] in _active_set
+ return jsonify({'strategies': strats, 'regime_active': sorted(_active_set)})
except Exception as e:
return jsonify({'error': str(e)}), 500
diff --git a/static/index.html b/static/index.html
index 049c59bb..ec773bf7 100644
--- a/static/index.html
+++ b/static/index.html
@@ -1,4 +1,4 @@
-
+
@@ -2111,9 +2111,8 @@ function renderResearch() {
if (!el) return;
el.innerHTML =
'' +
- '' +
- '' +
- '策略=版本迭代对比 · 组合=市场阶段分工方案' +
+ '📋 策略研究' +
+ '按温区自适应展开 · 每策略每温区一行 · 🟢=当前温区激活' +
'
' +
'' +
'
' +
@@ -2128,19 +2127,11 @@ function renderResearch() {
'
每版策略基于上一版归因分析迭代 · 点击行展开明细 ' +
'' +
'' +
- '' +
- '';
- // 子Tab切换
- el.querySelectorAll('.rsub-tab-btn').forEach(btn => {
- btn.onclick = () => {
- el.querySelectorAll('.rsub-tab-btn').forEach(b => { b.classList.remove('bg-slate-800', 'text-blue-400'); b.classList.add('text-slate-400'); });
- btn.classList.add('bg-slate-800', 'text-blue-400'); btn.classList.remove('text-slate-400');
- const target = btn.dataset.rtab;
- el.querySelectorAll('[id^="rsub-"]').forEach(div => div.classList.add('hidden'));
- document.getElementById('rsub-' + target).classList.remove('hidden');
- if (target === 'combo') renderResearchCombo();
- };
- });
+ '';
+ // 首次渲染即加载策略列表(无子Tab切换)
+ loadStrategyList();
+ loadEvolutionBox();
+ loadStrategyRegimeBanner();
// 恢复用户上次选择的周期(防自动刷新重置,2026-07-30老爸抓包)
const savedPt = window._btPeriodVal || '2y';
const ptSel = document.getElementById('btPeriod');
@@ -2162,6 +2153,8 @@ async function loadStrategyList() {
const resp = await fetch('/api/research/strategies?period_tag=' + pt);
const data = await resp.json();
if (data.error) { listEl.innerHTML = '' + data.error + '
'; return; }
+ // 2026-08-13 温区激活策略集合(供策略表高亮)
+ window._regimeActive = data.regime_active || [];
const mkt = document.getElementById('btMarket')?.value || 'all';
let strats = data.strategies || [];
// 市场语义:'all'=未分市场的A股回测(港股回填前跑的),'hk'=港股宇宙,'a'=显式A股
@@ -2264,274 +2257,6 @@ async function loadStrategyRegimeBanner() {
}
new MutationObserver(()=>{if(!document.getElementById('tab-research')?.classList?.contains('hidden'))loadStrategyRegimeBanner();}).observe(document.body,{attributes:true,subtree:true});
-// ══════════════════════════════════════════════════════
-// 组合方案子Tab(2026-08-02 新增)
-// 展示: 当前组合方案(v_next4趋势+v_mr超跌, regime分工) + 组合回测版本 + 组合自我进化
-// ══════════════════════════════════════════════════════
-async function renderResearchCombo() {
- const el = document.getElementById('rsub-combo');
- if (!el) return;
- el.innerHTML = '🧬 组合方案加载中...
';
- try {
- const r = await fetch('/api/evolution/combo');
- const d = await r.json();
- if (d.error) { el.innerHTML = '' + d.error + '
'; return; }
-
- let h = '';
-
- // ── 1. 当前市场阶段 + 组合方案路由卡片 ──
- const regime = d.regime || {};
- const regName = {trend_up:'📈 趋势市', choppy:'〰️ 震荡市', trend_down:'📉 下跌市'}[regime.regime] || (regime.regime || '未知');
- const regColor = regime.regime === 'trend_up' ? 'text-emerald-400' : regime.regime === 'choppy' ? 'text-amber-400' : 'text-red-400';
- h += '' +
- '
' +
- '🧬 当前组合方案' +
- '市场阶段: ' + regName + '' + (regime.adx ? ' ADX=' + regime.adx + '' : '') + '' +
- '
' +
- '
当前组合(2026-08-11):v_weak(弱市超跌确认,实盘)+ p_oversold(预测超跌反弹,新策略)+ 12维重评(持仓管理)——选股与持仓管理分离,超跌家族并行
' +
- '
';
- for (const rt of (d.routing || [])) {
- const active = regime.regime === rt.regime;
- h += '
' +
- '' + ({trend_up:'📈 趋势市', choppy:'〰️ 震荡市', trend_down:'📉 下跌市'}[rt.regime] || rt.regime) + '' +
- '' + rt.active + '' +
- '' + rt.action + ' · ' + rt.desc + '' +
- (active ? '当前生效' : '') +
- '
';
- }
- h += '
';
-
- // ── 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 += '' +
- '
' +
- '🌡️ 温区自适应 · 当前激活' +
- '平滑温区: ' + regName + '' +
- ' · 温度: ' + bandIcon + ' ' + bandName + '' +
- (rw.temp_rsi ? ' RSI=' + rw.temp_rsi + '' : '') +
- (rw.state_date ? ' (' + rw.state_date + ')' : '') + '' +
- '
' +
- '
策略全温区发信号,适用温区由实测胜率动态决定(strategy_regime_perf);组合按当前温区自动激活,选股/买卖/重评已温区感知
' +
- '
';
- 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 += '' +
- '' + n + ' ' + wr + ' ✓';
- }
- } else {
- h += '当前温区无激活策略';
- }
- h += '
';
- // 观察中策略(权重<0.5 或未匹配)
- const obsList = allList.filter(([k,v]) => !v.matched).slice(0, 8);
- if (obsList.length) {
- h += '
' + obsList.map(([k,v]) =>
- '' +
- '' + k + ' ' + (v.best_win_rate != null ? v.best_win_rate + '%' : '') + ' 观察'
- ).join('') + '
';
- }
- h += '
';
- }
-
- // ── 2. 组合成员策略指标 ──
- const members = d.members || {};
- if (Object.keys(members).length) {
- h += '成员策略(10年回测,组合收益已扣费)
' +
- '';
- for (const [v, m] of Object.entries(members)) {
- const u = m.universality || {};
- const yearly5 = m.positions_taken_5slot && m.positions_taken_5slot > 0 ? Math.round(m.positions_taken_5slot / 10) : '—';
- h += '
' +
- '
' + v + (m.is_sel ? ' ✅推荐' : '') + '' +
- '' + (m.role || '') + '
' +
- // 盈利率大字突出(用户关注的核心指标)
- '
' +
- '
单笔均收益(毛利)
' + (m.avg_profit_pct != null ? m.avg_profit_pct + '%' : '—') + '
' +
- '
组合年化(扣费)
' + (m.cagr_pct != null ? m.cagr_pct + '%' : '—') + '
' +
- '
组合10年收益
' + (m.return_pct != null ? m.return_pct + '%' : '—') + '
' +
- '
' +
- '
' +
- '
胜率
' + (m.win_rate != null ? m.win_rate + '%' : '—') + '
' +
- '
信号总数
' + (m.trades != null ? (m.trades > 999 ? Math.round(m.trades/1000) + 'k' : m.trades) : '—') + '
' +
- '
组合执行
' + (m.positions_taken_5slot != null ? m.positions_taken_5slot + '笔' : '—') + '
' +
- '
覆盖月
' + (u.months || '—') + '
' +
- '
' +
- '
均持' + (m.avg_hold_days != null ? m.avg_hold_days + '天' : '—') + ' · 回撤' + (m.max_dd_pct != null ? m.max_dd_pct + '%' : '—') + ' · 组合年均' + yearly5 + '笔(人工可操作)
' +
- (v === 'v_next4' ? '
⚠️ 适用池:系统跟踪池(267只,科创板/沪市为主)——2026-08-04验证:v_next4全部历史回测跑在跟踪池上(当时stock_daily未全市场扩表),全市场复跑失效(wr 35.9%/组合-34.3%)。edge=池子策展×v8.1评分×信念叠乘,不可外推全市场。实盘范围=跟踪池,池内数字有效。
' : '') +
- (v === 'v_mr' ? '
✅ v_weak 弱市策略(2026-08-03 六步方法论+12维框架定稿):大盘弱市(MA20下)+ADX∈[25,30]甜区 + 个股bias60∈[-35,-20]深超跌 + RSI≤25极度超卖 + 5日急跌确认;出场tp30%/sl12%/40日。回测:234笔/单笔avg+7.17%/胜率62.4%/去2018仍+8.02%/正贡献8/11年/组合8槽收益178.3%/年化12.8%/回撤16.4%(每月≤30信号,等权8槽,收益/回撤比10.9)。关键认知:弱市深超跌反弹的edge前提=大盘ADX∈[25,30](v_mr 缺失的大盘前置条件),负面剔除(过深/RSI偏高/阴跌)比正面排序更有效。
' : '') +
- '
';
- }
- h += '
';
- }
-
- // ── 3. 组合回测版本列表 ──
- const combos = d.combos || [];
- h += '组合方案版本(回测记录)
';
- if (combos.length) {
- h += '' +
- '| 版本 | 名称 | ' +
- '区间 | 执行数 | ' +
- '胜率 | 平均收益 | ' +
- '年化 | 回撤 | ' +
- '普适 |
';
- for (const c of combos) {
- const st = c.summary_stats || {};
- const pf = st.portfolio_full || {};
- const u = st.universality || {};
- const name = c.version === 'v_combo' ? 'v8.1波段+B20动量' : c.version;
- h += '' +
- '| ' + c.version + ' | ' +
- '' + name + ' | ' +
- '' + (c.period_tag || '') + ' | ' +
- '' + ((pf.positions_taken || 0)) + '/' + (st.total_trades != null ? (st.total_trades > 999 ? Math.round(st.total_trades/1000) + 'k' : st.total_trades) : '—') + ' | ' +
- '' + (st.win_rate != null ? st.win_rate + '%' : '—') + ' | ' +
- '' + (st.avg_profit_pct != null ? st.avg_profit_pct + '%' : '—') + ' | ' +
- '' + (pf.cagr_pct != null ? pf.cagr_pct + '%' : '—') + ' | ' +
- '' + (pf.portfolio_max_dd_pct != null ? pf.portfolio_max_dd_pct + '%' : '—') + ' | ' +
- '' + (u.score != null ? u.score + '/' + (u.months || 0) + '月' : '—') + ' | ' +
- '
';
- }
- h += '
';
- h += '⚠️ v_combo 为历史组合实验:2年+47.9%但5年验证2023/24震荡转折年亏损(B动量族假突破),未采纳——当前组合采用 v_next4+v_mr regime 分工方案
';
- } else {
- h += '暂无组合回测记录
';
- }
-
- // ── 4. 组合自我进化 ──
- h += '' +
- '
🧬 组合方案自我进化
' +
- '
组合方案 = 策略分工路由(regime → 策略),进化方向:
' +
- '
' +
- '- ① 市场阶段判定参数(MA20/ADX 阈值)随实盘验证迭代
' +
- '- ② 各成员策略独立进化(v_next4 参数迭代见策略Tab)
' +
- '- ③ 组合权重/接管时机按回测与实盘偏差调优
' +
- '
' +
- '
📌 组合级进化记录待接入:当前进化系统只跟踪单策略(strategy_evolution 表),组合路由的自动调优需要新的 evolution 数据表。
' +
- '
';
-
- el.innerHTML = h;
- } catch(e) {
- el.innerHTML = '组合方案加载失败: ' + e.message + '
';
- }
-}
-
-function showDesc(version) {
- const s = (window._strats || []).find(x => x.version === version);
- const d = s && s.description;
- if (!d || !d.title) { showToast('暂无说明'); return; }
- const modal = document.createElement('div');
- modal.className = 'fixed inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-sm';
- modal.onclick = () => modal.remove();
- modal.innerHTML = `
- `;
- document.body.appendChild(modal);
-}
-function showConviction(version) {
- const s = (window._strats || []).find(x => x.version === version);
- const st = (s && s.summary_stats) || {};
- const model = st.conviction_model;
- if (!model) { showToast('该策略无信念分级仓位'); return; }
- const slots = st.sizing_slots || 10;
- const isStack = model.includes('叠乘');
- // boost分布(从trades统计在前端没有, 用summary里的说明)
- const rules = isStack ? [
- ['动量基因 DNA', '收缩突破形态(ATR处20日最低1/4位+破20日新高+量比>1.2)', '×2'],
- ['行业确认牛', '行业板块ADX>25(行业级趋势强化)', '×2'],
- ['资金加速度', 'flow_delta>0(主力资金净流入在加速)', '×2'],
- ] : [
- ['动量基因 DNA', '收缩突破形态(ATR处20日最低1/4位+破20日新高+量比>1.2)', '任一命中 ×2'],
- ['行业趋势强', '行业板块ADX≥20', '任一命中 ×2'],
- ['资金加速度', 'flow_delta>0(主力资金净流入在加速)', '任一命中 ×2'],
- ];
- const modal = document.createElement('div');
- modal.className = 'fixed inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-sm';
- modal.onclick = () => modal.remove();
- modal.innerHTML = `
-
-
-
⚡ 信念分级仓位
-
-
-
-
${model}
-
基准 ${slots} 仓(总资金分${slots}份,每份一票)。命中信念因子的票按规则放大单票仓位:
- ${rules.map(r => `
-
${r[0]}
-
${r[1]}
-
${r[2]}
-
`).join('')}
-
${isStack ? '多个因子同时命中则叠乘(如 DNA+行业牛 = ×4),封顶 ×4;均不命中 ×1(基准仓)。' : '多个因子同时命中不叠乘,统一 ×2;均不命中 ×1(基准仓)。'}
-
-
`;
- document.body.appendChild(modal);
-}
-function showToast(msg) {
- const t = document.createElement('div');
- t.className = 'fixed top-4 right-4 z-50 bg-slate-800 border border-slate-600 rounded-lg px-4 py-2 text-sm text-slate-200 shadow-lg';
- t.textContent = msg;
- document.body.appendChild(t);
- setTimeout(() => t.remove(), 2000);
-}
-
-function sortBy(key) {
- if (window._sortKey === key) {
- window._sortDir = window._sortDir === 'desc' ? 'asc' : 'desc';
- } else {
- window._sortKey = key;
- window._sortDir = ASC_DEFAULT.has(key) ? 'asc' : 'desc';
- }
- renderStrategyTable(window._strats || []);
-}
-
-function sortStrategies(strategies, key, dir) {
- const get = (s) => {
- const st = s.summary_stats || {}; const pf = st.portfolio || {};
- switch(key) {
- case 'version': return s.version || '';
- case 'name': return s.name || '';
- case 'sizing_slots': return st.sizing_slots || 10;
- case 'composite': return s._composite != null ? s._composite : -999;
- case 'universality': return (st.universality || {}).score || 0;
- case 'total_return': return pf.total_return_pct != null ? pf.total_return_pct : -999;
- case 'full_return': return (st.portfolio_full || {}).total_return_pct != null ? st.portfolio_full.total_return_pct : -999;
- case 'capital_final': return (st.portfolio_full || pf).capital_final || 0;
- case 'cagr': return (st.portfolio_full || pf).cagr_pct != null ? (st.portfolio_full || pf).cagr_pct : -999;
- case 'trades': return st.total_trades || 0;
- case 'hold': return st.avg_hold_days || 0;
- case 'win_rate': return st.win_rate != null ? st.win_rate : -999;
- case 'avg_profit': return st.avg_profit_pct != null ? st.avg_profit_pct : -999;
- case 'sharpe': return st.sharpe_ratio != null ? st.sharpe_ratio : -999;
- case 'profit_factor': return st.profit_factor != null ? st.profit_factor : -999;
- case 'max_dd': return (st.portfolio_full || pf).portfolio_max_dd_pct != null ? (st.portfolio_full || pf).portfolio_max_dd_pct : 999;
- default: return 0;
- }
- };
- const arr = [...strategies];
- arr.sort((a, b) => {
- const va = get(a), vb = get(b);
- let cmp = (typeof va === 'string') ? va.localeCompare(vb) : va - vb;
- return dir === 'desc' ? -cmp : cmp;
- });
- return arr;
-}
-
function renderStrategyTable(strategies) {
const el = document.getElementById('strategyList');
if (!strategies.length) { el.innerHTML = '暂无策略版本
'; return; }
@@ -2623,12 +2348,14 @@ function renderStrategyTable(strategies) {
const arrow = window._sortKey === key ? (window._sortDir === 'desc' ? '▼' : '▲') : '';
return `${label}${arrow ? ' ' + arrow : ''} | `;
};
- // 2026-08-11 新增:拆分当前/历史区域(老莫需求)
- // 当前 = current=true(实盘/新策略);历史 = 其余,默认折叠
+ // 2026-08-13 温区自适应:按"适应温区"展开——每策略每温区一行
+ // 当前 = 当前温区激活(后端 s.current 已改为 regime_weights.active 判断);历史 = 其余,默认折叠
const currentStrats = strategies.filter(s => s.current === true);
const historyStrats = strategies.filter(s => s.current !== true);
+ const REGIME_META = {trend_up:{icon:'📈',name:'趋势市'}, choppy:{icon:'〰️',name:'震荡市'}, trend_down:{icon:'📉',name:'下跌市'}};
const renderGroup = (groupStrats, groupTitle, groupIcon, collapsed) => {
let ghtml = '' +
+ '| 适应温区 | ' +
th('version', '版本', 'text-left') + th('name', '名称', 'text-left') +
th('sizing_slots', '仓位', 'text-center') +
'说明 | ' +
@@ -2650,27 +2377,47 @@ function renderStrategyTable(strategies) {
const smallSample = hasResult && st.total_trades < 40;
const isCurrent = s.current === true;
const deprecatedReason = DEPRECATED[s.version];
- const rowCls = 'border-b border-slate-800/50 hover:bg-slate-800/30 cursor-pointer' + (isCurrent ? ' bg-emerald-900/20 border-l-2 border-l-emerald-400' : '');
- ghtml += '
' +
- '| ' + s.version + (isCurrent ? ' 当前' : '') + (deprecatedReason ? ' 已证伪' : '') + ((s.market && s.market !== 'all') ? ' ' + (s.market === 'hk' ? '港' : 'A') + '' : '') + ' | ' +
- '' + (s.name || '') + (smallSample ? ' ⚠️' : '') + ' | ' +
- '' + (st.sizing_slots ? st.sizing_slots + '仓' : '10仓') + (st.conviction_model ? '' : '') + ' | ' +
- '' + ((s.description && s.description.title) ? '' : '—') + ' | ' +
- cell('composite', s._composite, v => v + (s._confidence != null && s._confidence < 1 ? '×' + s._confidence.toFixed(2) + '' : ''), 'font-bold text-amber-300') +
- cell('universality_score', (st.universality || {}).score, v => v + '/' + (st.universality || {}).months + '月') +
- cell('full_return_pct', (st.portfolio_full || {}).total_return_pct, v => v + '%' + ((st.portfolio_full||{}).std ? '±' + (st.portfolio_full||{}).std + '' : ''), 'font-bold text-amber-300') +
- cell('capital_final', (st.portfolio_full||pf).capital_final, v => '¥' + (v/10000).toFixed(0) + '万') +
- cell('cagr_pct', (st.portfolio_full||pf).cagr_pct, v => v + '%', hl((st.portfolio_full||pf).cagr_pct, best.cagr_pct)) +
- cell('total_trades', st.total_trades, v => ((st.portfolio_full||{}).positions_taken ?? (pf.positions_taken||0)) + '/' + (v > 999 ? Math.round(v/1000) + 'k' : v), '', false) +
- cell('avg_hold_days', st.avg_hold_days, v => v + 'd') +
- cell('win_rate', st.win_rate, v => v + '%', hl(st.win_rate, best.win_rate)) +
- cell('avg_profit_pct', st.avg_profit_pct, v => v + '%', (st.avg_profit_pct || 0) >= 0 ? 'text-green-400' : 'text-red-400') +
- cell('sharpe_ratio', st.sharpe_ratio, v => v, hl(st.sharpe_ratio, best.sharpe_ratio)) +
- cell('profit_factor', st.profit_factor, v => v, hl(st.profit_factor, best.profit_factor)) +
- cell('portfolio_max_dd_pct', (st.portfolio_full||pf).portfolio_max_dd_pct, v => v + '%', hl((st.portfolio_full||pf).portfolio_max_dd_pct, best.portfolio_max_dd_pct, true), true) +
- '' +
- '' +
- ' |
';
+ // 温区展开:有 regime_winrates 则每温区一行;无则单行("整体")
+ const rws = s.regime_winrates || {};
+ const regimes = Object.keys(rws).length ? Object.keys(rws).sort() : ['overall'];
+ for (const rg of regimes) {
+ const rw = rws[rg];
+ const isOverall = rg === 'overall';
+ const rgMeta = REGIME_META[rg] || {icon:'🌐', name: rg === 'overall' ? '整体' : rg};
+ const rgActive = !isOverall && isCurrent && (window._regimeActive || []).includes(s.version);
+ // 温区行数据:该温区胜率/均盈/样本(有则覆盖,无则用整体)
+ const wrShow = rw && rw.win_rate != null ? rw.win_rate : (isOverall ? st.win_rate : null);
+ const pnlShow = rw && rw.avg_pnl != null ? rw.avg_pnl : (isOverall ? st.avg_profit_pct : null);
+ const tradesShow = rw && rw.trades != null ? rw.trades : (isOverall ? st.total_trades : null);
+ const rowCls = 'border-b border-slate-800/50 hover:bg-slate-800/30 cursor-pointer' + (isCurrent && !isOverall ? ' bg-emerald-900/20 border-l-2 border-l-emerald-400' : '');
+ ghtml += '' +
+ '| ' +
+ (isOverall ? '整体' :
+ '' + rgMeta.icon + ' ' + rgMeta.name + '') +
+ (rw && rw.win_rate != null ? ' 胜率' + rw.win_rate + '%' : '') +
+ (rw && rw.avg_pnl != null ? ' ' + (rw.avg_pnl >= 0 ? '+' : '') + rw.avg_pnl + '%' : '') +
+ (rw && rw.trades != null ? ' ' + rw.trades + '笔' : '') +
+ ' | ' +
+ '' + s.version + (isCurrent ? ' 激活' : '') + (deprecatedReason ? ' 已证伪' : '') + ((s.market && s.market !== 'all') ? ' ' + (s.market === 'hk' ? '港' : 'A') + '' : '') + ' | ' +
+ '' + (s.name || '') + (smallSample ? ' ⚠️' : '') + ' | ' +
+ '' + (st.sizing_slots ? st.sizing_slots + '仓' : '10仓') + (st.conviction_model ? '' : '') + ' | ' +
+ '' + ((s.description && s.description.title) ? '' : '—') + ' | ' +
+ cell('composite', s._composite, v => v + (s._confidence != null && s._confidence < 1 ? '×' + s._confidence.toFixed(2) + '' : ''), 'font-bold text-amber-300') +
+ cell('universality_score', (st.universality || {}).score, v => v + '/' + (st.universality || {}).months + '月') +
+ cell('full_return_pct', (st.portfolio_full || {}).total_return_pct, v => v + '%' + ((st.portfolio_full||{}).std ? '±' + (st.portfolio_full||{}).std + '' : ''), 'font-bold text-amber-300') +
+ cell('capital_final', (st.portfolio_full||pf).capital_final, v => '¥' + (v/10000).toFixed(0) + '万') +
+ cell('cagr_pct', (st.portfolio_full||pf).cagr_pct, v => v + '%', hl((st.portfolio_full||pf).cagr_pct, best.cagr_pct)) +
+ cell('total_trades', tradesShow, v => (v > 999 ? Math.round(v/1000) + 'k' : v) + (isOverall ? '' : ''), '', false) +
+ cell('avg_hold_days', st.avg_hold_days, v => v + 'd') +
+ cell('win_rate', wrShow, v => v + '%', (isOverall ? hl(wrShow, best.win_rate) : (wrShow >= 50 ? 'text-green-400' : 'text-red-400'))) +
+ cell('avg_profit_pct', pnlShow, v => v + '%', (pnlShow || 0) >= 0 ? 'text-green-400' : 'text-red-400') +
+ cell('sharpe_ratio', st.sharpe_ratio, v => v, hl(st.sharpe_ratio, best.sharpe_ratio)) +
+ cell('profit_factor', st.profit_factor, v => v, hl(st.profit_factor, best.profit_factor)) +
+ cell('portfolio_max_dd_pct', (st.portfolio_full||pf).portfolio_max_dd_pct, v => v + '%', hl((st.portfolio_full||pf).portfolio_max_dd_pct, best.portfolio_max_dd_pct, true), true) +
+ '' +
+ '' +
+ ' |
';
+ }
}
ghtml += '
';
return ghtml;
@@ -2679,7 +2426,7 @@ function renderStrategyTable(strategies) {
let html = '';
if (currentStrats.length) {
html += '' +
- '
🟢 当前使用(' + currentStrats.length + '个)
' +
+ '
🟢 当前温区激活(' + currentStrats.length + '个)
' +
renderGroup(currentStrats, '当前', '🟢', false) +
'
';
}