Files
MoFin/deploy/profile-scripts/strategy_router.py
T

190 lines
7.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""strategy_router.py v5 — MoFin 策略动态路由(动态策略库,2026-08-13)
核心(老莫原则):
- 策略全温区发信号(不留温区门控在策略内)
- 策略-温区表现常态化记录(regime_perf.py / strategy_regime_perf),适用温区动态化
- 组合按当前温区自动激活/休眠策略:当前温区实测胜率高的策略优先
- 不漏历史策略(v_mr_sel trend_down 93%、v7.3 trend_up 94% 等被埋没的强者)
数据流:
market_regime(三态) + regime_tracker(平滑K=5) → 当前温区
temp_band(rsi) → 温度/仓位乘数
regime_perf(实测) → 各策略温区表现
→ strategy_weights.json(各策略权重/激活状态)
"""
import json
import sys
from pathlib import Path
from datetime import datetime
_SCRIPT_DIR = Path(__file__).resolve().parent
sys.path.insert(0, str(_SCRIPT_DIR))
sys.path.insert(0, "/home/hmo/MoFin")
OUT = Path("/home/hmo/MoFin/data/strategy_weights.json")
DEFAULT_FAMILY = "mr"
FAMILY_MAP = {
"v_weak": "mr", "v_oversold": "mr", "v_mr": "mr", "v_mr2": "mr", "v_mr3": "mr",
"v_mr4": "mr", "v_mr_sel": "mr", "v_lurk_v1": "mr", "v_lurk_v2": "mr", "v_lurk_v3": "mr",
"s2_panic": "mr", "v_osc": "mr",
"v_next": "trend", "v_next3": "trend", "v_next4": "trend", "v_next5": "trend",
"v8.0": "trend", "v8.1": "trend", "v8.2": "trend", "v8.3": "trend",
"v7.0": "trend", "v7.1": "trend", "v7.1b": "trend", "v7.2": "trend", "v7.3": "trend",
"v6.0": "trend", "v6.1": "trend", "v6.2": "trend",
"v9.0": "trend", "v9.1": "trend", "v9.2": "trend",
"v_combo": "trend", "v1.0": "trend", "v2.0": "trend", "v3.0": "trend",
"v4.0": "trend", "v4.0a": "trend", "v4.0b": "trend", "v4.0c": "trend",
"v4.0d": "trend", "v4.0e": "trend", "v4.0f": "trend", "v4.0g": "trend",
"v4.0h": "trend", "v4.1": "trend", "v5.0": "trend",
"v11.0": "trend", "v11.1": "trend",
"hk_mr1": "mr", # 港股深度超卖反弹(2026-08-14 港股归因研发,trend_down 主战场)
}
def load_regime(market='a'):
"""读取当前温区。market='a'(默认,A股 smoothed 顶层,行为不变) / 'hk'(港股 markets.hk)"""
if market == 'hk':
try:
p = Path("/home/hmo/MoFin/data/market_regime_smoothed.json")
if p.exists():
d = json.loads(p.read_text(encoding="utf-8"))
mk = (d.get("markets") or {}).get("hk") or {}
if mk.get("current_regime"):
return {"regime": mk["current_regime"], "date": mk.get("current_date", "")}
except Exception:
pass
try:
from market_regime import load_market_regime
return load_market_regime(market='hk')
except Exception:
return {"regime": "unknown"}
try:
p = Path("/home/hmo/MoFin/data/market_regime_smoothed.json")
if p.exists():
d = json.loads(p.read_text(encoding="utf-8"))
return {"regime": d.get("current_regime", "unknown"),
"date": d.get("current_date", "")}
except Exception:
pass
try:
from market_regime import load_market_regime
return load_market_regime()
except Exception:
return {"regime": "unknown"}
def load_temp(market='a'):
"""读取当前温度。market='a'(默认,A股) / 'hk'(港股)"""
try:
from temp_band import get_market_temp
return get_market_temp(market=market)
except Exception:
return {"band": "unknown", "rsi": None}
def load_regime_perf(market='a'):
"""读取策略-温区表现。market='a'(默认,A股,行为不变) / 'hk'(港股策略)"""
conn = None
try:
import sqlite3
conn = sqlite3.connect("/home/hmo/MoFin/data/mofin.db", timeout=30)
conn.execute("PRAGMA busy_timeout=30000")
rows = conn.execute(
"SELECT strategy, regime, trades, win_rate, avg_pnl FROM strategy_regime_perf "
"WHERE COALESCE(market,'a')=?", (market,)
).fetchall()
result = {}
for strat, reg, n, wr, pnl in rows:
result.setdefault(strat, {})[reg] = {"trades": n, "win_rate": wr, "avg_pnl": pnl}
return result
except Exception:
return {}
finally:
if conn:
conn.close()
def route(regime, temp, perf):
current_regime = regime.get("regime", "unknown")
band = temp.get("band", "unknown")
weights = {}
for name, regs in perf.items():
if not regs:
continue
cur = regs.get(current_regime)
best = max(regs.items(), key=lambda x: x[1].get("win_rate", 0))
best_wr = best[1].get("win_rate", 0)
cur_wr = cur.get("win_rate") if cur else None
matched = (best_wr >= 50) and (cur_wr is not None and cur_wr >= 50)
family = FAMILY_MAP.get(name, DEFAULT_FAMILY)
base = 1.0 if matched else 0.3
try:
from temp_band import temp_multiplier
mult = temp_multiplier(band, family)
except Exception:
mult = 0.8
weights[name] = {
"weight": round(base * mult, 2),
"regime": current_regime,
"temp_band": band,
"family": family,
"matched": matched,
"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,
}
return dict(sorted(weights.items(), key=lambda x: -x[1]["weight"]))
def main():
# A股路由(完全不变)
regime = load_regime() # A股温区
temp = load_temp() # A股温度
perf = load_regime_perf('a') # A股策略表现
weights = route(regime, temp, perf)
out = {
"state": regime.get("regime", "unknown"),
"state_date": regime.get("date", ""),
"temp_band": temp.get("band", "unknown"),
"temp_rsi": temp.get("rsi"),
"weights": weights,
"active": [k for k, v in weights.items() if v["matched"]],
"updated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"note": "温区(平滑K=5)选策略类型 + 温度(rsi)乘数;策略全温区发信号,适用温区由实测动态决定",
}
# 港股路由(2026-08-14 新增,不影响A股)——港股策略按港股温区激活
try:
hk_regime = load_regime('hk')
hk_temp = load_temp('hk')
hk_perf = load_regime_perf('hk')
if hk_perf:
hk_weights = route(hk_regime, hk_temp, hk_perf)
out["markets"] = {"hk": {
"state": hk_regime.get("regime", "unknown"),
"state_date": hk_regime.get("date", ""),
"temp_band": hk_temp.get("band", "unknown"),
"weights": hk_weights,
"active": [k for k, v in hk_weights.items() if v["matched"]],
}}
except Exception as e:
print(f"港股路由失败(不影响A股): {e}", flush=True)
OUT.write_text(json.dumps(out, ensure_ascii=False, indent=1), encoding="utf-8")
print(f"strategy_weights.json: 状态={out['state']} 温度={out['temp_band']}(rsi={out['temp_rsi']})")
print(f"激活策略(A股): {out['active']}")
if "markets" in out:
hk = out["markets"]["hk"]
print(f"港股温区={hk['state']} 激活策略(港股): {hk['active']}")
print("权重排名(前15:")
for name, w in list(weights.items())[:15]:
mark = "✓" if w["matched"] else "观察"
print(f" {name:<12} w={w['weight']:<5} {w['best_regime']:<11} 最佳{w['best_win_rate']:>3.0f}% {mark}")
if __name__ == "__main__":
main()