feat: 策略加best_regime(适应温区)字段+淘汰判定改用适应温区2y/10y年化都<0→历史

This commit is contained in:
xxm
2026-08-15 23:42:44 +08:00
parent db9f41ce50
commit b1ede2747e
+43 -13
View File
@@ -661,6 +661,34 @@ def api_research_strategies():
except Exception:
pass
_candidate_pool |= set(_regime_winrates.keys())
# ── 2026-08-15 适应温区(best_regime):weights 优先,缺失从温区数据推断(2y最高胜率温区)──
_best_regime_map = {}
try:
for _v, _w in (_weights.get("weights") or {}).items():
_br = _w.get("best_regime")
if _br:
_best_regime_map[_v] = _br
except Exception:
pass
# 推断缺失的(港股/历史策略)
try:
import sqlite3 as _sqb
_cb = _sqb.connect(str(DATA_DIR / "mofin.db"), timeout=10)
for _v, _rws in _regime_winrates.items():
if _v in _best_regime_map or not _rws:
continue
_best_br = None
_best_wr = -1
for _reg, _rw in _rws.items():
_wr = _rw.get("win_rate")
if _wr is not None and _wr > _best_wr:
_best_wr = _wr
_best_br = _reg
if _best_br:
_best_regime_map[_v] = _best_br
_cb.close()
except Exception:
pass
for s in strats:
# 2026-08-15 温区加权综合/普适:整体行的综合/普适 = 按温区时长占比加权各温区表现
# (业务逻辑:策略只在特定温区激活,评估应该限定在温区范围才值得参考)
@@ -715,6 +743,8 @@ def api_research_strategies():
s['regime_winrates'] = _regime_winrates.get(s['version'], {})
# current = 当前温区激活(替代旧的 CURRENT_VERSIONS 硬编码)
s['current'] = s['version'] in _active_set
# 2026-08-15 适应温区(前端方案A:策略只在适应温区表显示一行)
s['best_regime'] = _best_regime_map.get(s['version'])
# 2026-08-15 证伪数据驱动:从 strategy_research.deprecated 读(替代前端硬编码)
s['deprecated'] = _deprecated.get(s['version'])
# 2026-08-15 三状态(派生,不存储):激活/可用未激活/不可用
@@ -725,27 +755,27 @@ def api_research_strategies():
s['state'] = 'unavailable'
s['state_reason'] = '已证伪: ' + str(s['deprecated'])[:80]
elif s['version'] in _candidate_pool:
# ── 2026-08-15 无价值淘汰:2y+10y 温区年化都跑不赢大盘 → 历史 ──
# 只在 2y/10y 请求时判定;用当次数据(2y) + 缓存(10y),避免额外重算
# ── 2026-08-15 无价值淘汰:适应温区(best_regime) 2y+10y 年化都<0 → 历史 ──
# (老莫逻辑:温区表数据对应适应温区;适应温区都亏的策略无价值)
_elim_reason = None
try:
_b2, _b10 = _get_benchmarks()
if _b2 is not None and _b10 is not None:
# 读表拿 2y/10y 温区数据(毫秒级,数据加工层预计算)
_br_v = s.get('best_regime')
if _br_v:
_r2 = _compute_regime_winrates_cached('2y', _approx_regime_universality)
_r10 = _compute_regime_winrates_cached('10y', _approx_regime_universality)
_v2 = _r2.get(s['version']) or {}
_v10 = _r10.get(s['version']) or {}
if _v2 and _v10:
_best2 = max(r.get('cagr_pct') or -999 for r in _v2.values())
_best10 = max(r.get('cagr_pct') or -999 for r in _v10.values())
if _best2 < _b2 and _best10 < _b10:
_elim_reason = f'2y年化{round(_best2,1)}%<大盘{_b2}% 且 10y年化{round(_best10,1)}%<大盘{_b10}%'
_rw2 = (_r2.get(s['version']) or {}).get(_br_v)
_rw10 = (_r10.get(s['version']) or {}).get(_br_v)
if _rw2 and _rw10:
_c2 = _rw2.get('cagr_pct')
_c10 = _rw10.get('cagr_pct')
if _c2 is not None and _c10 is not None and _c2 < 0 and _c10 < 0:
_elim_reason = (f'适应温区[{_br_v}] 2y年化{round(_c2,1)}%<0 '
f'且 10y年化{round(_c10,1)}%<0')
except Exception:
_elim_reason = None
if _elim_reason:
s['state'] = 'unavailable'
s['state_reason'] = '跑不赢大盘已淘汰: ' + _elim_reason
s['state_reason'] = '适应温区亏损已淘汰: ' + _elim_reason
else:
s['state'] = 'available'
s['state_reason'] = '候选池内,当前温区未激活(温区切换即可激活)'