fix: 证伪标记数据驱动——strategy_research加deprecated字段,前后端从数据读(替代硬编码),strategy_router排除证伪策略

This commit is contained in:
hmo
2026-08-15 08:21:06 +08:00
parent 70687f4bf1
commit 6ad5c30ab1
3 changed files with 60 additions and 11 deletions
+11 -3
View File
@@ -26,8 +26,6 @@ sys.path.insert(0, "/home/hmo/MoFin")
OUT = Path("/home/hmo/MoFin/data/strategy_weights.json")
DEFAULT_FAMILY = "mr"
# 已证伪策略(2026-08-15 对齐前端 DEPRECATED——证伪的策略绝不激活)
DEPRECATED = {"v_mr", "v_mr_sel", "v_combo"}
FAMILY_MAP = {
"v_weak": "mr", "v_oversold": "mr", "v_mr": "mr", "v_mr2": "mr", "v_mr3": "mr",
@@ -114,10 +112,20 @@ def route(regime, temp, perf):
current_regime = regime.get("regime", "unknown")
band = temp.get("band", "unknown")
weights = {}
# 已证伪策略(从 strategy_research.deprecated 读,数据驱动——证伪绝不激活)
dep = set()
try:
import sqlite3 as _sq
_c = _sq.connect("/home/hmo/MoFin/data/mofin.db", timeout=5)
dep = {r[0] for r in _c.execute(
"SELECT DISTINCT version FROM strategy_research WHERE deprecated IS NOT NULL AND deprecated != ''")}
_c.close()
except Exception:
pass
for name, regs in perf.items():
if not regs:
continue
if name in DEPRECATED: # 已证伪策略绝不激活(2026-08-15)
if name in dep: # 已证伪策略绝不激活(数据驱动,2026-08-15
continue
cur = regs.get(current_regime)
best = max(regs.items(), key=lambda x: x[1].get("win_rate", 0))
+15
View File
@@ -567,11 +567,26 @@ def api_research_strategies():
_c.close()
except Exception:
pass
# 2026-08-15 证伪标记(数据驱动):strategy_research.deprecated
_deprecated = {}
try:
import sqlite3 as _sq2
_c2 = _sq2.connect(str(DATA_DIR / "mofin.db"), timeout=10)
for _r in _c2.execute(
"SELECT version, MAX(deprecated) FROM strategy_research "
"WHERE deprecated IS NOT NULL AND deprecated != '' GROUP BY version"
).fetchall():
_deprecated[_r[0]] = _r[1]
_c2.close()
except Exception:
pass
for s in strats:
s['description'] = STRATEGY_DESCRIPTIONS.get(s['version'], {})
s['regime_winrates'] = _regime_winrates.get(s['version'], {})
# current = 当前温区激活(替代旧的 CURRENT_VERSIONS 硬编码)
s['current'] = s['version'] in _active_set
# 2026-08-15 证伪数据驱动:从 strategy_research.deprecated 读(替代前端硬编码)
s['deprecated'] = _deprecated.get(s['version'])
# 2026-08-13 关键修复:激活策略必须始终在列表中(即使该 period 无回测记录)
# 否则 2y 等默认周期下激活策略缺失(只显示 v_oversold)。
+34 -8
View File
@@ -2263,7 +2263,7 @@ async function loadStrategyRegimeBanner() {
' · 温度: <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="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) {
@@ -2275,7 +2275,36 @@ async function loadStrategyRegimeBanner() {
} else {
h += '<span class="text-xs text-slate-500">当前温区无激活策略</span>';
}
h += '</div></div>';
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 = ''; }
}
@@ -2337,11 +2366,8 @@ function renderStrategyTable(strategies) {
// 条件格式色条:计算每列 min/max,单元格背景按相对大小画色条
const CURRENT_STRATEGY = 'v_next4';
const CURRENT_FAMILY = new Set(['v_weak', 's2_panic', 'v_next4']);
const DEPRECATED = {
'v_mr': '已证伪§12: 2018熊市依赖, 去2018后avg+2.14%/wr49.8%掷硬币, 组合回撤45%',
'v_mr_sel': '已证伪§12: 144笔中54%集中在2018-10, 单一事件依赖不可信',
'v_combo': '未采纳: 2年+47.9%但5年验证2023/24震荡转折年亏损(B动量族假突破)',
};
// 证伪标记数据驱动(2026-08-15):从 API s.deprecated 读,替代前端硬编码
const DEPRECATED = {};
const ranges = {};
const cols = ['composite','universality_score','full_return_pct','capital_final','cagr_pct','total_trades','avg_hold_days','win_rate','avg_profit_pct','sharpe_ratio','profit_factor','portfolio_max_dd_pct'];
for (const c of cols) {
@@ -2400,7 +2426,7 @@ function renderStrategyTable(strategies) {
const hasResult = st.total_trades != null;
const smallSample = hasResult && st.total_trades < 40;
const isCurrent = s.current === true;
const deprecatedReason = DEPRECATED[s.version];
const deprecatedReason = s.deprecated; // 数据驱动(2026-08-15,从API读)
// 温区展开:有 regime_winrates 则每温区一行;无则单行("整体")
const rws = s.regime_winrates || {};
const regimes = Object.keys(rws).length ? Object.keys(rws).sort() : ['overall'];