Skip to main content

fund-quant-backtest

A 股指数/基金估值定投与择时策略的可运行回测脚手架。

ソース情報

リポジトリ
digoal/skills
ソースの最終更新活動
2026年8月27日 08:28
検出された SKILL.md の言語
中国語
スター
39
フォーク
10

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

ファイルエクスプローラー
5 ファイル

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
fund-quant-backtest
description
A 股指数/基金估值定投与择时策略的可运行回测脚手架。
version
0.1.0
author
Hermes Agent (curator-managed)
license
MIT
metadata
{"hermes":{"tags":["finance","backtest","a-stock","dca","valuation"],"related_skills":["retail-trading-manual-writer","a-stock-prediction","finance-core-analysis"]}}
# Fund Quant Backtest ## When to Use 触发词 (任一即用): 回测、定投算法、估值定投、智能定投、年化对比、分位算法、复现一遍、对比普通定投。 典型场景: - 主人在某个指数 / 基金上想试一种估值定投策略, 问"这个比普通定投好吗" - 主人改了档位参数 (比如"30-50% 不买"), 需要在新参数下出回测结论 - 主人质疑支付宝 / 天天基金的"智能定投" 黑盒, 需要自有数据复现 - 主人问"X 指数 PE 现在几分位", 想做当下决策但顺便跑过去 10 年验证 **不要用本 skill**: - 投教文章 / 长文产出 → `retail-trading-manual-writer` - 短期 T+1 涨跌预测 → `a-stock-prediction` / `us-stock-prediction` - 个股财报深度分析 → `financial-report-analysis` - 行业体系讲透 → `industry-deep-explainer` ## Class Contract 本 skill 提供 **可运行的 Python 回测脚手架**,用于在 A 股指数/基金上验证估值定投 / 择时类策略。核心交付物是: 1. 一份脚本 `/root/new/tmp/<task>/<date>/backtest_*.py`, 跑出结论 + CSV 2. 一份策略汇总报告(可在终端打印,也可写到 .md) 3. 可视化图表(可选, 但推荐: 让主人一眼看懂) 输入: 指数或基金代码 + 回测区间 + 策略档位(分位阈值 + 倍率) + 基础定投金额。 输出: 各策略的总投入 / 总份额 / 终值 / 年化 / 买入月数 / 最大回撤 + 关键时间点的决策明细。 **触发词**: 回测、定投算法、估值定投、智能定投、年化对比、分位算法、复现一遍。 **明确边界**: 本 skill 不负责以下任务, 请跳转其他 skill: - 投教类长文产出 → `retail-trading-manual-writer` - 短期 T+1 走势预测 → `a-stock-prediction` / `us-stock-prediction` - 个股财报深度分析 → `financial-report-analysis` - 估值因子与宏观经济体系讲透 → `industry-deep-explainer` ## Default Workflow 1. **先抓指数, 不抓基金净值。** - A 股宽基指数的历史收盘价 + 滚动 PE 在 akshare 中证接口一次拉齐: ```python ak.stock_zh_index_hist_csindex(symbol="H00300", start_date="...", end_date="...") ``` 输出列含 `收盘` 和 `滚动市盈率`, **无需二次拼接 PE 数据**。 - 其他指数的中证代码: - 沪深300 → `H00300` - 中证500 → `H00905` - 中证红利 → `H00922` - 上证50 → `H00016` - 创业板指 → `H03900` - 科创50 → `H02021` - 申万行业指数 / 港股指数 PE 通常需要别的源(乌龟量化 / 万得), 不要硬拉 akshare 这条接口。 2. **不要用 PE 静态版(乐咕乐股)** —— 接口挂了 csrf, 直接放弃。 3. **不要拉基金净值代替指数。** 净值有跟踪误差 + 管理费 + 分红再投近似问题, 用指数回测结论更干净。**最后再**用真实净值做交叉验证(可选)。 4. **滚动分位的标准做法**: ```python WIN = 1252 # 5 年 ~ 1252 个交易日 df['pe_pct'] = df['pe_ttm'].rolling(WIN, min_periods=252).apply( lambda x: np.sum(x[:-1] <= x[-1]) / len(x[:-1]), raw=True ) ``` - 窗口选择: 5 年跨 1-2 个完整牛熊, 7-8 年更平滑, 10 年反应滞后。**与主人确认**。 - 头 252 交易日分位用全历史填充, 但只用于显示, 不用于前 252 天决策。 5. **每月决策 = 每月第一个交易日**: ```python df['ym'] = df['日期'].dt.to_period('M') month_first = df.groupby('ym').first().reset_index() ``` 6. **回测循环核心(伪代码)**: ```python for s in ['s1_naive', 's2_zhifubao', 's3_v1', 's4_v2']: month_first[f'{s}_amt'] = month_first[s] * BASE_AMT month_first[f'{s}_share'] = month_first[f'{s}_amt'] / month_first['close'] total_invest = month_first[f'{s}_amt'].sum() total_shares = month_first[f'{s}_share'].sum() final_value = total_shares * df['close'].iloc[-1] cagr = (final_value / total_invest) ** (1/years) - 1 if total_invest > 0 else 0 ``` 7. **必须输出的指标**(表格): - 总投入、总份额、终值、终值收益额 - 年化收益(CAGR) - 买入月数 / 总月数(验证策略是否触发) - 最大回撤(逐月市值) 8. **必须输出与一次性买入对比** —— 提醒主人"起点敏感性问题"。 9. **回测起点很重要**: - 不要从牛市顶点(2015-06, 2021-02)起, 那会反过来证明定投更好, 结论不普适。 - 不要从最低点起, 那是上帝视角, 不能复现。 - 推荐从整段牛熊都覆盖的窗口起, 例如 2014-01 ~ 2024-12。 ## Standard Strategy Ladder 默认提供的策略档位(可改): | 策略名 | 触发条件 | 扣款 | |---|---|---| | `s1_naive` | 不论分位 | 1.0x | | `s2_zhifubao` | PE 分位 < 30% | 1.0x, 否则 0 | | `s3_v1_middle_buy` | 三指标任一触发低估 | 1.5x, 30-70% 区间 0.5x, > 70% 0 | | `s4_v2_final` | < 30% → 1.5x, 30-50% → 0.5x, > 50% → 0 | (主人最终采纳版, 单 PE 信号) | | `s5_v4_three_indicators` | PE 分位 + 股债比 + 60月均线趋势 | 1.5x / 0.5x / 0 / 极低估 3x + 趋势折扣 (主人首选, 三指标版) | | `s6_extreme` | PE 分位 < 15% AND PB 分位 < 15% | 3.0x | **两版并存的关系**: - `s4_v2_final`: 单 PE 信号 + 主人档位偏好。简单, 透明度最高, 主人最初拍板的版本。 - `s5_v4_three_indicators`: PE 分位 + 股债比 (1/PE / 10Y 国债) + 60月均线趋势过滤。**这是 2026-08-27 主人进一步要求的版本**, 也是回测下来"绝对收益 + 资金利用率"双优的版本。**默认推荐用这个。** 回测验证 (沪深300, 2014-2026-08, 152 个月, 投入 1000/月): | 策略 | 终值 | CAGR | 买入月数 | |---|---|---|---| | 普通定投 | 220,452 | 2.98% | 152/152 | | 支付宝风 (PE<30%才买) | 147,660 | 4.08% | 89/152 | | v2 简化 (PE分位单指标) | 181,009 | 3.72% | 110/152 | | **v4 三指标 + 趋势** | **207,698** | **3.51%** | **111/152** | 沪深300 全收益指数同期 2602 → 6799, 涨幅 161.3% (年化 7.9%)。 **v4 不是 CAGR 最高, 是绝对收益最高 + 资金利用率最高** —— 这正是主人的偏好: 总收益才是真收益, 年化是给营销看的。后续新对话如果主人再调, 务必 patch 这个表, 不要在脚本里悄悄改。 ### 分段表现 (2026-08-27 主人额外要求) 默认 2014-2024 跑完一轮后, **主人会再问"扩到 2026 看近期"** —— 直接加分段表: | 段 | 时长 | 普通定投 CAGR | v4 CAGR | v4 优势 | |---|---|---|---|---| | 慢牛 (2019-2020) | 24 月 | 14.57% | 20.37% | +5.8 pp | | **阴跌 (2021-2023)** | 36 月 | **-5.90%** | **-2.84%** | **+3.1 pp** | | 反弹 (2024-2026) | 32 月 | 6.33% | 12.38% | +6.0 pp | **核心洞察**: v4 在三种不同行情下都跑赢普通定投, **阴跌段损失减半、反弹段收益翻倍**。这是估值信号的真正价值, 不是只看 CAGR 能看出来的。后续回答主人"为什么用 v4"时, 直接引用这段话。 **最近 12 个月 (2025-09 ~ 2026-08) v4 决策 = 全部 0.0 (PE 分位 73-96%)** —— 这就是 v4 在贵市里的"沉默期", 用来回答"算法是不是死了"质疑的最佳证据。 ## Common Pitfalls - ❌ 用 `df['pe'].rolling().rank(pct=True)` —— 那给的是滚动百分位, 不是历史分位, 含义不同。 - ❌ 在回测里"用未来数据算分位"(rolling 包含当日)—— 必须 `x[:-1] <= x[-1]`, 防止前视偏差。 - ❌ 用"全历史百分位"代替滚动窗口 —— 会让分位永远不进入"低估区", 永无扣款, 假阴性。 - ❌ 把"一次性买入"和"定投"放同一张图比较终值 —— 起点偏差巨大。要么同起点比较, 要么标注 "假设你某日开始"。 - ❌ 把 akshare 拉到的"沪深300全收益指数"当成价格指数 —— 它**含分红再投**, 比真实价格指数高, 做严格回测要减分红或换口径。 - ❌ 代理不稳时(`Cannot connect to proxy`)—— 用 `curl --socks5-hostname host.docker.internal:11112`, 或重试一次, 不要无限重试。 ## Visualization 回测结论最好落地为一张图: X 轴时间, Y 轴累计投入 / 累计市值, 多策略叠加。 推荐 `matplotlib` + `fill_between`, 例: ```python import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(12, 6)) for s in ['s1', 's2', 's3', 's4']: cum_value = (month_first[f'{s}_share'].cumsum() * month_first['close']).values ax.plot(month_first['日期'], cum_value, label=s) ax.legend() ax.grid(alpha=0.3) ``` 图存到 `/root/new/tmp/<task>/<date>/fig_*.png`, 在对话里直接引用路径。 ## 主人偏好 (digoal/德哥) —— 2026-08-27 实战沉淀 实战中主人明确表达的偏好, 后续回测必须满足, 不要替主人切档位: 1. **结果汇报的硬指标** (任一回测必须输出): - 累计投入、累计份额、终值、收益额 (不要只给 CAGR) - CAGR、买入月数 / 总月数 (验证策略是否触发) - 必要时给一次性买入作为起点敏感性参考, **但分两栏列, 不要混着看** 2. **分档偏好**: 30-50% 区间 0.5x, **50-70% 直接跳过(0)**。主人原话: "调整一项, 中性区间(分位 50-70%) 跳过不买. 30~50% 0.5倍"。这是有意设计的更严纪律, 不是疏漏。 3. **结论偏好**: 主人关注"绝对收益(终值)"远高于"年化"。回测总结话术要强调"投了 X 万, 终值 Y 万, 资金利用率 Z%", 不要只喊 CAGR。 4. **报告节奏**: 结论先行, 一张总表 + 3-5 条犀利观察, 不堆理论。详细数据落 CSV, 让主人自己复盘。 5. **回测分段**: 默认 2014-01 ~ 2024-12 覆盖完整牛熊, 但**额外加 2014-2018 / 2019-2024 拆分**, 让主人看清"近期是否仍适用"。 6. **设计先于自动化 (2026-08-27 主人明确纠正)**: - 主人原话: "先别急cron, 你给个比较优的算法先." - **触发模式**: 主人提出"我有个策略 / 我在用 X, 帮我评估 / 落 cron"时, **不要第一时间就搭 cron**。先用 1-2 轮对话设计/论证/调优算法, 等主人明确说"落 cron"才进入部署阶段。 - **判断信号**: 主人没说"现在就建" / "落 cron" / "跑起来" 时, 默认不要进入 cron/job/state script 阶段。 - **错踩后果**: 上来就建 cron 会被主人打回, 浪费一轮; 上来就回答"好, 落 cron"是替主人切档位, 违反主人"先设计后部署"的偏好。 ## 已知数据源陷阱 (实战踩坑沉淀) - **`ak.stock_zh_index_value_csindex` (中证指数估值)** 返回的 xls URL (`oss-ch.csindex.com.cn/static/html/...`) 已 404, 实际是占位 JPEG 图片。**不要用这个接口拿历史 PE/PB/股息率**。直接走 `stock_zh_index_hist_csindex`。 - **10 年国债日频**: 用 `ak.bond_zh_us_rate()`, 含 1990-2026 全历史, 列名 `中国国债收益率10年`。akshare 的 `bond_china_yield()` 只覆盖到 2021, 别用。 - **乐咕乐股 PE 静态版** (`ak.stock_index_pe_lg`): 挂了 csrf, 直接放弃, 别尝试。雪球 PE 也有 csrf / 反爬, 不推荐。 ## 从回测到生产: cron 部署阶段 (2026-08-27 主人拍板落地) 回测结论跑通 + 主人明确说"落 cron"后, 进入此阶段。**默认推荐用 `--script` + `--no-agent` 纯脚本模式**, 不是 agentic 模式: - daily-decision 是 if-then-else 表格, 不需要 LLM 阅读理解 - 节省 token, 跑得快 (< 5s) - 用 `hermes-cron-orchestrator` 描述的 agentic 模式是浪费 (那 skill 主要服务"数据 + LLM 解读"型 cron) 完整模板 / 部署流程 / 时区换算 / 7 步走 / 踩坑速查表, 看 `references/production-deployment.md`。关键提醒: - 脚本必须放 `/root/.hermes/profiles/digoal/scripts/` (per-profile, 不是全局) - `--script` 参数用纯文件名 (不要绝对路径) - workdir 必须在 `/root/new/work/digoal/` 下 - exit code 透传给 cron, 失败不要静默 ## Reference Files - `references/akshare-pe-data-sources.md`: 中证 / 乐咕乐股 / 雪球 / 万得 各源对比, 哪个能用、哪个有 csrf、字段含义。 - `references/valuation-strategy-design-notes.md`: 估值定投档位选择背后的依据, 三指标 / 趋势过滤 / EPS 一致预期修正等高级条件的取舍逻辑。 - `references/production-deployment.md`: 回测结论跑通后的生产化部署模式 (hermes cron + script + no-agent), 包括 wrapper.sh 模板、workdir 布局、history.json 格式、常见踩坑。 - `scripts/dca_backtest_template.py`: 一个可直接 copy 修改的回测模板。
GitHubで見る