feat: 策略列表改6表格——A股/港股当前市排前(温度并入标题尾部),其余温区全量可用策略按胜率降序,取消横幅
This commit is contained in:
+60
-119
@@ -2137,11 +2137,10 @@ function renderResearch() {
|
||||
'<div class="flex gap-2 items-center mb-3">' +
|
||||
'<span class="text-sm font-semibold text-slate-300">📋 策略研究</span>' +
|
||||
'<span class="spec-btns"><span class="spec-btn help" onclick="showModuleHelp(\'strategy\',\'human\')">?</span><span class="spec-btn ai" onclick="showModuleHelp(\'strategy\',\'ai\')">§</span></span>' +
|
||||
'<span class="text-xs text-slate-500">按温区分组 · 每策略每温区一行 · 🟢=当前温区激活</span>' +
|
||||
'<span class="text-xs text-slate-500">按市场×温区分组 · 每表格=该市该温区所有可用策略 · 🟢=当前市激活 · 温度=当前温区</span>' +
|
||||
'</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">' +
|
||||
@@ -2157,7 +2156,6 @@ function renderResearch() {
|
||||
// 2026-08-15 修复:不能在此直接 loadStrategyList()——此时 btPeriod.value 还是初始默认 '1m',
|
||||
// 与下方恢复 savedPt='2y' 后的调用并发竞态,1m 响应后到会覆盖 2y 渲染(周期错乱+综合分被小样本置信打崩)。
|
||||
loadEvolutionBox();
|
||||
loadStrategyRegimeBanner();
|
||||
// 恢复用户上次选择的周期(防自动刷新重置,2026-07-30老爸抓包)
|
||||
const savedPt = window._btPeriodVal || '2y';
|
||||
const ptSel = document.getElementById('btPeriod');
|
||||
@@ -2176,12 +2174,20 @@ async function loadStrategyList() {
|
||||
try {
|
||||
const ptMap = {'1m':'1m','6m':'6m','1y':'1y','2y':'2y','5y':'5y','10y':'10y'};
|
||||
const pt = ptMap[window._btPeriodVal || document.getElementById('btPeriod')?.value || '2y'] || '2y';
|
||||
const resp = await fetch('/api/research/strategies?period_tag=' + pt);
|
||||
const [resp, ovResp] = await Promise.all([
|
||||
fetch('/api/research/strategies?period_tag=' + pt),
|
||||
fetch('/api/overview').catch(() => null)
|
||||
]);
|
||||
const data = await resp.json();
|
||||
if (data.error) { listEl.innerHTML = '<div class="text-red-400">' + data.error + '</div>'; return; }
|
||||
// 2026-08-13 温区激活策略集合(供策略表高亮)
|
||||
// 2026-08-15 温区信息并入策略表(横幅取消):A股/港股温区状态+温度,供6表格当前市高亮与温度展示
|
||||
const ov = ovResp ? await ovResp.json().catch(() => null) : null;
|
||||
const rw = (ov && ov.regime_weights) || null;
|
||||
window._regimeA = rw && rw.state ? {state: rw.state, temp_band: rw.temp_band, temp_rsi: rw.temp_rsi} : null;
|
||||
const hkR = rw && rw.markets && rw.markets.hk;
|
||||
window._regimeHK = hkR && hkR.state ? {state: hkR.state, temp_band: hkR.temp_band} : null;
|
||||
window._regimeActive = data.regime_active || [];
|
||||
window._regimeState = data.regime_state || 'unknown';
|
||||
window._regimeState = (rw && rw.state) || data.regime_state || 'unknown';
|
||||
const mkt = document.getElementById('btMarket')?.value || 'all';
|
||||
let strats = data.strategies || [];
|
||||
// 市场语义:'all'=未分市场的A股回测(港股回填前跑的),'hk'=港股宇宙,'a'=显式A股
|
||||
@@ -2245,73 +2251,6 @@ 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">A股以下策略在当前温区激活(适用温区由实测胜率动态决定):</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>';
|
||||
// ── 港股温区(2026-08-14,与A股分别呈现)──
|
||||
try {
|
||||
const hk = rw.markets && rw.markets.hk;
|
||||
if (hk && hk.state) {
|
||||
const hkIcon = {trend_up:'📈', choppy:'〰️', trend_down:'📉'}[hk.state] || '🌐';
|
||||
const hkName = {trend_up:'趋势市', choppy:'震荡市', trend_down:'下跌市'}[hk.state] || hk.state;
|
||||
const hkColor = hk.state==='trend_up' ? 'text-emerald-400' : hk.state==='choppy' ? 'text-amber-400' : 'text-red-400';
|
||||
const hkActive = (hk.active || []).slice(0, 8);
|
||||
h += '<div class="border-t border-sky-500/20 mt-2.5 pt-2.5">' +
|
||||
'<div class="flex items-center justify-between flex-wrap gap-2 mb-1.5">' +
|
||||
'<span class="text-sm font-semibold text-sky-300">🇭🇰 港股温区</span>' +
|
||||
'<span class="text-sm">' + hkIcon + ' <span class="font-bold ' + hkColor + '">' + hkName + '</span>' +
|
||||
(hk.state_date ? ' <span class="text-slate-500 text-xs">(' + hk.state_date + ')</span>' : '') +
|
||||
(hk.temp_band ? ' · <b>' + hk.temp_band + '</b>' : '') + '</span>' +
|
||||
'</div>' +
|
||||
'<div class="text-xs text-slate-400 mb-1.5">港股激活策略(按港股温区独立调度):</div>' +
|
||||
'<div class="flex flex-wrap gap-1.5">';
|
||||
if (hkActive.length) {
|
||||
for (const n of hkActive) {
|
||||
h += '<span class="text-xs bg-sky-500/15 text-sky-300 border border-sky-500/30 rounded px-2 py-0.5">' +
|
||||
'<span class="font-mono font-bold">' + n + '</span></span>';
|
||||
}
|
||||
} else {
|
||||
h += '<span class="text-xs text-slate-500">当前港股温区无激活策略</span>';
|
||||
}
|
||||
h += '</div></div>';
|
||||
}
|
||||
} catch(e) {}
|
||||
h += '</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});
|
||||
|
||||
function renderStrategyTable(strategies) {
|
||||
const el = document.getElementById('strategyList');
|
||||
@@ -2403,9 +2342,6 @@ function renderStrategyTable(strategies) {
|
||||
};
|
||||
// 2026-08-13 温区自适应:按"适应温区"展开——每策略每温区一行
|
||||
// 当前 = 当前温区激活(后端 s.current 已改为 regime_weights.active 判断);历史 = 其余,默认折叠
|
||||
const currentStrats = strategies.filter(s => s.current === true);
|
||||
const availableStrats = strategies.filter(s => s.current !== true && s.state === 'available');
|
||||
const unavailableStrats = strategies.filter(s => s.current !== true && s.state !== 'available');
|
||||
const REGIME_META = {trend_up:{icon:'📈',name:'趋势市'}, choppy:{icon:'〰️',name:'震荡市'}, trend_down:{icon:'📉',name:'下跌市'}};
|
||||
const renderGroup = (groupStrats, groupTitle, groupIcon, collapsed) => {
|
||||
let ghtml = '<div class="overflow-x-auto"><table class="w-full text-xs whitespace-nowrap"><thead><tr class="text-slate-500 border-b border-slate-700">' +
|
||||
@@ -2502,7 +2438,8 @@ function renderStrategyTable(strategies) {
|
||||
// ── 2026-08-15 按温区分组:当前温区激活区块改为温区优先(当前温区排最前高亮),
|
||||
// 每个温区下列出所有在该温区有数据的策略(按该温区胜率降序)──
|
||||
const REGIME_ORDER = ['trend_up', 'choppy', 'trend_down'];
|
||||
const renderRegimeRow = (s, rg, isCur) => {
|
||||
const renderRegimeRow = (s, rg) => {
|
||||
// 2026-08-15 行级激活按策略自身(后端已按所属市场温区算好 s.current),不再按表格 isCur
|
||||
const rw = (s.regime_winrates || {})[rg] || {};
|
||||
const rwPf = rw.portfolio || null;
|
||||
const wr = rw.win_rate != null ? rw.win_rate : null;
|
||||
@@ -2527,8 +2464,9 @@ function renderStrategyTable(strategies) {
|
||||
const ddV = rwPf ? rwPf.portfolio_max_dd_pct : null;
|
||||
const univ = rw.universality ? rw.universality.score : null;
|
||||
const univM = rw.universality ? (rw.universality.months + '/' + (rw.universality.regime_total_months || '?')) : null;
|
||||
return '<tr class="border-b border-slate-800/50 hover:bg-slate-800/30 cursor-pointer' + (isCur ? ' bg-emerald-900/10' : '') + '" onclick="showStrategyDetail(\'' + s.version + '\')">' +
|
||||
'<td class="px-2 py-1.5 font-mono font-bold ' + (isCur ? 'text-emerald-400' : 'text-blue-400') + '">' + s.version + (isCur ? ' <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>' +
|
||||
const isActive = s.current === true;
|
||||
return '<tr class="border-b border-slate-800/50 hover:bg-slate-800/30 cursor-pointer' + (isActive ? ' bg-emerald-900/10' : '') + '" onclick="showStrategyDetail(\'' + s.version + '\')">' +
|
||||
'<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>' +
|
||||
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') +
|
||||
@@ -2540,47 +2478,50 @@ function renderStrategyTable(strategies) {
|
||||
cell('portfolio_max_dd_pct', ddV, v => v + '%', '') +
|
||||
'<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 renderGroupByRegime = (strats, currentRegime) => {
|
||||
const order = [currentRegime, ...REGIME_ORDER.filter(r => r !== currentRegime)];
|
||||
let g = '';
|
||||
for (const rg of order) {
|
||||
const metas = strats
|
||||
.filter(s => (s.regime_winrates || {})[rg] && (s.regime_winrates || {})[rg].trades != null)
|
||||
.sort((x, y) => ((y.regime_winrates || {})[rg].win_rate || -1) - ((x.regime_winrates || {})[rg].win_rate || -1));
|
||||
if (!metas.length) continue;
|
||||
const isCur = rg === currentRegime;
|
||||
const meta = REGIME_META[rg] || {icon: '🌐', name: rg};
|
||||
g += '<div class="mb-3 rounded-lg border ' + (isCur ? 'border-emerald-700/60 bg-emerald-900/10' : 'border-slate-700') + '">' +
|
||||
'<div class="flex items-center gap-2 px-3 py-1.5 text-sm ' + (isCur ? 'text-emerald-300' : 'text-slate-400') + '">' +
|
||||
meta.icon + ' ' + meta.name + (isCur ? ' <span class="text-[10px] bg-emerald-500/20 text-emerald-300 px-1 rounded">当前温区</span>' : '') +
|
||||
'<span class="text-xs text-slate-500">(' + metas.length + '个策略)</span>' +
|
||||
'<span class="text-[10px] text-slate-600">' + (isCur ? '当前温区匹配即激活' : '该温区下有数据(参考)') + '</span></div>' +
|
||||
'<div class="overflow-x-auto"><table class="w-full text-xs whitespace-nowrap"><thead><tr class="text-slate-500 border-b border-slate-700">' +
|
||||
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('universality', '普适', 'text-right') + th('max_dd', '回撤', 'text-right') +
|
||||
'<th class="text-center px-2 py-1.5">操作</th></tr></thead><tbody>' +
|
||||
metas.map(s => renderRegimeRow(s, rg, isCur)).join('') +
|
||||
'</tbody></table></div></div>';
|
||||
}
|
||||
return g;
|
||||
const renderRegimeTable = (strats, rg, isCur, marketLabel, tempHtml) => {
|
||||
// 2026-08-15 单温区表格:该市场在该温区有数据的所有可用策略(按该温区胜率降序),激活策略高亮
|
||||
const metas = strats
|
||||
.filter(s => (s.regime_winrates || {})[rg] && (s.regime_winrates || {})[rg].trades != null)
|
||||
.sort((x, y) => ((y.regime_winrates || {})[rg].win_rate || -1) - ((x.regime_winrates || {})[rg].win_rate || -1));
|
||||
if (!metas.length) return '';
|
||||
const meta = REGIME_META[rg] || {icon: '🌐', name: rg};
|
||||
return '<div class="mb-3 rounded-lg border ' + (isCur ? 'border-emerald-700/60 bg-emerald-900/10' : 'border-slate-700') + '">' +
|
||||
'<div class="flex items-center gap-2 px-3 py-1.5 text-sm ' + (isCur ? 'text-emerald-300' : 'text-slate-400') + '">' +
|
||||
marketLabel + ' · ' + meta.icon + ' ' + meta.name + (isCur ? ' <span class="text-[10px] bg-emerald-500/20 text-emerald-300 px-1 rounded">当前温区</span>' : '') + (tempHtml || '') +
|
||||
'<span class="text-xs text-slate-500">(' + metas.length + '个策略)</span>' +
|
||||
'<span class="text-[10px] text-slate-600">' + (isCur ? '当前温区匹配即激活' : '该温区下有数据(参考)') + '</span></div>' +
|
||||
'<div class="overflow-x-auto"><table class="w-full text-xs whitespace-nowrap"><thead><tr class="text-slate-500 border-b border-slate-700">' +
|
||||
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('universality', '普适', 'text-right') + th('max_dd', '回撤', 'text-right') +
|
||||
'<th class="text-center px-2 py-1.5">操作</th></tr></thead><tbody>' +
|
||||
metas.map(s => renderRegimeRow(s, rg)).join('') +
|
||||
'</tbody></table></div></div>';
|
||||
};
|
||||
// ── 2026-08-15 按市场×温区展示:6表格 = A股当前市 → 港股当前市 → A股其他2市 → 港股其他2市,
|
||||
// 每表格列出该市场在该温区有数据的所有可用策略(含未激活,按该温区胜率降序),激活策略高亮;温度并入当前市标题尾部
|
||||
const usableStrats = strategies.filter(s => s.current === true || s.state === 'available');
|
||||
const unavailableStrats = strategies.filter(s => s.current !== true && s.state !== 'available');
|
||||
const aStrats = usableStrats.filter(s => (s.market || 'all') !== 'hk');
|
||||
const hkStrats = usableStrats.filter(s => (s.market || 'all') === 'hk');
|
||||
const regA = window._regimeA || null;
|
||||
const regHK = window._regimeHK || null;
|
||||
const aCur = regA && regA.state;
|
||||
const hkCur = regHK && regHK.state;
|
||||
const tempHtml = (reg, hasRsi) => {
|
||||
if (!reg || !reg.temp_band) return '';
|
||||
const bandIcon = {panic:'🔴', fear:'🟠', neutral:'🟡', greed:'🟢', euphoria:'🔵'}[reg.temp_band] || '⚪';
|
||||
const bandName = {panic:'恐慌', fear:'偏冷', neutral:'中性', greed:'偏热', euphoria:'亢奋'}[reg.temp_band] || reg.temp_band;
|
||||
return ' · 温度: <b>' + bandIcon + ' ' + bandName + '</b>' + (hasRsi && reg.temp_rsi ? ' <span class="text-slate-500 text-xs">RSI=' + reg.temp_rsi + '</span>' : '');
|
||||
};
|
||||
// 当前区域(展开)+ 历史区域(默认折叠)
|
||||
let html = '';
|
||||
if (currentStrats.length) {
|
||||
html += '<div class="mb-4">' +
|
||||
'<div class="flex items-center gap-2 mb-2"><span class="text-sm font-semibold text-emerald-400">🟢 当前温区激活</span><span class="text-xs text-slate-500">(' + currentStrats.length + '个) · 按温区分组 · 当前温区排最前高亮</span></div>' +
|
||||
renderGroupByRegime(currentStrats, window._regimeState) +
|
||||
'</div>';
|
||||
}
|
||||
if (availableStrats.length) {
|
||||
html += '<div class="mb-4">' +
|
||||
'<button class="w-full flex items-center justify-between px-3 py-2 bg-slate-800/50 hover:bg-slate-800 rounded-lg border border-slate-700 text-sm" onclick="this.nextElementSibling.classList.toggle(\'hidden\'); this.querySelector(\'span\').textContent = this.nextElementSibling.classList.contains(\'hidden\') ? \'▶\' : \'▼\'">' +
|
||||
'<span class="text-blue-300">🔵 可用未激活</span><span class="text-slate-500 text-xs">(' + availableStrats.length + '个)</span><span class="text-slate-500">▶</span></button>' +
|
||||
'<div class="hidden mt-2">' + renderGroup(availableStrats, '可用', '🔵', true) + '</div>' +
|
||||
'</div>';
|
||||
}
|
||||
// 头两个:A股当前市 + 港股当前市(标题尾部带温度)
|
||||
if (aCur) html += renderRegimeTable(aStrats, aCur, true, '🇨🇳 A股', tempHtml(regA, true));
|
||||
if (hkCur) html += renderRegimeTable(hkStrats, hkCur, true, '🇭🇰 港股', tempHtml(regHK, false));
|
||||
// 后四个:A股其他2市 + 港股其他2市
|
||||
for (const rg of REGIME_ORDER) if (rg !== aCur) html += renderRegimeTable(aStrats, rg, false, '🇨🇳 A股', '');
|
||||
for (const rg of REGIME_ORDER) if (rg !== hkCur) html += renderRegimeTable(hkStrats, rg, false, '🇭🇰 港股', '');
|
||||
if (unavailableStrats.length) {
|
||||
html += '<div class="mb-4 opacity-70">' +
|
||||
'<button class="w-full flex items-center justify-between px-3 py-2 bg-slate-800/50 hover:bg-slate-800 rounded-lg border border-slate-700 text-sm" onclick="this.nextElementSibling.classList.toggle(\'hidden\'); this.querySelector(\'span\').textContent = this.nextElementSibling.classList.contains(\'hidden\') ? \'▶\' : \'▼\'">' +
|
||||
@@ -2588,7 +2529,7 @@ function renderStrategyTable(strategies) {
|
||||
'<div class="hidden mt-2">' + renderGroup(unavailableStrats, '不可用', '📚', true) + '</div>' +
|
||||
'</div>';
|
||||
}
|
||||
if (!currentStrats.length && !availableStrats.length && !unavailableStrats.length) {
|
||||
if (!usableStrats.length && !unavailableStrats.length) {
|
||||
html = '<div class="text-slate-500">暂无策略版本</div>';
|
||||
}
|
||||
html += '<div class="text-xs text-slate-600 mt-2">总收益/最终资产 = 100万本金·最多10等分仓位·24个月组合模拟 · ⚠️样本<40笔 · 绿色=该列最优 · 悬停名称查看改进假设</div>';
|
||||
|
||||
Reference in New Issue
Block a user