From ca08969a8d899f6f1238c8e83dfae69694a026f6 Mon Sep 17 00:00:00 2001 From: xxm Date: Tue, 18 Aug 2026 01:25:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=BF=80=E6=B4=BB=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E2=80=94=E2=80=94=E6=8C=89=E6=B8=A9=E5=8C=BA?= =?UTF-8?q?=E6=BF=80=E6=B4=BB=E7=9F=A9=E9=98=B5(=E8=80=81=E8=8E=AB?= =?UTF-8?q?=E5=8E=9F=E5=88=99)=20-=20route()=20matched=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E4=BB=BB=E4=B8=80=E6=B8=A9=E5=8C=BA=E4=B8=89=E9=A1=B9=E8=BE=BE?= =?UTF-8?q?=E6=A0=87(=E4=B8=8D=E5=8F=AA=E5=BD=93=E5=89=8D=E6=B8=A9?= =?UTF-8?q?=E5=8C=BA)=20-=20main()=E7=94=9F=E6=88=90regime=5Factive?= =?UTF-8?q?=E7=9F=A9=E9=98=B5(=E6=AF=8F=E6=B8=A9=E5=8C=BA=E7=8B=AC?= =?UTF-8?q?=E7=AB=8B=E6=8B=A9=E4=BC=98,=E8=B5=84=E6=A0=BC=E5=A4=9F?= =?UTF-8?q?=E5=B0=B1=E6=BF=80=E6=B4=BB,=E4=B8=8D=E5=90=88=E6=A0=BC?= =?UTF-8?q?=E7=BB=9D=E4=B8=8D=E6=BF=80=E6=B4=BB)=20-=20=E5=BD=93=E5=89=8D?= =?UTF-8?q?=E6=B8=A9=E5=8C=BAactive=3Dregime=5Factive[state](=E5=AE=9E?= =?UTF-8?q?=E7=9B=98=E9=97=B8=E9=97=A8)=20=E7=BB=93=E6=9E=9C:=20trend=5Fdo?= =?UTF-8?q?wn=3D[b=5Ftd1=5Fv3,v=5Flurk=5Fv3,s2=5Fpanic=5Fv2]=20choppy=3D[v?= =?UTF-8?q?=5Flurk=5Fv2]=20trend=5Fup=3D[v=5Fnext,v8.1]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/profile-scripts/strategy_router.py | 63 ++++++++++++++++++----- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/deploy/profile-scripts/strategy_router.py b/deploy/profile-scripts/strategy_router.py index 645c22d4..c0972ee3 100644 --- a/deploy/profile-scripts/strategy_router.py +++ b/deploy/profile-scripts/strategy_router.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- """strategy_router.py v5 — MoFin 策略动态路由(动态策略库,2026-08-13) @@ -154,19 +154,31 @@ def route(regime, temp, perf): best_wr = best[1].get("win_rate", 0) cur_wr = cur.get("win_rate") if cur else None # 2026-08-16 资格标准A(老莫):长期10y/近期2y/当下1y 适应温区年化>大盘 三项达标 + 手动可用 - # (替代只看胜率≥50%的旧判定——旧标准会让年化-41%但胜率51%的策略激活) + # 2026-08-18 重构(老莫):matched 改为【任一温区三项达标】即可(不只当前温区)。 + # 核心:资格够就必须能激活;当前温区是实盘闸门,但choppy/trend_up等温区达标策略也要备好激活。 + # 不合格(如 v_lurk_v3 @ choppy ✅❌❌)绝不激活该温区;合格(v_lurk_v2 @ choppy)就激活。 try: from strategy_qualify import evaluate_all_regimes, is_available, get_benchmarks _qbench = get_benchmarks('a') - # 2026-08-17 择优激活:按当前温区评估资格(同 server.py 修复——best_regime 会让 - # v_lurk_v3 在 trend_down 达标却被 choppy 评估误判不合格) - _qev_all = evaluate_all_regimes(name, 'a', bench=_qbench) - _qev_cur = (_qev_all or {}).get(current_regime) or {} - _qual_ok = bool(_qev_cur.get("long_ok") and _qev_cur.get("mid_ok") and _qev_cur.get("short_ok")) + _qev_all = evaluate_all_regimes(name, 'a', bench=_qbench) or {} + # 达标温区列表(任一温区三项全达) + _qual_regimes = [] + for _rg in ("trend_down", "choppy", "trend_up"): + _q = (_qev_all or {}).get(_rg) or {} + if _q.get("long_ok") and _q.get("mid_ok") and _q.get("short_ok"): + _qual_regimes.append(_rg) _manual_ok = is_available(name) - matched = _qual_ok and _manual_ok + matched = bool(_qual_regimes) and _manual_ok + _qual_cur_ok = False + if _qual_regimes: + _qev_cur = (_qev_all or {}).get(current_regime) or {} + _qual_cur_ok = bool(_qev_cur.get("long_ok") and _qev_cur.get("mid_ok") and _qev_cur.get("short_ok")) except Exception: - matched = (best_wr >= 50) and (cur_wr is not None and cur_wr >= 50) # 兜底旧标准 + _qual_regimes = [current_regime] if ((best_wr >= 50) and (cur_wr is not None and cur_wr >= 50)) else [] + _qual_cur_ok = current_regime in _qual_regimes + matched = bool(_qual_regimes) + # ✓ 记录达标温区(供按温区激活矩阵) + qualifies = _qual_regimes if 'qualifies' in dir() else [] family = FAMILY_MAP.get(name, DEFAULT_FAMILY) base = 1.0 if matched else 0.3 try: @@ -180,11 +192,14 @@ def route(regime, temp, perf): "temp_band": band, "family": family, "matched": matched, + "qualifies": qualifies, # 达标温区列表(2026-08-18) + "qual_cur_ok": _qual_cur_ok, # 当前温区是否达标(2026-08-18) "best_regime": best[0], "best_win_rate": best[1].get("win_rate", 0), "cur_win_rate": cur.get("win_rate") if cur else None, "cur_avg_pnl": cur.get("avg_pnl") if cur else None, "trades": cur.get("trades") if cur else 0, + "active_regimes": qualifies, # 别名(前端用) } return dict(sorted(weights.items(), key=lambda x: -x[1]["weight"])) @@ -247,15 +262,39 @@ def main(): temp = load_temp() # A股温度 perf = load_regime_perf('a') # A股策略表现 weights = route(regime, temp, perf) + # 2026-08-18:按温区生成激活矩阵(老莫:资格够就激活,不合格绝不激活) + # - 每个温区,从"在该温区三项达标(qualifies含该温区)"里按质量分择优取前 MAX_ACTIVE + # - 当前温区 active = regime_active[当前温区](实盘闸门) + _all_regimes = ("trend_down", "choppy", "trend_up") + _cur_rg = regime.get("regime", "unknown") + regime_active = {} + for _rg in _all_regimes: + # 该温区达标策略(qualifies 含 rg) + _rg_matched = [(k, v) for k, v in weights.items() + if v.get("matched") and _rg in v.get("qualifies", [])] + # 按质量分择优 + _rg_scored = [] + for name, v in _rg_matched: + q = _quality_score(name, 'a', _rg) + fam = FAMILY_MAP_ACT.get(name, name) + _rg_scored.append({"name": name, "quality": q, "family": fam}) + _rg_scored.sort(key=lambda x: -x["quality"]) + _used = set(); _sel = [] + for s in _rg_scored: + if s["family"] in _used: continue + if len(_sel) >= MAX_ACTIVE: break + _used.add(s["family"]); _sel.append(s["name"]) + regime_active[_rg] = _sel out = { - "state": regime.get("regime", "unknown"), + "state": _cur_rg, "state_date": regime.get("date", ""), "temp_band": temp.get("band", "unknown"), "temp_rsi": temp.get("rsi"), "weights": weights, - "active": _select_active(weights, regime.get("regime", "unknown"), 'a'), + "active": regime_active.get(_cur_rg, []), + "regime_active": regime_active, "updated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), - "note": "择优激活(2026-08-17): 每温区按质量分(综合分×普适有效年占比)排序+家族去重取前%d个; 温区(平滑K=5)选类型+温度乘数" % MAX_ACTIVE, + "note": "择优激活(2026-08-18): 按温区——任一温区三项达标即可激活该温区;当前温区实盘闸门;不合格绝不激活;合格就激活(择优排序)", } # 港股路由(2026-08-14 新增,不影响A股)——港股组合按温区调度(hk_strategies 定义) try: