feat: b_td1_v3——原池(5000信号)+score每日top5截断,信号572/成交316/比1.8(v2超跌强化错误砍成交,已修正)

This commit is contained in:
xxm
2026-08-17 03:02:18 +08:00
parent 8f36517f9e
commit 23be0d7c76
+112
View File
@@ -0,0 +1,112 @@
# -*- coding: utf-8 -*-
"""b_td1_v3 生成器(基于 DB 原版信号 + merge 查 score + 每日top-N截断)"""
import sys, json
sys.path.insert(0, "/home/hmo/MoFin")
import pandas as pd
import numpy as np
import sqlite3
TOP_N = 5
SRC_VERSION = "b_td1"
def score_row(b, r, s, r5):
sc = 0
if b is not None and not pd.isna(b): sc += 40 if b < -30 else 32 if b < -20 else 20 if b < -10 else 8
if r is not None and not pd.isna(r): sc += 30 if r < 30 else 24 if r < 40 else 14 if r < 50 else 6
if s is not None and not pd.isna(s): sc += 20 if s < -20 else 14 if s < -10 else 8 if s < 0 else 3
if r5 is not None and not pd.isna(r5): sc += 10 if r5 < -25 else 7 if r5 < -15 else 4 if r5 < -8 else 1
return sc
def gen_trades(start, end, top_n=TOP_N):
conn = sqlite3.connect("/home/hmo/MoFin/data/mofin.db", timeout=30)
r = conn.execute("SELECT results_json FROM strategy_research WHERE version=? AND period_tag='2y'",
(SRC_VERSION,)).fetchone()
conn.close()
if not r:
return []
d = json.loads(r[0])
trades = [t for t in d["trades"] if start <= t["entry_date"] <= end]
if not trades:
return []
# panel 特征用 merge(快)
panel = pd.read_pickle("/tmp/panel_12d.pkl")
pcols = ["bias60", "rsi", "sec_ret20", "ret5"]
pf = panel[["code", "date"] + pcols].copy()
pf["code"] = pf["code"].astype(str).str.zfill(6)
pf["date"] = pf["date"].astype(str)
tdf = pd.DataFrame(trades)
tdf["code"] = tdf["code"].astype(str).str.zfill(6)
tdf["date"] = tdf["entry_date"].astype(str)
merged = tdf[["code", "date"]].merge(pf, on=["code", "date"], how="left")
merged["score"] = merged.apply(lambda r: score_row(r["bias60"], r["rsi"], r["sec_ret20"], r["ret5"]), axis=1)
score_map = dict(zip(zip(merged["code"], merged["date"]), merged["score"]))
for t in trades:
t["score"] = score_map.get((str(t["code"]).zfill(6), t["entry_date"]), 50)
t.setdefault("boost", 1.0)
# 每日 top-N
from collections import defaultdict
by_day = defaultdict(list)
for t in trades:
by_day[t["entry_date"]].append(t)
chosen = []
for dt in sorted(by_day):
chosen.extend(sorted(by_day[dt], key=lambda x: -x["score"])[:top_n])
return chosen
def build_results(trades):
import copy, random
from strategy_lab import portfolio_sim
n = len(trades)
wins = [t for t in trades if t["profit_pct"] > 0]
wr = len(wins) / n * 100 if n else 0
avg = sum(t["profit_pct"] for t in trades) / n if n else 0
sim = portfolio_sim(trades, 1000000, max_positions=10) or {}
rets = []
for seed in range(5):
t2 = copy.deepcopy(trades); rng = random.Random(seed); rng.shuffle(t2)
rets.append((portfolio_sim(t2, 1000000, max_positions=10) or {}).get("total_return_pct") or 0)
return {"summary": {"total_trades": n, "win_rate": round(wr, 1), "avg_profit_pct": round(avg, 2)},
"portfolio": {"positions_taken": sim.get("positions_taken"), "positions_skipped": sim.get("positions_skipped"),
"total_return_pct": sim.get("total_return_pct"), "cagr_pct": sim.get("cagr_pct"),
"portfolio_max_dd_pct": sim.get("portfolio_max_dd_pct"), "capital_final": sim.get("capital_final")},
"robustness": {"shuffle_total_return": rets, "spread_pp": round(max(rets) - min(rets), 1)},
"trades": trades}
if __name__ == "__main__":
from datetime import datetime
DB = "/home/hmo/MoFin/data/mofin.db"
VERSION = "b_td1_v3"
windows = {"1y": ("2025-07-01", "2026-07-01"), "2y": ("2024-07-01", "2026-07-01"),
"5y": ("2021-07-01", "2026-07-01"), "10y": ("2016-01-01", "2026-07-01")}
conn = sqlite3.connect(DB, timeout=30)
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
for pt, (s, e) in windows.items():
trades = gen_trades(s, e)
if not trades:
print(f"[{pt}] 无信号")
continue
results = build_results(trades)
exist = conn.execute("SELECT id FROM strategy_research WHERE version=? AND period_tag=?", (VERSION, pt)).fetchone()
if exist:
conn.execute("UPDATE strategy_research SET results_json=? WHERE version=? AND period_tag=?",
(json.dumps(results, ensure_ascii=False), VERSION, pt))
else:
conn.execute("""INSERT INTO strategy_research (version, name, summary, hypothesis, parent, config_json, results_json, period, created_at, market, period_tag, deprecated)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)""",
(VERSION, "B组超跌·原池优选", "b_td1原池+score每日top5截断",
"老莫指正: v2超跌强化错误砍成交。改原池+score每日top5 → 信号-89%/成交-9%/比1.8",
"B组", json.dumps({"top_n": TOP_N, "src": SRC_VERSION}, ensure_ascii=False),
json.dumps(results, ensure_ascii=False), None, now, "a", pt, None))
s2 = results["summary"]; p = results["portfolio"] or {}
_pt2 = p.get("positions_taken") or 0
print(f"[{pt}] 信号{s2['total_trades']} 成交{_pt2}{s2['total_trades']/max(_pt2,1):.1f} "
f"胜率{s2['win_rate']}% 年化{p.get('cagr_pct') or 0}% 回撤{p.get('portfolio_max_dd_pct') or 0}% 洗牌差{results['robustness']['spread_pp']}pp")
conn.commit(); conn.close()
print(f"\n写入完成 (version={VERSION})")