feat: 融合自动链路——多周期trades+温区预计算+资格评估+可用性初始化(B组融合即可在温区表可见可评估)
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
安全:不自动 promote,不自动启用;融合只是把候选变成"可用的新策略版本"。
|
||||
"""
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import sqlite3
|
||||
from datetime import datetime
|
||||
@@ -120,10 +121,95 @@ def merge(version=None):
|
||||
else:
|
||||
r = register_a_share(cand)
|
||||
r["candidate"] = cand.get("hypothesis", "")
|
||||
# 融合链路:多周期trades + 温区预计算 + 资格评估 + 可用性初始化
|
||||
if r.get("status") in ("registered", "exists") and r.get("version"):
|
||||
try:
|
||||
link = _post_merge_chain(r["version"], cand)
|
||||
r["chain"] = link
|
||||
except Exception as e:
|
||||
r["chain"] = {"error": str(e)}
|
||||
out.append(r)
|
||||
return {"merged": out}
|
||||
|
||||
|
||||
def _post_merge_chain(version, cand):
|
||||
"""融合后链路:按period_tag生成窗口trades → 温区预计算 → 资格评估 → 可用性
|
||||
返回 {period_trades: {...}, regime_records: n, qualification: {...}, availability: {...}}"""
|
||||
import subprocess, json as _json
|
||||
out = {}
|
||||
# 1) 生成各周期窗口trades 写入 strategy_research(每个 period_tag 记录独立 results_json)
|
||||
# (B组候选的 trades 来自模拟验证,按 entry_date 过滤窗口)
|
||||
try:
|
||||
import sys as _sys
|
||||
_sys.path.insert(0, "/home/hmo/MoFin")
|
||||
_sys.path.insert(0, "/home/hmo/MoFin/evolution")
|
||||
import sqlite3 as _sq
|
||||
import pandas as _pd
|
||||
from datetime import datetime as _dt, timedelta as _td
|
||||
from b_group_miner import _simulate_verify
|
||||
market = cand.get("market", "a")
|
||||
regime = cand.get("regime", "trend_down")
|
||||
entry = cand.get("entry", {})
|
||||
panel_path = "/tmp/panel_12d_hk.pkl" if market == "hk" else "/tmp/panel_12d.pkl"
|
||||
panel = _pd.read_pickle(panel_path)
|
||||
panel = panel.sort_values(["code", "date"]).reset_index(drop=True)
|
||||
panel["fwd_ret60"] = panel.groupby("code")["close"].transform(lambda x: x.shift(-60) / x - 1) * 100
|
||||
cond = _pd.Series(True, index=panel.index)
|
||||
for feat, val in entry.items():
|
||||
if "_min" in feat:
|
||||
cond &= panel[feat.replace("_min", "")] >= val
|
||||
elif "_max" in feat:
|
||||
cond &= panel[feat.replace("_max", "")] < val
|
||||
elif feat in panel.columns:
|
||||
cond &= panel[feat] == val
|
||||
tp = int(cand.get("sim_tp", 15)); sl = int(cand.get("sim_sl", 8)); mh = int(cand.get("sim_maxh", 35))
|
||||
r = _simulate_verify(market, regime, panel, cond, tp=tp, sl=sl, maxh=mh)
|
||||
if not r:
|
||||
out["period_trades"] = {"error": "模拟验证无结果"}
|
||||
else:
|
||||
all_trades = r["trades"]
|
||||
latest_dt = _dt.strptime(max(t["entry_date"] for t in all_trades), "%Y-%m-%d")
|
||||
conn = _sq.connect("/home/hmo/MoFin/data/mofin.db", timeout=30)
|
||||
for pt, yrs in [("1y", 1), ("2y", 2), ("5y", 5), ("10y", 10)]:
|
||||
cutoff = (latest_dt - _td(days=365 * yrs)).strftime("%Y-%m-%d")
|
||||
wt = [t for t in all_trades if t["entry_date"] >= cutoff]
|
||||
n = len(wt)
|
||||
wins = [t for t in wt if t.get("profit_pct", 0) > 0]
|
||||
wr = round(len(wins) / n * 100, 1) if n else 0
|
||||
avg = round(sum(t.get("profit_pct", 0) for t in wt) / n, 2) if n else 0
|
||||
results = {"summary": {"total_trades": n, "win_rate": wr, "avg_profit_pct": avg},
|
||||
"trades": wt[:5000],
|
||||
"sim_params": {"tp": tp, "sl": sl, "maxh": mh},
|
||||
"window": {"cutoff": cutoff, "latest": max(t["entry_date"] for t in all_trades)}}
|
||||
conn.execute("UPDATE strategy_research SET results_json=? WHERE version=? AND period_tag=?",
|
||||
(_json.dumps(results, ensure_ascii=False), version, pt))
|
||||
out.setdefault("period_trades", {})[pt] = {"n": n, "win_rate": wr}
|
||||
conn.commit(); conn.close()
|
||||
except Exception as e:
|
||||
out["period_trades"] = {"error": str(e)}
|
||||
# 2) 温区预计算
|
||||
try:
|
||||
mkt_flag = "--market=hk" if market == "hk" else "--market=a"
|
||||
p = subprocess.run(["/home/hmo/MoFin/venv/bin/python",
|
||||
"/home/hmo/MoFin/deploy/profile-scripts/regime_perf_by_period.py",
|
||||
mkt_flag, "--periods=1y 2y 5y 10y"],
|
||||
capture_output=True, text=True, timeout=900)
|
||||
out["regime_run"] = {"rc": p.returncode, "tail": (p.stdout or "").strip().splitlines()[-1:]}
|
||||
except Exception as e:
|
||||
out["regime_run"] = {"error": str(e)}
|
||||
# 3) 资格评估 + 可用性
|
||||
try:
|
||||
_sys.path.insert(0, "/home/hmo/MoFin/deploy/profile-scripts")
|
||||
import strategy_qualify as sq
|
||||
out["qualification"] = sq.evaluate_all_regimes(version, market=market)
|
||||
sq.auto_init_availability([version])
|
||||
av = sq.load_availability().get(version)
|
||||
out["availability"] = av
|
||||
except Exception as e:
|
||||
out["qualification"] = {"error": str(e)}
|
||||
return out
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
v = sys.argv[1] if len(sys.argv) > 1 else None
|
||||
|
||||
Reference in New Issue
Block a user