From 581ad0ea61c99ccec14550f80cf54c548284b43b Mon Sep 17 00:00:00 2001 From: xxm Date: Sun, 16 Aug 2026 08:47:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20qualification=E6=94=B9per-regime(?= =?UTF-8?q?=E7=AD=96=E7=95=A5=E5=8F=AF=E9=80=82=E5=BA=94=E5=A4=9A=E6=B8=A9?= =?UTF-8?q?=E5=8C=BA)+=E6=BF=80=E6=B4=BB=E7=94=A8=E5=BD=93=E5=89=8D?= =?UTF-8?q?=E6=B8=A9=E5=8C=BA=E5=88=A4=E5=AE=9A,=E6=9B=BF=E4=BB=A3?= =?UTF-8?q?=E5=8D=95best=5Fregime=E9=99=90=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/server.py b/server.py index 8c670801..619b3ca1 100644 --- a/server.py +++ b/server.py @@ -648,7 +648,7 @@ def api_research_strategies(): # 2026-08-16 资格评估 + 手动可用性(标准A:长期10y/近期2y/当下1y 适应温区年化>大盘) try: sys.path.insert(0, "/home/hmo/MoFin/deploy/profile-scripts") - from strategy_qualify import get_benchmarks as _qbench, evaluate_strategy as _qeval, is_available as _qavail, load_availability as _qload + from strategy_qualify import get_benchmarks as _qbench, evaluate_all_regimes as _qeval, is_available as _qavail, load_availability as _qload except Exception: _qbench = _qeval = _qavail = _qload = None _qbench_data = _qbench() if _qbench else {} @@ -795,28 +795,29 @@ def api_research_strategies(): s['current'] = s['version'] in _active_set # 2026-08-15 适应温区(前端方案A:策略只在适应温区表显示一行) s['best_regime'] = _best_regime_map.get(s['version']) - # 2026-08-16 资格评估(标准A:长期10y/近期2y/当下1y 适应温区年化>大盘) - _qual = _qeval(s['version'], (s.get('market') or 'a') if (s.get('market') or 'a') != 'all' else 'a', - best_regime=s.get('best_regime'), bench=_qbench_data) if _qeval else None - if _qual: - s['qualification'] = { - 'long_ok': _qual.get('long_ok'), 'mid_ok': _qual.get('mid_ok'), - 'short_ok': _qual.get('short_ok'), - 'cagr_10y': _qual.get('cagr_10y'), 'cagr_2y': _qual.get('cagr_2y'), - 'cagr_1y': _qual.get('cagr_1y'), + # 2026-08-16 资格评估(标准A)——per-regime,策略可适应多个温区 + _mkt_v = (s.get('market') or 'a') if (s.get('market') or 'a') != 'all' else 'a' + _quals = _qeval(s['version'], _mkt_v, bench=_qbench_data) if _qeval else {} + s['qualification'] = {} + for _rg, _q in _quals.items(): + s['qualification'][_rg] = { + 'long_ok': _q.get('long_ok'), 'mid_ok': _q.get('mid_ok'), + 'short_ok': _q.get('short_ok'), + 'cagr_10y': _q.get('cagr_10y'), 'cagr_2y': _q.get('cagr_2y'), + 'cagr_1y': _q.get('cagr_1y'), 'bench_10y': _qbench_data.get('10y'), 'bench_2y': _qbench_data.get('2y'), 'bench_1y': _qbench_data.get('1y'), } - else: - s['qualification'] = None + # 当前温区资格(激活判定用) + _cur_regime_q = (s.get('qualification') or {}).get(_weights.get('state') or '') + _l_ok = bool(_cur_regime_q and _cur_regime_q.get('long_ok')) + _m_ok = bool(_cur_regime_q and _cur_regime_q.get('mid_ok')) + _s_ok = bool(_cur_regime_q and _cur_regime_q.get('short_ok')) # 2026-08-16 手动可用性(老莫把关):激活只能是可用的策略 s['manual_available'] = _qavail(s['version']) if _qavail else True # 2026-08-15 证伪数据驱动:从 strategy_research.deprecated 读(替代前端硬编码) s['deprecated'] = _deprecated.get(s['version']) - # ── 2026-08-16 三状态(派生):激活=当前温区+手动可用+三项达标;可用=手动可用+长期近期过 ── - _l_ok = bool(_qual and _qual.get('long_ok')) - _m_ok = bool(_qual and _qual.get('mid_ok')) - _s_ok = bool(_qual and _qual.get('short_ok')) + _qual_ok_3 = _l_ok and _m_ok and _s_ok _qual_ok_2 = _l_ok and _m_ok if s['version'] in _active_set: