From bf0e1c2dbce417988120e5c43912b5be99b6f6e6 Mon Sep 17 00:00:00 2001 From: hmo Date: Sat, 15 Aug 2026 08:48:49 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20hk=5Fbacktest=E8=A1=A5=E5=85=A8summary?= =?UTF-8?q?=5Fstats=E2=80=94=E2=80=94=E5=A4=8D=E7=94=A8calc=5Fsummary?= =?UTF-8?q?=E5=85=A8=E5=AD=97=E6=AE=B5(=E8=83=9C=E7=8E=87/=E7=9B=88?= =?UTF-8?q?=E4=BA=8F/=E5=A4=8F=E6=99=AE/=E7=9B=88=E4=BA=8F=E6=AF=94/?= =?UTF-8?q?=E6=8C=81=E4=BB=93/=E6=99=AE=E9=80=82)+portfolio=5Fsim=E7=BB=84?= =?UTF-8?q?=E5=90=88=E6=A8=A1=E6=8B=9F,=E4=B8=8EA=E8=82=A1=E5=90=8C?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/profile-scripts/hk_backtest.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/deploy/profile-scripts/hk_backtest.py b/deploy/profile-scripts/hk_backtest.py index c874ae07..d86173f1 100644 --- a/deploy/profile-scripts/hk_backtest.py +++ b/deploy/profile-scripts/hk_backtest.py @@ -198,10 +198,10 @@ def window_returns(nav_series): def portfolio_metrics(trades, capital=1000000, slots=8): - """资金模拟 + 窗口收益(净值曲线)""" + """资金模拟 + 完整 summary_stats(复用 strategy_lab.calc_summary,与A股同构)""" + import strategy_lab as lab nav, stats = portfolio_nav(trades, capital, slots) win = window_returns(nav) - # 年化(用首末净值) cagr = None if nav: items = sorted(nav.items()) @@ -209,14 +209,23 @@ def portfolio_metrics(trades, capital=1000000, slots=8): d1, v1 = items[-1] yrs = max((datetime.strptime(d1, "%Y-%m-%d") - datetime.strptime(d0, "%Y-%m-%d")).days / 365.0, 0.5) cagr = (((v1 / v0) ** (1 / yrs)) - 1) * 100 if v0 > 0 else None + # 完整 summary_stats(复用 A 股 calc_summary——字段结构与A股完全一致) + cs = lab.calc_summary(trades, capital) + pf = lab.portfolio_sim(trades, capital, max_positions=slots) or {} + pff = lab.portfolio_sim_full(trades, capital) or {} + summary = dict(cs) + summary["sizing_slots"] = slots + summary["portfolio"] = pf + summary["portfolio_full"] = pff return { + "summary_stats": summary, "cagr": cagr, "year1": win.get("year1"), "month6": win.get("month6"), "month3": win.get("month3"), "trades": len(trades), "skipped": stats.get("skipped", 0), - "win_rate": sum(1 for t in trades if t["profit_pct"] > 0) / len(trades) * 100 if trades else 0, + "win_rate": cs.get("win_rate"), } @@ -261,14 +270,16 @@ def main(): trades = [t for t in trades if td_run.get(t["entry_date"], 0) <= args.td_guard] print(f" 温区调度({reg})+防守: 保留 {len(trades)} 笔", flush=True) m = portfolio_metrics(trades, slots=args.slots) - print(f" 交易{m['trades']} 胜率{m['win_rate']:.0f}% 组合年化{m['cagr']}% " + ss = m["summary_stats"] + print(f" 交易{ss['total_trades']} 胜率{ss['win_rate']}% 组合年化{m['cagr']}% " f"近1年{m['year1']:+.1f}% 近6月{m['month6']:+.1f}% 近3月{m['month3']:+.1f}%\n", flush=True) all_trades += trades if all_trades and not args.version: print("=== 港股策略组合(全温区)===", flush=True) m = portfolio_metrics(all_trades, slots=args.slots) - print(f" 组合: 交易{m['trades']} 胜率{m['win_rate']:.0f}% 组合年化{m['cagr']}% " + ss = m["summary_stats"] + print(f" 组合: 交易{ss['total_trades']} 胜率{ss['win_rate']}% 组合年化{m['cagr']}% " f"近1年{m['year1']:+.1f}% 近6月{m['month6']:+.1f}% 近3月{m['month3']:+.1f}%", flush=True) ok = (m['cagr'] or 0) > 10 and (m['year1'] or 0) > 10 and (m['month6'] or 0) > 5 and (m['month3'] or 0) > 0 print(f" 验收: {'✅ 达标' if ok else '❌ 未达标'}(年化>10/近1年>10/近6月>5/近3月>0)", flush=True)