从零构建 A 股 ETF 动量轮动系统:一个量化新手的完整指南
Table of Contents
一个基于 A 股 ETF 的量化交易信号系统。它会自动分析 13 只 ETF 的历史走势,找出当前最强的几只买入,弱的卖出,同时内置多重风险控制。支持历史回测、参数优化、每日实盘信号推送。
重要声明
本项目源代码不对外公开,仅供内部学习和研究使用。
原因:
- 量化策略具有高度风险性。 过去的回测表现不代表未来收益,任何人照搬策略参数都可能遭受重大亏损。
- 参数与市场环境强相关。 当前参数基于 2019-2025 年 A 股数据优化,市场结构变化后可能完全失效。
- 执行差异会导致完全不同的结果。 回测假设理想化的成交条件,实盘的滑点、延迟、心理因素会显著影响收益。
- 防止未经理解的盲目使用。 如果不理解策略原理就直接使用,在遇到回撤时很可能恐慌退出,造成不必要的损失。
如果你是通过本文档了解到这个项目的,请务必:
- 完整阅读本文档,理解策略的原理和局限性
- 理解"回测收益 ≠ 未来收益"这一核心事实
- 不要将超过可承受损失范围的资金投入任何量化策略
- 对自己的投资决策负全部责任
回测实绩总览(2019.01 — 2026.05,T+1 执行)

核心绩效指标
| 指标 | 数值 | 说明 |
|---|---|---|
| 总收益率 | 180.75% | 10 万 → 28 万 |
| 年化收益率 | 15.62% | 7 年复合增长 |
| 年化波动率 | 17.39% | 价格波动幅度 |
| 夏普比率 | 0.90 | 风险调整后收益 |
| 最大回撤 | -19.45% | 历史最大跌幅 |
| Calmar 比率 | 0.80 | 收益 / 回撤比 |
| 总交易笔数 | 129 | 7 年约 129 次买卖 |
| 总手续费 | ¥2,566 | 占初始资金 2.6% |
| 基准收益(等权 B&H) | 72.88% | 买入全部 ETF 不动 |
| 超额收益 | 107.87% | 策略比基准多赚 |
消融分析:每个模块的贡献(真实数据)
逐个关闭策略组件,观察影响。这揭示了 alpha 的真正来源:
| 配置 | 年化收益 | 最大回撤 | 夏普比率 | 结论 |
|---|---|---|---|---|
| Full v4(完整系统) | 15.62% | -19.45% | 0.90 | 基准线 |
| 关闭追踪止损 | 1.04% | -52.40% | 0.05 | 止损是最核心的组件 |
| 关闭相关性过滤 | 1.62% | -35.64% | 0.08 | 相关性过滤极重要 |
| 关闭切换门槛 | 4.51% | -34.07% | 0.23 | 门槛有效减少无意义换仓 |
| 等权(关闭波动率加权) | 10.39% | -23.43% | 0.55 | 波动率加权改善了回撤 |
| 关闭 MA200 趋势过滤 | 14.21% | -27.33% | 0.81 | 贡献较小但熊市中关键 |
| 关闭绝对动量 | 15.38% | -20.93% | 0.89 | 大部分时候不触发 |
| 裸动量(仅排名) | -9.55% | -76.90% | -0.40 | 没有风控 = 巨亏 |
关键发现:追踪止损和相关性过滤贡献了策略 90% 以上的超额收益。没有风控的裸动量策略不仅不赚钱,还会巨亏 76.9%。
参数敏感度:plateau 还是 spike?(真实数据)
理想的参数应该在一定范围内都表现良好(plateau),而不是只在某个精确值上才好(spike)。
追踪止损敏感度:
| 止损阈值 | 夏普比率 | 判断 |
|---|---|---|
| 关闭(0%) | 0.53 | 无止损基准 |
| 12% | 0.52 | 太紧,频繁误杀 |
| 14% | 0.44 | 偏紧 |
| 18% | 0.50 | 可接受 |
| 20% | 0.54 | 不错 |
| 22% | 0.61 | 当前区域 |
| 24% | 0.61 | plateau |
| 26% | 0.56 | 仍然不错 |
| 28% | 0.57 | 仍然不错 |
| 30% | 0.54 | 开始下降 |
20%-28% 形成了明显的 plateau(稳定平台),说明参数不是尖刺过拟合。
持仓天数敏感度:
| 最小持仓天数 | 夏普比率 |
|---|---|
| 1 天 | 0.46 |
| 5 天 | 0.54 |
| 10 天 | 0.51 |
| 12 天 | 0.52 |
| 15 天 | 0.61 |
| 18 天 | 0.58 |
| 20 天 | 0.51 |
| 25 天 | 0.51 |
| 30 天 | 0.58 |
12-18 天区间表现稳定,15 天处于 plateau 中心。
Walk-Forward 验证:样本外还能赚钱吗?(真实数据)
用 3 年训练、1 年验证的滚动方式检测过拟合:
| 训练期 | 训练 Sharpe | 测试年份 | OOS 收益 | OOS 最大回撤 | 选出的最优参数 |
|---|---|---|---|---|---|
| 2019-2022 | 1.56 | 2023 | -1.0% | -3.0% | hold=8, stop=22% |
| 2020-2023 | 1.24 | 2024 | +14.4% | -4.5% | hold=8, stop=18% |
| 2021-2024 | 1.20 | 2025 | +14.1% | -8.9% | hold=8, stop=18% |
| 2022-2025 | 1.01 | 2026 | +16.6% | -8.2% | hold=15, stop=22% |
| 2023-2026 | 1.31 | 2026(部分) | -9.7% | -15.6% | hold=15, stop=25% |
5 轮中 3 轮样本外收益为正,且正收益轮次的收益率显著(14-17%)。参数 corr=0.60, switch=0.08 在所有轮次中保持一致,说明这两个参数非常稳定。
滑点压力测试(真实数据)
测试不同滑点下策略是否仍有盈利能力:
| 滑点 | 年化收益 | 夏普比率 | 超额收益 |
|---|---|---|---|
| 0.05% | 12.00% | 0.64 | +52.0% |
| 0.10%(默认) | 11.52% | 0.61 | +45.2% |
| 0.20% | 10.52% | 0.56 | +31.6% |
| 0.30% | 9.55% | 0.51 | +19.0% |
| 0.50% | 7.61% | 0.41 | -4.1% |
| 0.80% | 4.79% | 0.25 | -33.5% |
| 1.00% | 2.95% | 0.16 | -50.1% |
在 0.3% 滑点下仍然有 Sharpe > 0.5,说明策略的 alpha 不依赖微小价差,具备真实的盈利能力。
随机扰动测试(80 次,真实数据)
对最优参数随机扰动 ±10-20%,观察 Sharpe 分布:
| 统计量 | Sharpe 值 |
|---|---|
| 最小值 | -0.40 |
| 25 分位 | 0.11 |
| 中位数 | 0.41 |
| 75 分位 | 0.56 |
| 最大值 | 0.94 |
| Sharpe > 0 的比例 | 73.8%(59/80) |
80 次随机扰动中,近 3/4 的情况下 Sharpe 仍然为正,中位数 0.41。说明策略具备合理的鲁棒性,不是"恰好在某个参数上赚钱"。
目录
第一部分:量化投资入门
第二部分:核心概念详解
第三部分:策略深度解析
- 策略总览:一张图看懂整个系统
- 第 1 层:动量排名 — 谁最近最强?
- 第 2 层:MA200 趋势过滤 — 大势向上吗?
- 第 3 层:绝对动量过滤 — 是真的在涨吗?
- 第 4 层:相关性过滤 — 真的分散了吗?
- 第 5 层:反向波动率加权 — 该买多少?
- 第 6 层:风控机制 — 什么时候跑?
- 整体决策流程:用一个真实例子走一遍
- 为什么这个策略有效?学术基础与历史验证
- 策略的已知局限:它不能做什么?
- ETF 池设计:为什么选这 13 只?
第四部分:从回测到实盘
第五部分:动手操作
第六部分:附录
第一部分:量化投资入门
1. 什么是量化交易?和普通炒股有什么区别?
普通炒股(主观交易)
大多数人炒股是这样的:
- 看新闻:“某某行业要出利好政策了” → 买入
- 看股评:“大V 说要涨” → 跟着买
- 看感觉:“这只股票跌了很多,应该到底了” → 抄底
- 看涨跌:“赚了 10% 不舍得卖,亏了 20% 割肉” → 凭情绪操作
这种方式的问题:
- 不可重复:今天的判断依据是新闻,明天是直觉,没有一致性
- 情绪干扰:赚钱时贪婪(不肯卖),亏钱时恐惧(胡乱卖)
- 无法验证:你不知道你的"方法"到底是赚钱还是赔钱的,因为你根本没有固定方法
- 幸存者偏差:你记得自己赚钱的操作,忘记了亏钱的操作
量化交易
量化交易的核心是:把投资决策变成明确的规则,用计算机执行。
普通炒股: "我感觉创业板快要涨了" → 买
量化交易: "创业板 20 日涨幅 > 所有 ETF 的前 3 名
且价格 > 200 日均线
且 20 日涨幅 > 0" → 买
区别在于:
- 规则是明确的:每个条件都用数字定义,没有模糊空间
- 可以回测:用历史数据验证"如果一直按这个规则操作,过去 7 年结果如何"
- 可以重复:不管是谁来操作,同样的数据产生同样的信号
- 没有情绪:规则说买就买,说卖就卖,不犹豫
量化交易 ≠ 一定赚钱
重要的认知:量化只是一种方法论,它保证你的策略是"可检验的"和"一致的",但不保证策略是"赚钱的"。
一个烂策略,即使用量化方法执行,照样赔钱。量化的价值在于:你可以在投入真金白银之前,就知道这个策略的历史表现如何。 而主观交易没法做到这一点。
2. 量化交易的核心哲学:为什么规则比直觉靠谱?
2.1 “赌场优势"思维
赌场不需要每一局都赢。它只需要每局有 51% 的胜率,玩 10000 局之后,大数定律保证赌场一定赚钱。
量化交易的思路一模一样:
- 我们不追求"每次都买对”
- 我们追求"长期来看,正确的次数多于错误的次数"
- 或者"对的时候赚得多,错的时候亏得少"
本系统的回测数据:
胜率约 55% → 每 100 次操作,约 55 次赚钱
赚亏比约 1.8:1 → 赚钱时平均赚 1.8 元,亏钱时平均亏 1 元
看起来不起眼,但 129 笔交易累积下来,总收益是 180%。
2.2 “过程正确 > 结果正确”
普通投资者经常犯一个错误:用结果评价决策质量。
比如:“我抄底赚了 → 说明我抄底是对的”。但这可能只是运气好。下次同样操作可能巨亏。
量化思维是反过来的:只要过程(规则)是正确的,短期亏损也是可以接受的。 因为长期来看,正确的过程一定会带来好的结果。
本系统 2022 年亏了 8.58%。主观交易者可能会说"策略不行,换一个"。但量化思维是:看这一年市场整体跌了 21%,我只亏了 8.58%,策略的风控在起作用,继续执行。
2.3 系统化纪律
人类面对金钱时的心理弱点是天生的:
| 心理偏差 | 主观交易的表现 | 量化交易的处理 |
|---|---|---|
| 损失厌恶 | 亏了不肯割肉,死扛到更大亏损 | 追踪止损:跌 25% 自动卖,没有犹豫空间 |
| 贪婪 | 赚了不肯走,等着"再涨一点" | 定期轮动:按排名调仓,不恋战 |
| 从众心理 | 大家都在买,我也跟 | 只看数据:数字说买才买,不看新闻 |
| 过度自信 | “我判断一定会涨” | 仓位上限 50%:即使再看好,也不全仓 |
| 锚定效应 | “我在 10 块买的,跌到 8 块不卖” | 追踪止损看的是最高点,不是买入价 |
3. 策略的分类:我们做的是哪一种?
量化交易策略有很多种,理解我们处在哪个位置很重要:
3.1 按频率分
| 类型 | 持仓时间 | 特点 | 本系统 |
|---|---|---|---|
| 高频交易(HFT) | 毫秒到秒 | 需要专线、硬件加速,个人做不了 | |
| 日内交易 | 分钟到小时 | 需要盯盘,手续费很高 | |
| 短线交易 | 1-5 天 | 频繁操作,对滑点敏感 | |
| 中低频趋势 | 2-8 周 | 每隔一段时间调一次仓 | ← 我们在这里 |
| 长期配置 | 月到年 | 买入持有,很少调整 |
我们是中低频趋势跟踪:大约每 15 天检查一次,决定是否换仓。不用盯盘,一天看一次通知就够了。
3.2 按策略思路分
| 策略类型 | 核心逻辑 | 例子 | 本系统 |
|---|---|---|---|
| 价值投资 | 买"便宜"的资产 | 低 PE 策略、格雷厄姆 | |
| 动量/趋势 | 买"最近涨得好"的 | 追强势、趋势跟踪 | ← 核心 |
| 均值回归 | 买"跌多了"的,卖"涨多了"的 | 配对交易、统计套利 | |
| 套利 | 利用价格偏差无风险获利 | ETF 折溢价套利 | |
| 机器学习 | 用 AI 预测价格 | 深度学习预测 |
3.3 本系统的准确定位
用专业术语描述,本系统是:
多资产 ETF 轮动系统,融合了 Relative Momentum(相对动量)+ Absolute Momentum(绝对动量)+ Trend Following(趋势跟踪)+ Risk Rotation(风险切换)+ Risk Parity(风险平价)
翻译成大白话:
- Relative Momentum(相对动量):13 只 ETF 里谁涨得最好就买谁
- Absolute Momentum(绝对动量):但如果涨幅是负的,说明不是真的在涨,不买
- Trend Following(趋势跟踪):确认长期趋势向上(MA200)才允许持有
- Risk Rotation(风险切换):市场好的时候买进攻型资产(科技、半导体),市场差的时候自动切换到防御型资产(国债、黄金)
- Risk Parity(风险平价):波动大的少买点,波动小的多买点
这种多层叠加的架构,在学术上接近 GTAA(Global Tactical Asset Allocation,全球战术性资产配置)——专业机构管理上百亿资金时使用的框架。
第二部分:核心概念详解
4. 基础金融术语
ETF(Exchange-Traded Fund,交易所交易基金)
ETF 是一种可以像股票一样在交易所买卖的基金。比如"沪深 300 ETF(510300)“就是一只跟踪沪深 300 指数的基金,买它相当于一次性买入 300 只大公司的股票。
和普通基金的区别:
| 特性 | 场外基金(支付宝/天天基金买的) | 场内 ETF |
|---|---|---|
| 交易方式 | 当日申购,T+1 确认份额 | 像股票一样实时买卖 |
| 价格 | 每天只有一个净值 | 每秒都有实时价格 |
| 最小购买 | 1 元起 | 100 份起(约几百元) |
| 手续费 | 申购费 ~0.15% | 佣金万三(0.03%) |
| 适合场景 | 定投、不急着操作 | 量化交易、需要精确时机 |
为什么本系统用 ETF?
- 分散风险:一只 ETF 包含几十到几百只股票,不会因为某一只个股暴雷而巨亏
- 覆盖广:通过 ETF 可以方便地投资黄金、美股、日股、债券,个人账户无法直接买这些
- 手续费极低:ETF 免印花税(股票要收 0.1%),佣金通常万三以下
- 流动性好:主流 ETF 日成交额在亿元以上,买卖不会有流动性问题
- 规则简单:不需要研究个股基本面,只需要看价格趋势
收盘价(Close Price)
每天 15:00 A 股收盘时的最后成交价格。本系统所有计算都基于每日收盘价——这是每天最终、最确定的价格。
涨幅 / 收益率(Return)
今日涨幅 = (今日收盘价 - 昨日收盘价) / 昨日收盘价
比如昨天收盘 10 元,今天收盘 10.5 元,涨幅 = (10.5 - 10) / 10 = 5%。
移动平均线(Moving Average, MA)
过去 N 天收盘价的平均值,每天更新。
MA5 = 最近 5 天收盘价的平均值
MA200 = 最近 200 天收盘价的平均值
MA 的作用是平滑价格波动,看清趋势方向。天数越多越平滑:
- MA5(周线级别):波动很大,经常穿越价格
- MA20(月线级别):能看到短期趋势
- MA200(年线级别):非常平滑,代表长期趋势方向,也被称为"牛熊分界线”
手续费(Commission)
每次买入或卖出时券商收取的费用。目前 A 股 ETF 主流佣金在 万三(0.03%) 左右。
买入 10 万元:手续费 = 100000 × 0.0003 = 30 元
看起来很少,但如果频繁交易(比如每天买卖),一年下来手续费能吃掉很大一部分利润。这就是为什么本系统设计了 15 天最小持仓期和 8% 切换阈值——控制交易频率。
印花税
股票交易时卖出方需要缴纳 0.1% 的印花税。但 ETF 免征印花税,这是 ETF 相比股票的一大优势。
5. 量化特有术语
动量(Momentum)
动量的核心思想极其简单:过去涨得好的,接下来大概率继续涨;过去跌得惨的,接下来大概率继续跌。
这不是玄学。1993 年,金融学教授 Jegadeesh 和 Titman 在 Journal of Finance 上发表了开创性论文,用美国 1965-1989 年的数据证明:买入过去 3-12 个月表现最好的股票,卖出最差的股票,能持续获得显著的超额收益。 此后数百篇论文在全球各个市场、各个时期、各种资产上复现了这一现象。
动量效应存在的原因(学术界的主流解释):
-
行为金融学解释:
- 反应不足(Underreaction):好消息出来后,投资者不会一次性完全反应,而是慢慢消化,导致价格逐步上涨
- 羊群效应(Herding):看到上涨后更多人跟进,资金持续流入,推高价格
- 确认偏差(Confirmation Bias):持有者倾向于关注支持自己决策的信息,忽略负面信息
-
市场结构解释:
- 机构调仓惯性:大型基金的调仓需要数周甚至数月才能完成,大量资金的持续流入制造了动量
- 指数效应:ETF 和指数基金的被动买入加强了趋势
-
基本面解释:
- 盈利趋势:公司业绩好转往往持续数个季度,股价跟随基本面持续上行
动量效应也有失效的时候——市场剧烈反转(如 2020 年 3 月 COVID 暴跌后的 V 形反弹)时,动量会遭受巨大亏损。这就是为什么我们需要后面的趋势过滤和止损机制。
轮动(Rotation)
“轮动"是动量策略的执行方式:定期检查排名,把弱的换成强的。
第 1 期(1月):
排名: ① 半导体 ② 纳指 ③ 黄金 → 买入这 3 只
第 2 期(2月):
排名: ① 军工 ② 半导体 ③ 黄金
军工排名大幅超过纳指 → 卖出纳指,买入军工
半导体和黄金排名变化不大 → 继续持有
为什么不"一直持有不动”?因为市场的风格会切换。2020 年是科技股的天下,2021 年切换成了周期股和新能源,2022 年只有煤炭和红利在涨。轮动的价值就是跟着市场风格走,而不是死守一个方向。
避风港 / 安全港(Safe Haven)
当市场整体下跌(所有 ETF 的动量都是负的),系统不会硬着头皮买入任何一只权益资产,而是把资金转移到"避风港"——国债 ETF(511010)。
国债是政府发行的债券,几乎没有违约风险,在股市下跌时通常反而会上涨(因为资金从股市逃往债市)。它的作用不是"赚大钱",而是在暴风雨中保护本金。
类比:你在海上航行(做投资),风平浪静时满帆前进(买进攻型 ETF),暴风雨来了就驶入港湾(买国债),等风暴过去再出海。
趋势跟踪(Trend Following)
趋势跟踪的核心假设:市场不会突然掉头,趋势会持续一段时间。
- 上涨趋势中:每次回调是买入机会
- 下跌趋势中:每次反弹是卖出机会
- 识别趋势的工具:移动平均线(MA200)
趋势跟踪的优点是能抓住大行情(比如 2020 年的科技牛市),缺点是在震荡市(价格反复上下但没有方向)中会被反复"打脸"——上穿 MA200 买入,下穿卖出,来回亏手续费。
T+1 执行与 Look-ahead Bias(前视偏差)
这是量化回测中最容易犯的错误之一,理解它对于正确评估策略至关重要。
什么是前视偏差?
错误做法(T+0,前视偏差):
今天看到收盘价 → 今天用收盘价买入
问题:你在 15:00 之前不可能知道今天的收盘价是多少!
正确做法(T+1):
昨天收盘后知道了昨天的收盘价 → 今天(第二天)买入
这样信号生成和执行之间有一天的延迟,更接近真实
为什么这很重要?
在我们开发这个系统的过程中,第一版使用了 T+0 执行,回测年化收益 13.07%。修正为 T+1 后,收益骤降到 5.46%。这说明之前 7.6% 的收益是"偷看答案"产生的虚假 alpha。
但好消息是:在 T+1 框架下重新优化参数后,收益恢复到 15.6%——说明策略本身是有效的,只是需要不同的参数。
教训:如果一个策略在修正前视偏差后收益归零,说明它根本没有真实的盈利能力。
滑点(Slippage)
你看到屏幕上的价格是 10.00 元,点击"买入"后实际成交价可能是 10.01 元。这个差距就是滑点。
滑点的来源:
- 价格变动:从你看到价格到下单完成的几秒内,价格在变
- 市场冲击:你的买单推高了价格(尤其是买入量较大时)
- 买卖价差(Bid-Ask Spread):市场上卖家的报价总是比买家高一点
本系统默认假设 0.1% 的滑点,即买入时价格贵 0.1%,卖出时价格便宜 0.1%。对于主流 ETF(如沪深 300 ETF,日成交额几十亿),0.1% 是偏保守的估计。
过拟合(Overfitting)
量化交易最大的敌人。 如果你不理解过拟合,做量化大概率赔钱。
什么是过拟合?
你有 7 年的历史数据。你不停地调参数,直到在这 7 年上表现完美。但这些参数可能只是恰好适合这段历史,换一段时间就完全失效。
类比:考试 vs 做题
过拟合 ≈ 背答案
你把模拟题的答案全背下来了 → 模拟考 100 分!
但真正高考题不一样 → 考了 30 分
正确学习 ≈ 理解原理
你理解了解题方法 → 模拟考 85 分
真正高考 → 也能考 80 分
怎么识别过拟合?
| 信号 | 可能过拟合 | 可能真实 |
|---|---|---|
| 参数敏感度 | 改一点点参数就大幅变化 | 参数在一定范围内都表现不错(plateau) |
| 样本外表现 | 训练期很好,验证期很差 | 训练期和验证期都不错 |
| 交易频率 | 极少交易就获得高收益 | 足够多的交易形成统计意义 |
| 收益曲线 | 只在几笔关键交易上赚大钱 | 持续稳定地小赚 |
本系统通过 Walk-Forward 验证和随机扰动测试来检测过拟合(详见参数优化章节)。
6. 统计与评估术语
年化收益率(Annualized Return, CAGR)
把任意时间段的总收益折算成"每年赚多少"。
年化收益率 = (1 + 总收益率)^(1/年数) - 1
例子:
- 3 年总共赚了 72% → 年化 = (1.72)^(1/3) - 1 ≈ 19.8%
- 7 年总共赚了 180% → 年化 = (2.80)^(1/7) - 1 ≈ 15.9%
为什么不直接用总收益? 因为 “10 年赚 100%” 和 “1 年赚 100%” 完全不同。年化收益让不同时间段的策略可以公平比较。
波动率(Volatility)
衡量价格波动的剧烈程度。
年化波动率 = 日收益率的标准差 × √252
(252 是一年的交易日数)
直觉理解:
- 波动率 10%:大部分时间价格在 ±10% 的范围内波动,走势相对平稳(如国债 ETF)
- 波动率 30%:价格大起大落(如半导体 ETF),可能一个月涨 20% 然后跌 15%
- 波动率 50%:过山车行情(某些个股)
波动率不区分上涨和下跌——涨 10% 和跌 10% 对波动率的贡献是一样的。这是它的局限性,但也是最常用的风险衡量指标。
夏普比率(Sharpe Ratio)
量化界最核心的指标之一。衡量每承受一单位风险,获得了多少超额回报。
夏普比率 = (策略年化收益 - 无风险利率) / 策略年化波动率
无风险利率一般取国债收益率(约 2-3%)或简化为 0。
直觉理解:
| 场景 | 年化收益 | 波动率 | Sharpe | 含义 |
|---|---|---|---|---|
| 策略 A | 20% | 10% | 2.0 | 低风险高回报,极好 |
| 策略 B | 20% | 40% | 0.5 | 过山车式回报,勉强及格 |
| 策略 C | 5% | 30% | 0.17 | 承受了大风险但回报很差 |
| 余额宝 | 2% | 0.1% | 20 | 几乎无风险(但收益也很低) |
经验参考值(扣费后、样本外):
- Sharpe < 0:赔钱的策略
- 0 < Sharpe < 0.5:不如买基金
- 0.5 < Sharpe < 1.0:不错,值得关注
- 1.0 < Sharpe < 2.0:优秀
- Sharpe > 2.0:要么非常厉害,要么数据有问题
最大回撤(Max Drawdown, MDD)
从账户净值的历史最高点到随后最低点的最大跌幅。
例子:
账户变化:10万 → 15万 → 12万 → 18万 → 13万 → 20万
回撤 1:15万 → 12万 = -20%
回撤 2:18万 → 13万 = -27.8% ← 最大回撤
最大回撤是你投资过程中"最痛苦的时刻"。 它决定了你是否能坚持执行策略——如果你看到账户从高点跌了 30% 就受不了止损了,那最大回撤 30% 的策略不适合你。
一般建议:你能承受的最大回撤 = 你的实际容忍度 × 0.5。因为未来的回撤几乎一定比历史回测更大(回测有各种理想化假设)。
Calmar 比率
Calmar = 年化收益率 / |最大回撤|
它衡量每承受 1% 的最大回撤,能获得多少年化收益。
本系统的 Calmar = 15.62% / 19.45% ≈ 0.80,意思是每承受 1% 的回撤换回了 0.8% 的年化收益。
经验参考值:
- Calmar < 0.3:风险收益不成比例
- 0.3 < Calmar < 0.5:可接受
- 0.5 < Calmar < 1.0:不错
- Calmar > 1.0:优秀
超额收益(Alpha)
策略收益超出基准(比如"买入所有 ETF 等权持有不动")的部分。
超额收益 = 策略总收益 - 基准总收益 = 180.75% - 72.88% = 107.87%
这说明策略不只是"随大盘涨",而是通过主动的选择和风控,额外多赚了 107.87%。
胜率与赔率
| 指标 | 含义 | 本系统约值 |
|---|---|---|
| 胜率 | 赚钱交易占总交易的比例 | ~55% |
| 赔率(盈亏比) | 平均赚钱金额 / 平均亏钱金额 | ~1.8:1 |
一个策略可以胜率低但赔率高(每次赚很多但经常小亏),也可以胜率高但赔率低(经常小赚但偶尔大亏)。好的策略通常是 “胜率略高 + 赔率 > 1” 的组合。
换手率(Turnover)
一段时间内买卖的金额占总资金的比例。
年换手率 = 年内买卖总金额 / 平均持仓市值
换手率越高:手续费越多、滑点损耗越大。但换手率太低说明策略几乎不操作,可能错过机会。
第三部分:策略深度解析
7. 策略总览:一张图看懂整个系统
┌─────────────────────────────────────────────────────────────┐
│ 数据输入层 │
│ AkShare → 13只ETF日线收盘价 → 本地 parquet 缓存 │
└───────────────────────┬─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 信号生成层(每日运行) │
│ │
│ ① 动量排名 ─→ 得分 = 0.5×R20 + 0.3×R60 + 0.2×R120 │
│ 按得分从高到低排序 │
│ │
│ ② MA200过滤 ─→ 价格 < MA200 的 ETF 被剔除 │
│ │
│ ③ 正收益过滤 ─→ 得分 < 0 的 ETF 被剔除 │
│ 全部被剔除 → 切换到国债(避风港) │
│ │
│ ④ 相关性过滤 ─→ top_n 内两两 corr > 0.60 → 剔除弱者 │
│ │
│ ⑤ 波动率加权 ─→ 权重 ∝ 1/σ(波动大的买少点) │
│ 再受 max_position_pct=50% 硬性约束 │
│ │
│ ⑥ 调仓判断 ─→ 新组合 vs 当前组合:差距 > 8% 才换 │
│ 距上次建仓 < 15 天 → 不换(除非止损) │
└───────────────────────┬─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 风控层(每日运行) │
│ │
│ 追踪止损: 从持仓最高点回撤 > 25% → 立即卖出 + 冷却15天 │
│ MA200退出: 持仓跌破 MA200 → 立即卖出 │
│ │
│ 注意:止损检查优先于调仓判断,每天都执行 │
└───────────────────────┬─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 执行层 │
│ │
│ 回测模式: T+1 执行,昨日信号 → 今日收盘价成交 │
│ 实盘模式: 09:50 推送信号 → 你手动在券商 APP 下单 │
└─────────────────────────────────────────────────────────────┘
8. 第 1 层:动量排名 — 谁最近最强?
原理
对 13 只 ETF 中的每一只,计算一个"综合动量得分":
得分 = 0.5 × (过去20天涨了多少%) + 0.3 × (过去60天涨了多少%) + 0.2 × (过去120天涨了多少%)
然后按得分从高到低排序,取前 3 名。
为什么用三个时间窗口?
| 窗口 | 时间跨度 | 捕捉什么 | 权重 | 为什么这个权重 |
|---|---|---|---|---|
| 20 天 | 约 1 个月 | 短期爆发力 | 50% | 最灵敏,最快反映最新变化 |
| 60 天 | 约 3 个月 | 中期趋势 | 30% | 过滤掉短期噪音 |
| 120 天 | 约半年 | 长期方向 | 20% | 确认趋势不是昙花一现 |
如果只看 20 天:很容易被短期暴涨诱骗(比如一只 ETF 因为某个消息暴涨 3 天,但之后就回落了)。
如果只看 120 天:反应太慢,趋势已经走了一大半才发现。
多周期结合的效果:既能快速发现新趋势,又不会被短期噪音欺骗。
实际计算举例
假设今天是 2024 年 6 月 1 日:
| ETF | 20日涨幅 | 60日涨幅 | 120日涨幅 | 综合得分 |
|---|---|---|---|---|
| 半导体 | 15% | 25% | 40% | 0.5×15 + 0.3×25 + 0.2×40 = 23.0 |
| 纳指 | 8% | 12% | 20% | 0.5×8 + 0.3×12 + 0.2×20 = 11.6 |
| 黄金 | 5% | 10% | 15% | 0.5×5 + 0.3×10 + 0.2×15 = 8.5 |
| 红利 | 3% | 5% | 8% | 0.5×3 + 0.3×5 + 0.2×8 = 4.6 |
| 创业板 | -2% | -5% | -10% | 0.5×(-2) + 0.3×(-5) + 0.2×(-10) = -4.5 |
排名:① 半导体(23.0) ② 纳指(11.6) ③ 黄金(8.5) ④ 红利(4.6) ⑤ 创业板(-4.5)
取 top 3:半导体、纳指、黄金(但还要经过后续过滤层)。
这里的"涨幅"是怎么算的?
20日涨幅 = (今日收盘价 - 20天前收盘价) / 20天前收盘价
非常简单直接,不需要复杂的技术指标。这种简单性本身就是优势——越复杂的计算越容易过拟合。
9. 第 2 层:MA200 趋势过滤 — 大势向上吗?
原理
MA200(200 日移动平均线) = 过去 200 个交易日收盘价的算术平均值。
规则极其简单:
当前价格 > MA200 → 长期趋势向上 → 允许买入
当前价格 < MA200 → 长期趋势向下 → 禁止买入
为什么是 200 天?
200 天 ≈ 约 10 个月的交易日。这个数字不是随便选的:
- 学术来源:200 日均线是技术分析中最经典的"牛熊分界线",在全球各个市场上被广泛验证
- 经济含义:大约对应一个经济周期的"中段",足够长到能过滤掉短期波动,又不会太迟钝
- 自我实现:因为太多人在用 MA200,当价格跌破它时确实会引发集体抛售,使得它成为一个有意义的支撑/阻力位
实际作用:避免"接飞刀"
没有趋势过滤的动量策略有一个致命弱点:在下跌趋势中,短期反弹会被误判为"上涨动量"。
没有 MA200 过滤:
某 ETF 从 10 元暴跌到 5 元,然后反弹到 6 元
20日涨幅 = (6-5)/5 = 20% → 排名第 1!
但这只是"下跌途中的反弹",后续可能继续跌到 3 元
有 MA200 过滤:
MA200 = 8 元,当前价格 6 元 < MA200
直接剔除,不允许买入
避免了"抄底被套"
图示理解
价格
↑
15│ ╱╲
│ ╱ ╲
12│------╱--------╲-------- ← MA200
│ ╱ ╲
9│ ╱ ╲
│╱ ╲ ← 价格跌破 MA200:禁止买入
6│ ╲
│ ╲____
3│
└──────────────────────────→ 时间
← 可以买入区域 → ← 禁止买入区域 →
10. 第 3 层:绝对动量过滤 — 是真的在涨吗?
相对动量 vs 绝对动量
前面的排名是相对动量:13 只 ETF 之间比较,选最强的。
但有一个问题:如果所有 13 只 ETF 都在跌呢?
大熊市里的排名:
① 国债 -1% ← "最强"但也在亏
② 黄金 -3%
③ 红利 -5%
④ 沪深300 -15%
...
⑬ 半导体 -35%
如果只看相对排名,你会买入国债(-1%)、黄金(-3%)、红利(-5%)——但它们三个都在亏钱!
绝对动量过滤规则:动量得分 > 0 才允许买入。
得分 > 0 → 过去一段时间确实在涨 → 可以买
得分 ≤ 0 → 过去一段时间在跌 → 不买
如果所有 ETF 的得分都 ≤ 0,系统会把资金全部转移到避风港(国债 ETF)。
学术背景
绝对动量的概念由 Gary Antonacci 在 2014 年的著作《Dual Momentum Investing》中系统化提出。他证明了:将相对动量和绝对动量结合使用,可以显著降低回撤,同时保持大部分收益。
其逻辑是:相对动量告诉你"买什么",绝对动量告诉你"该不该买"。
11. 第 4 层:相关性过滤 — 真的分散了吗?
什么是相关性?
相关性(Correlation)衡量两只 ETF 走势的相似程度,取值范围 -1 到 +1:
相关性 = +1.0:完全同步,A涨B必涨,A跌B必跌
相关性 = +0.8:高度相似,大部分时间同涨同跌
相关性 = 0.0:完全无关,A的涨跌和B没有关系
相关性 = -0.5:反向关系,A涨时B大概率跌
相关性 = -1.0:完全反向
为什么需要相关性过滤?
如果没有这个过滤,你可能遇到这种情况:
排名前 3:① 半导体(23%) ② 创业板(21%) ③ 科创50(20%)
看起来分散了(3 只不同的 ETF),但实际上:
半导体 vs 创业板 相关性 = 0.85
半导体 vs 科创50 相关性 = 0.90
创业板 vs 科创50 相关性 = 0.88
它们本质上都是"A 股科技成长股",几乎同涨同跌!
你以为持有 3 只分散了风险,其实 ≈ 3 倍杠杆买了同一类资产。
如果科技股集体崩盘(比如 2022 年),你的 3 只持仓会同时暴跌,回撤会非常惨烈。
过滤规则
for 每只候选 ETF (按排名从高到低):
for 已选中的每只 ETF:
if 两者的 60 日相关性 > 0.60:
跳过这只候选,看下一个
选入这只 ETF
用前面的例子:
① 半导体(23%) → 选入(第一只直接选入)
② 创业板(21%) → 与半导体相关性 0.85 > 0.60 → 跳过!
③ 科创50(20%) → 与半导体相关性 0.90 > 0.60 → 跳过!
④ 纳指(15%) → 与半导体相关性 0.35 < 0.60 → 选入!
⑤ 红利(12%) → 与半导体相关性 0.10 < 0.60,与纳指相关性 0.20 < 0.60 → 选入!
最终选出:半导体 + 纳指 + 红利
这三只来自完全不同的风险来源(A股科技、美股科技、A股高股息),真正实现了风险分散。
为什么阈值是 0.60?
| 阈值 | 效果 |
|---|---|
| 0.90 | 太宽松,几乎不过滤,半导体+创业板都能同时入选 |
| 0.80 | 中等,部分相似品种仍可同选 |
| 0.70 | 较严格 |
| 0.60 | 当前设定:严格但不过分,保证真正分散 |
| 0.50 | 过于严格,可能选不满 3 只 |
0.60 的选择来自网格搜索和 Walk-Forward 验证——在多种参数下,0.60 都表现良好,而不是某个尖刺上的偶然最优。
60 日滚动相关性
相关性不是固定的,它会随时间变化。我们用最近 60 天的数据计算,而不是全部历史数据:
- 为什么不用全部历史? 因为 2019 年的相关性不代表 2025 年的。市场结构在变。
- 为什么是 60 天? 大约 3 个月,足够稳定,又能反映最近的市场结构。
12. 第 5 层:反向波动率加权 — 该买多少?
问题:选了 3 只 ETF,每只买多少?
最简单的做法是"等权"——每只买 1/3。但这有问题:
等权分配:
半导体(年化波动率 40%):33% 仓位
黄金 (年化波动率 15%):33% 仓位
红利 (年化波动率 12%):33% 仓位
组合的风险贡献:
半导体贡献了 40%/(40%+15%+12%) ≈ 60% 的组合风险!
你的组合 60% 的涨跌取决于半导体一只 ETF
等权分配让高波动资产主宰了整个组合。如果半导体暴跌,即使黄金和红利没跌,你的组合也会大幅亏损。
解决方案:反向波动率加权
核心思想:波动大的少买,波动小的多买,让每只 ETF 对组合风险的贡献大致相等。
权重 = (1/波动率) / Σ(1/波动率)
用同样的例子:
半导体 σ=40%: 1/0.40 = 2.50
黄金 σ=15%: 1/0.15 = 6.67
红利 σ=12%: 1/0.12 = 8.33
合计 = 2.50 + 6.67 + 8.33 = 17.50
最终权重:
半导体 = 2.50/17.50 = 14.3%
黄金 = 6.67/17.50 = 38.1%
红利 = 8.33/17.50 = 47.6%
对比:
| ETF | 等权 | 反向波动率 | 风险贡献(等权) | 风险贡献(反向波动率) |
|---|---|---|---|---|
| 半导体 | 33% | 14% | ~60% | ~33% |
| 黄金 | 33% | 38% | ~22% | ~33% |
| 红利 | 33% | 48% | ~18% | ~33% |
反向波动率加权后,三只 ETF 对组合风险的贡献大致相等——这就是风险平价(Risk Parity) 的核心思想。
为什么这样更好?
- 降低极端风险:不会因为一只高波动 ETF 的暴跌而导致组合崩溃
- 更平滑的收益曲线:组合的波动率被控制在更合理的水平
- 更好的夏普比率:在不牺牲太多收益的前提下降低波动
仓位上限:max_position_pct = 50%
即使反向波动率计算出某只 ETF 应该占 70%(比如国债,波动率极低),也会被硬性限制在 50%。这是一道安全阀——防止任何单一资产过度集中。
超出 50% 的部分会被按比例分配给其他 ETF。
13. 第 6 层:风控机制 — 什么时候跑?
风控是整个系统最重要的部分。消融分析(Ablation Study)显示,追踪止损和相关性过滤贡献了策略大部分的超额收益和回撤控制能力。
a) 追踪止损(Trailing Stop Loss)
核心思想:让利润奔跑,截断亏损。
这是趋势跟踪策略中最经典的退出机制。它不设固定止损价,而是跟踪持仓以来的最高价:
追踪止损触发条件:(当前价格 - 持仓期间最高价) / 持仓期间最高价 < -25%
详细流程:
Day 1: 买入 @ 10元, 最高价 = 10元
Day 5: 涨到 12元, 最高价更新为 12元
Day 10: 涨到 15元, 最高价更新为 15元 ← 利润在奔跑
Day 15: 跌到 14元, 回撤 (14-15)/15 = -6.7% < 25%, 不触发
Day 20: 跌到 12元, 回撤 (12-15)/15 = -20% < 25%, 不触发
Day 25: 跌到 11元, 回撤 (11-15)/15 = -26.7% > 25%, 触发止损!
卖出 @ 11元, 赚了 10%(虽然从最高点损失了 26.7%)
和固定止损的区别:
固定止损(比如亏 10% 就卖):
买入 10元 → 涨到 15元 → 跌到 9元
触发止损,总亏损 = -10%
问题:如果不设固定止损,可能在 15元时已经赚了50%
追踪止损(从最高点回撤 25%):
买入 10元 → 涨到 15元 → 触发条件 = 15 × 0.75 = 11.25元
只有跌到 11.25 才卖出,此时你还赚了 12.5%!
追踪止损的精妙之处:它是"非对称"的——在涨的时候永远不会触发(最高价不断上移),只有在跌的时候才可能触发。这完美匹配了"让利润奔跑,截断亏损"的理念。
b) MA200 紧急退出
如果一只持仓的 ETF 跌破了 200 日均线,即使追踪止损还没触发,也会强制卖出。
这是防范系统性风险的保险丝。当一只 ETF 跌破 MA200,通常意味着长期趋势已经掉头向下,不是简单的回调。
c) 追踪止损 vs MA200 退出的关系
┌─ 快速下跌(比如3周跌30%)
│ 追踪止损先触发
持仓 │
──────→ 价格下跌 ─────┤
│ 缓慢阴跌(比如3个月跌15%)
│ 追踪止损可能没触发(因为每天跌一点)
└─ 但 MA200 退出会触发(价格已低于长期均线)
两者互补:
- 追踪止损:应对快速暴跌(闪崩、黑天鹅)
- MA200 退出:应对缓慢阴跌(熊市初期的温水煮青蛙)
d) 止损冷却期(Stop Cooldown)
触发止损后,该 ETF 在 15 天内不允许重新买入。
为什么需要冷却期?想象没有冷却期的场景:
Day 1: 半导体跌 26% 触发止损 → 卖出
Day 2: 半导体小幅反弹 3% → 排名恢复到 top 3 → 又买入
Day 5: 半导体再次暴跌 20% → 又触发止损 → 又卖出
Day 6: 又反弹 → 又买入...
来来回回反复交易(whipsaw),每次都亏手续费和滑点
冷却期确保触发止损后有足够的观察期,等市场真正稳定后才考虑重新买入。
e) 切换阈值(Switch Threshold = 8%)
新标的的动量得分需要显著高于当前持仓才会触发换仓:
avg_新标的得分 - avg_当前持仓得分 > 8% → 换仓
avg_新标的得分 - avg_当前持仓得分 ≤ 8% → 继续持有
为什么需要这个阈值?
没有切换阈值:
Day 1: 半导体(12.1%) > 纳指(12.0%) → 买半导体
Day 2: 纳指(12.2%) > 半导体(12.1%) → 卖半导体买纳指
Day 3: 半导体(12.3%) > 纳指(12.2%) → 卖纳指买半导体
...每天买来卖去,手续费亏死
有 8% 切换阈值:
Day 1: 持有半导体(12%)
Day 2: 纳指(12.5%) - 半导体(12%) = 0.5% < 8% → 不换
Day 15: 军工(22%) - 半导体(10%) = 12% > 8% → 换!
8% 意味着只有当新标的显著更强时才换,避免了因微弱排名波动造成的频繁交易。
f) 最小持仓天数(min_hold_days = 15 天)
买入后至少持有 15 天才允许主动调仓(因排名变化而换仓)。
但两个例外不受此限制:
- 追踪止损触发 → 必须立即卖出
- MA200 紧急退出 → 必须立即卖出
为什么是 15 天?
- 太短(比如 5 天):频繁交易,手续费和滑点吃掉利润
- 太长(比如 30 天):反应迟钝,错过趋势切换
- 15 天 ≈ 3 周,是 A 股市场上中频趋势跟踪的经典窗口
g) 单只仓位上限(max_position_pct = 50%)
任何单只 ETF 的仓位不超过总资金的 50%。这是一道硬性红线。
即使波动率加权计算出国债 ETF 应该占 80%(因为它波动率极低),也会被限制在 50%。多出的比例会按比例分配给其他持仓。
14. 整体决策流程:用一个真实例子走一遍
假设今天是 2024 年 8 月 15 日,系统开始运行。
Step 1:获取数据
系统获取 13 只 ETF 的历史收盘价数据,构建收盘价矩阵。
Step 2:计算动量得分
ETF | 20日涨幅 | 60日涨幅 | 120日涨幅 | 综合得分 | MA200判断
─────────────┼─────────┼─────────┼──────────┼─────────┼─────────
半导体(512480)| +18% | +30% | +45% | 24.0 | 价格>MA200 ✓
纳指(513100) | +10% | +15% | +22% | 13.9 | 价格>MA200 ✓
军工(512660) | +8% | +12% | +20% | 11.6 | 价格>MA200 ✓
黄金(518880) | +6% | +8% | +10% | 7.4 | 价格>MA200 ✓
红利(510880) | +4% | +6% | +8% | 5.4 | 价格>MA200 ✓
银行(512800) | +3% | +4% | +5% | 3.7 | 价格>MA200 ✓
沪深300 | +1% | -2% | -5% | -0.6 | 价格<MA200 ✗
创业板(159915)| -3% | -8% | -15% | -6.9 | 价格<MA200 ✗
...(其余省略)
Step 3:层层过滤
全部 13 只
↓ MA200 过滤:沪深300、创业板等 5 只被剔除(长期趋势向下)
剩余 8 只
↓ 正收益过滤:所有 8 只得分 > 0 ✓(不需要切换到避风港)
剩余 8 只
↓ 取 top 3 候选:半导体(24.0), 纳指(13.9), 军工(11.6)
Step 4:相关性过滤
半导体 → 直接选入
纳指 → 与半导体的 60 日相关性 = 0.35 < 0.60 → 选入
军工 → 与半导体的 60 日相关性 = 0.45 < 0.60 ✓
与纳指的 60 日相关性 = 0.20 < 0.60 ✓ → 选入
最终候选:半导体 + 纳指 + 军工
Step 5:反向波动率加权
半导体 σ=35%: 1/0.35 = 2.86 → 权重 = 2.86/9.86 = 29.0%
纳指 σ=22%: 1/0.22 = 4.55 → 权重 = 4.55/9.86 = 46.1%
军工 σ=40%: 1/0.40 = 2.50 → 权重 = 2.50/9.86 = 25.4%
合计 = 9.86 - 这里没有超过max_position_pct限制
→ 仓位分配(假设总资金 10 万元):
半导体 2.90 万元
纳指 4.61 万元 (波动小,所以多买)
军工 2.54 万元 (波动大,所以少买)
Step 6:和当前持仓比较
假设当前持仓是"黄金 + 红利 + 银行"(防御性组合),平均得分 5.5。
新候选平均得分 = (24.0 + 13.9 + 11.6) / 3 = 16.5
当前持仓平均得分 = 5.5
差距 = 16.5 - 5.5 = 11.0 > 8%(切换阈值)
→ 触发调仓!卖出黄金/红利/银行,买入半导体/纳指/军工
Step 7:输出信号
📊 ETF 动量轮动信号
操作:调仓
原因:新标的领先当前持仓 11.0%,超过阈值 8%
卖出:
黄金ETF (518880) 全部卖出
红利ETF (510880) 全部卖出
银行ETF (512800) 全部卖出
买入:
纳指ETF (513100) 46.1% → ¥46,100
半导体ETF (512480) 29.0% → ¥29,000
军工ETF (512660) 25.4% → ¥25,400
15. 为什么这个策略有效?学术基础与历史验证
15.1 动量效应的学术证据
动量效应是金融学中最有力的实证发现之一,仅次于市场风险溢价(equity risk premium)。
重要研究:
| 年份 | 作者 | 发现 |
|---|---|---|
| 1993 | Jegadeesh & Titman | 美股 3-12 月动量策略年化超额收益 ~12% |
| 2007 | Asness, Moskowitz & Pedersen | 动量效应在股票、债券、外汇、商品中全部存在 |
| 2012 | Geczy & Samonov | 动量效应在美国市场上追溯到 1801 年都有效 |
| 2014 | Gary Antonacci | 提出 Dual Momentum,结合相对/绝对动量 |
在中国 A 股市场: 动量效应同样存在,但有自己的特点:
- 在行业/板块层面(如 ETF)比个股层面更显著
- 3-12 月的中期动量最有效,超短期(1 周以内)和超长期(12 月以上)可能反转
- A 股的动量周期比美股略短,与市场情绪化交易的特点有关
15.2 趋势跟踪的百年历史
趋势跟踪策略有超过 100 年的历史。最早的系统化趋势跟踪可以追溯到 1930 年代的 Richard Donchian。
过去一个世纪中,趋势跟踪策略在:
- 2000 年互联网泡沫破裂时成功避开暴跌
- 2008 年金融危机中获得正收益(做空或空仓)
- 2022 年全球通胀年中通过商品趋势获利
趋势跟踪有效的根本原因: 市场不是即时有效的。信息的传播和消化需要时间,大型机构的调仓需要数周甚至数月,这创造了持续的趋势。
15.3 风险平价的实践
桥水基金(Bridgewater)的 Ray Dalio 在 1996 年创建的 All Weather(全天候)基金,核心思想就是风险平价——让每类资产对组合贡献相等的风险。该基金在过去 25 年中表现出色,年化波动率仅 ~10%。
本系统的反向波动率加权是风险平价的简化版本——虽然不如桥水的多因子风险模型精确,但核心思想一致。
15.4 消融分析的结论
我们对系统的每个组件做了消融分析(逐个关闭,看影响):
| 模块 | 关闭后的影响 | 结论 |
|---|---|---|
| 追踪止损 | Sharpe 大幅下降,回撤大幅增加 | 最核心的模块——没有止损就没有这个系统 |
| 相关性过滤 | Sharpe 明显下降 | 第二重要——防止伪分散 |
| 反向波动率 | Sharpe 略有下降,回撤改善消失 | 有价值,降低了波动 |
| MA200 过滤 | Sharpe 轻微变化 | 贡献有限,但在大熊市中至关重要 |
| 绝对动量 | 几乎不变 | 大部分时候不触发,但在全面熊市中是救命稻草 |
关键洞察:这个系统的 alpha 主要来自"少亏"而不是"多赚"。 动量排名负责选出强势 ETF,但真正让策略脱颖而出的是追踪止损和相关性过滤——它们控制了回撤。
16. 策略的已知局限:它不能做什么?
任何策略都有弱点。诚实面对弱点比盲目自信更重要。
16.1 震荡市表现差
当市场在一个区间内反复横跳(没有明确趋势),动量策略会反复被"骗":
假涨 → 买入 → 跌回去 → 止损 → 又假涨 → 又买入 → 又跌...
每次操作都亏手续费和滑点。这种情况下策略会持续小亏。
应对方式: 接受它。震荡市的亏损是趋势策略在趋势市中大赚的"成本"。只要趋势市的利润 > 震荡市的亏损,长期就是赚钱的。
16.2 快速 V 形反转
2020 年 3 月 COVID 暴跌后极速反弹,从底部 2 周内涨了 20%+。
动量策略在暴跌时已经止损出场了,等信号重新确认趋势向上时,已经错过了大部分反弹。
应对方式: 这是趋势策略的天然弱点。V 形反转极其罕见,历史上大部分暴跌后是 U 形或 L 形恢复,趋势策略在这些情况下表现很好。
16.3 跨境 ETF 的特殊性
纳指 ETF(513100)、日经 ETF(513520)等跨境 ETF 存在特殊问题:
- 时区差异:纳斯达克在北京时间凌晨收盘,A 股的纳指 ETF 第二天开盘时已经"知道"了纳斯达克的涨跌,但我们的信号是用昨天的 A 股收盘价生成的
- 折溢价:跨境 ETF 的价格可能偏离其实际净值(因为跨时区交易、额度限制等原因),这在回测中无法完全模拟
- QDII 额度限制:大额买入时可能买不到,出现"限额"
应对方式: T+1 执行模型已经部分缓解了时区问题。但跨境 ETF 的实际滑点可能比假设的 0.1% 更大。
16.4 参数有失效风险
当前参数(min_hold=15, stop=25%, corr=0.60, switch=8%)是基于 2019-2025 年数据优化的。市场结构可能变化:
- 如果 A 股引入 T+0 制度,日内波动率会改变
- 如果 ETF 品种大幅扩容,相关性结构会变
- 如果出现极端通胀/通缩,所有资产可能同涨同跌(相关性趋近 1)
应对方式: 定期(每年一次)重新运行 Walk-Forward 验证,检查参数是否仍然有效。如果连续两年 OOS 收益为负,考虑暂停策略。
16.5 不适合所有市场环境
| 市场环境 | 预期表现 | 原因 |
|---|---|---|
| 牛市(单边上涨) | 很好 | 动量满仓进攻型资产 |
| 熊市(单边下跌) | 尚可 | 止损限制亏损,切入避风港 |
| 结构性牛市(部分板块涨) | 非常好 | 轮动到最强板块 |
| 震荡市(横盘无趋势) | 较差 | 反复被假突破欺骗 |
| 极端危机(流动性枯竭) | 未知 | 止损可能无法执行(跌停卖不出) |
17. ETF 池设计:为什么选这 13 只?
设计原则
ETF 池的设计不是随便挑的,遵循三个原则:
- 覆盖全球主要资产类别:A 股、美股、商品、债券
- 每个类别内选代表性最强的:不需要 5 只科技 ETF,1-2 只就够
- 类别之间低相关性:确保轮动有意义(如果全是 A 股科技股,那不叫轮动)
各类别详解
A 股宽基(2 只)
| ETF | 代表什么 | 特点 |
|---|---|---|
| 沪深 300 (510300) | 大盘蓝筹(银行、白酒、保险) | 稳健,波动率中等 |
| 创业板 (159915) | 科技成长(新能源、医药、半导体) | 高弹性,波动率高 |
两者的相关性约 0.6-0.7,各自代表不同的市场风格。
进攻型行业(2 只)
| ETF | 代表什么 | 特点 |
|---|---|---|
| 军工 (512660) | 国防军工板块 | 独立行情,受政策驱动 |
| 半导体 (512480) | 芯片和半导体产业 | 高波动,牛市弹性极大 |
这两只在牛市中弹性最大,但也是跌起来最猛的。
防御型行业(3 只)
| ETF | 代表什么 | 特点 |
|---|---|---|
| 红利 (510880) | 高股息蓝筹(银行、公用事业) | 低波动,熊市抗跌 |
| 银行 (512800) | 银行板块 | 估值极低,高分红 |
| 酒 (512690) | 白酒等消费龙头 | 长期增长稳定 |
这三只在熊市中跌幅远小于进攻型 ETF,是"防御阵线"。
海外权益(3 只)
| ETF | 代表什么 | 特点 |
|---|---|---|
| 纳指 (513100) | 美国科技巨头(苹果、微软、英伟达) | 和 A 股相关性低,是天然的分散工具 |
| 中概互联 (513050) | 在美上市的中国科技公司(腾讯、阿里) | 兼具中美两个市场的特点 |
| 日经 (513520) | 日本股市(丰田、索尼) | 和 A 股极低相关性 |
海外 ETF 是分散风险的利器——当 A 股下跌时,纳指和日经可能在涨。
商品(2 只)
| ETF | 代表什么 | 特点 |
|---|---|---|
| 黄金 (518880) | 国际金价 | 经典避险资产,通胀对冲 |
| 能源化工 (159981) | 石油、天然气等 | 和股市低相关,但波动大 |
债券(1 只)
| ETF | 代表什么 | 特点 |
|---|---|---|
| 国债 (511010) | 中国国债 | 避风港——股市暴跌时资金的避难所 |
被排除的 ETF 及原因
| ETF | 排除原因 |
|---|---|
| 科创 50 (588000) | 和半导体 ETF 相关性 > 0.85,重复 |
| 新能源车 ETF | 和创业板 ETF 相关性 > 0.80,重复 |
| 医药 ETF | 和创业板有中等相关性,池子已有 |
| 原油 LOF | 展期损耗严重,跟踪误差大,不适合趋势跟踪 |
| 德国 DAX ETF | 和纳指有一定相关性,池子已有海外品种 |
第四部分:从回测到实盘
18. 什么是回测?为什么不能只看回测?
回测的本质
回测 = 时间旅行模拟器。
假装你在 2019 年 1 月 1 日拿了 10 万元,从那天起每天按策略规则操作。计算机帮你快进到 2025 年,告诉你一共赚了多少、亏了多少、最大回撤多少。
回测的价值
- 验证逻辑:策略的基本逻辑在历史数据上是否成立
- 估计风险:最大回撤大约多少,亏损的持续时间多久
- 参数范围:哪些参数范围是合理的
- 排除垃圾策略:如果回测都赚不了钱,实盘更不可能
回测的陷阱
但回测有很多陷阱,如果你不了解,很容易被自己的回测结果骗了。
陷阱 1:过拟合(最常见)
你测试了 1000 种参数组合 → 挑出表现最好的那个
问题:1000 组里,即使全是随机策略,也一定有几个看起来很厉害(纯运气)
类比: 让 1000 只猴子预测股市,总有一两只碰巧预测对了 7 年。你能说那只猴子"有能力预测股市"吗?
解决方案: Walk-Forward 验证(见下一节)。
陷阱 2:前视偏差
用了"未来信息"做决策(比如用今天的收盘价做今天的交易信号)。本系统已经修复为 T+1 执行。
陷阱 3:幸存者偏差
只测试了"活到今天"的 ETF。那些退市的、合并的 ETF 不在你的测试数据里,但它们曾经存在过。因为 ETF 退市概率极低(不像个股),这个问题在 ETF 策略中不算严重。
陷阱 4:滑点和手续费低估
回测假设 0.1% 滑点和万三手续费。如果实际滑点是 0.5%(某些小盘 ETF),利润会被大幅侵蚀。
陷阱 5:回测曲线不等于实盘体验
回测是"事后看"整条净值曲线——你知道 2022 年亏了之后 2023 年会涨回来。但在实盘中,你身处 2022 年底,不知道 2023 年会不会继续亏。这种心理压力是回测无法模拟的。
19. 参数优化的正确姿势:怎么避免自欺欺人?
param_optimize.py 包含 6 个研究模块,它们的目的不是"找到最赚钱的参数",而是验证策略是否真正有效。
模块 1:Grid Search(网格搜索)
做什么: 穷举所有参数组合,找出表现最好的。
搜索空间(示例):
min_hold_days: [5, 8, 10, 12, 15, 20, 25] ← 7 个选项
trailing_stop: [15%, 18%, 20%, 22%, 25%, 28%] ← 6 个选项
corr_threshold: [0.55, 0.60, 0.65, 0.70, 0.80] ← 5 个选项
switch_threshold: [4%, 6%, 8%, 10%] ← 4 个选项
总组合数 = 7 × 6 × 5 × 4 = 840 种
怎么排名: 使用多目标评分(不只看 Sharpe):
综合得分 = 0.4 × Sharpe + 0.3 × Calmar + 0.2 × CAGR - 0.1 × 换手率
这样既要赚钱,又要控制回撤,还要避免过度交易。
关键警告: 网格搜索的结果是全样本最优(In-Sample),存在过拟合风险。它的输出最后会打印警告:“以上为 IS (全样本) 最优,存在过拟合风险。请以 Walk-Forward OOS 结果为准。”
模块 2:Ablation Study(消融分析)
做什么: 逐个关闭策略的每个组件,看它到底有多大贡献。
配置说明:
"Full" = 完整系统
"No Trail Stop"= 关闭追踪止损
"No Corr" = 关闭相关性过滤
"No InvVol" = 关闭反向波动率,改用等权
"No MA200" = 关闭趋势过滤
"Bare" = 只留动量排名,关闭所有增强模块
怎么看结果:
CAGR MaxDD Sharpe
Full 15.6% -19.5% 0.90 ← 完整系统
No Stop 3.2% -45.0% 0.10 ← 止损贡献巨大
No Corr 8.1% -32.0% 0.45 ← 相关性过滤很重要
No InvVol 13.1% -24.0% 0.71 ← 波动率加权有帮助
No MA200 14.8% -21.0% 0.83 ← MA200 贡献较小
Bare 1.5% -55.0% -0.05 ← 裸动量几乎不赚钱
这张表告诉你一个深刻的事实:这个策略赚钱主要不是因为"选得准",而是因为"控制得好"。 止损和相关性过滤贡献了大部分的 alpha。
模块 3:Sensitivity Curves(敏感度分析)
做什么: 每次只改一个参数,其他不变,看 Sharpe 怎么变。
怎么看结果:好的结果应该是"高原"(plateau),坏的结果是"尖刺"(spike):
好的(plateau,鲁棒): 坏的(spike,过拟合):
Sharpe Sharpe
^ ^
1.0│ ████████ 1.0│ █
│ ██ ██ │ █ █
0.5│██ ██ 0.5│ ██ ██
│ ██ │ ██ ██
0.0│ █ 0.0│██ ██
└──────────────────→ └──────────────→
15% 18% 20% 22% 25% 15% 18% 20% 22% 25%
trailing stop trailing stop
← 20%-25% 都行,很稳定 → ← 只有 22% 好,前后骤降 →
本系统的追踪止损参数在 20%-28% 范围内表现都不错(plateau),说明这个参数是稳定的。
模块 4:Slippage Stress Test(滑点压力测试)
做什么: 测试策略在更大滑点下还能不能赚钱。
滑点 | Sharpe | 年化收益
──────┼────────┼─────────
0.1% | 0.90 | 15.6% ← 默认假设
0.2% | 0.83 | 14.2% ← 略有衰减
0.3% | 0.75 | 12.8% ← 仍然可观
0.5% | 0.61 | 10.1% ← 开始明显衰减
1.0% | 0.35 | 5.8% ← 勉强有盈利
怎么解读: 如果 0.3% 滑点下策略仍然有正的 Sharpe,说明策略不是"靠微小价差赚钱",有真实的 alpha。
模块 5:Walk-Forward Validation(最重要!)
做什么: 模拟"每年用历史数据优化参数,然后用下一年的新数据验证"。
这是识别过拟合最有效的方法。
第 1 轮:
训练集: 2019-2021(用这 3 年找最优参数)
↓ 找到: min_hold=10, stop=22%
测试集: 2022(用 2022 年验证,这一年模型没见过)
第 2 轮:
训练集: 2020-2022
↓ 找到: min_hold=15, stop=25%
测试集: 2023
第 3 轮:
训练集: 2021-2023
↓ 找到: min_hold=12, stop=22%
测试集: 2024
真实结果(详见文档顶部的 Walk-Forward 验证表格): 5 轮中 3 轮样本外收益为正(+14.4%, +14.1%, +16.6%),且 corr=0.60, switch=0.08 在所有轮次中保持一致。
关键判断标准:
- OOS(样本外)的 Sharpe 平均 > 0 → 策略有真实盈利能力
- OOS Sharpe ÷ 训练 Sharpe > 0.5 → 过拟合不严重
- 每轮选出的参数比较接近 → 参数稳定,不是碰巧
一句话总结 Walk-Forward 的意义: 它回答的问题不是"这个参数最优吗?“而是"这个策略在没见过的数据上还能赚钱吗?”
模块 6:Random Perturbation(随机扰动测试)
做什么: 随机微调最优参数 80 次,看 Sharpe 的分布。
真实结果(详见文档顶部的随机扰动测试表格): 80 次扰动中 73.8% 保持正 Sharpe,中位数 0.41。说明策略具备合理的鲁棒性。
需要诚实面对的是:中位数 0.41 而非 0.90,说明最优参数确实有一定的运气成分。但大多数扰动仍然盈利,证明策略的底层逻辑(动量 + 风控)是有效的。
20. 回测结果深度解读
完整的绩效指标、消融分析、参数敏感度、Walk-Forward、滑点压力、随机扰动等真实数据已在本文档顶部的"回测实绩总览"中详细展示,此处对数字的含义做深入解读。
绩效总览怎么理解
- 年化 15.62% 好不好? 余额宝约 2%,沪深 300 长期年化约 8%,公募基金前 1/4 约 15-20%。这个收益处于公募基金头部水平。但请注意,这是全样本最优参数下的结果,Walk-Forward 样本外的平均年化收益会更低。
- Sharpe 0.90 好不好? 专业量化基金的目标通常是 Sharpe > 1.0。0.90 已经接近了。随机扰动测试显示中位数 Sharpe 为 0.41,这更接近"真实"水平。
- 最大回撤 -19.45% 是什么概念? 同期沪深 300 最大回撤超过 -35%。策略的回撤控制显著优于大盘。但实盘回撤几乎一定会比回测更大。
逐年收益解读
年份 | 收益率 | 市场环境 | 策略表现分析
─────┼────────┼──────────────────────┼───────────
2020 | +85.7% | 科技大牛市 | 动量精确抓住了科技+黄金行情
2021 | +15.2% | 核心资产高位震荡 | 轮动到周期板块,获得正收益
2022 | -8.6% | 全面熊市(沪深300 -21%)| 止损和避风港机制限制了亏损
2023 | +18.3% | AI+日经行情 | 抓住了纳指和日经的趋势
2024 | +12.1% | 红利+黄金行情 | 成功轮动到低波防御资产
2025 | +23.5% | 科技反弹 | 重回进攻型资产
关键观察:
- 牛市中(2020)赚得最多——动量策略的天然优势
- 熊市中(2022)亏损远小于大盘——风控机制在工作
- 没有连续两年亏损——策略的"适应性"较好
图表解读(output/backtest_result.png)
上图(净值曲线):
- 蓝线(Strategy):策略的累计净值
- 灰线(Benchmark):如果买入所有 13 只 ETF 等权持有不动
- 绿色竖线:买入操作
- 红色竖线:卖出操作
- 蓝线在大部分时间位于灰线之上 → 策略跑赢了基准
中图(回撤):
- 红色面积越深,回撤越大
- 最深处就是最大回撤的位置
- 理想的回撤图是"浅而短"——跌得少、恢复得快
下图(ETF 走势):
- 显示了每只 ETF 的标准化走势
- 可以看出不同资产类别的涨跌周期差异很大
- 这正是轮动策略的机会所在
21. 从回测到实盘的关键差异
回测是理想化的,实盘会面对很多回测不考虑的问题:
21.1 执行延迟
回测:信号出来 → 0 延迟 → 以收盘价成交
实盘:信号 09:50 出来 → 你打开 APP → 输入代码 → 下单
可能已经过去了 5 分钟,价格变了
影响: 通常不大(ETF 的日内波动不太剧烈),但在大行情日(开盘涨/跌停)可能差很多。
21.2 滑点差异
回测假设固定 0.1% 滑点。实盘的滑点取决于:
- ETF 的流动性(成交额越大,滑点越小)
- 你的下单金额(金额越大,滑点可能越大)
- 下单时间(开盘和收盘附近波动大,滑点也大)
建议: 尽量在 10:00-11:00 或 13:30-14:30 下单,避开开盘和收盘的波动。
21.3 心理因素
回测没有心理压力,但实盘中你会面对:
- “亏了 15% 了,要不要止损?还是再等等?” → 策略说止损就止损
- “这只 ETF 在跌,但我’感觉’它要涨回来” → 别猜,执行策略
- “连续 3 次换仓都亏了,策略是不是有问题?” → 正常波动,坚持执行
最重要的一条纪律:策略说什么就做什么,不加入主观判断。 如果你经常覆盖策略的信号,那你做的就不是量化交易,只是"用了一个花哨工具的主观交易"。
21.4 建议的上线流程
第 1 个月:纸上交易(Paper Trading)
每天看信号,记录下来,但不实际操作
月底对比:你记录的信号 vs 实际市场走势
第 2-3 个月:小资金实盘
投入 1-2 万元,严格按信号操作
对比回测和实盘的差异(滑点、执行时机等)
第 4 个月起:逐步加仓
确认实盘表现与回测基本一致后
每月增加投入,直到达到你的目标仓位
第五部分:动手操作
22. 快速开始:5 分钟跑通
前提条件
- Python 3.10 或更高版本
- macOS / Linux(Windows 也可以,但定时任务需要改用 Task Scheduler)
步骤
# 进入项目目录
cd etf-momentum
# 1. 创建 Python 虚拟环境(隔离依赖,不污染系统 Python)
python3 -m venv .venv
source .venv/bin/activate # macOS/Linux
# .venv\Scripts\activate # Windows
# 2. 安装依赖
pip install -r requirements.txt
# 3. 下载全量历史数据(首次约 30 秒,数据存到 data/ 目录)
python download_data.py
# 4. 运行回测(用历史数据模拟交易)
python run_backtest.py
# 5. 获取今日实盘信号
python run_live.py
# 6.(可选)安装每日定时任务
bash setup_cron.sh
依赖说明
| 库 | 版本要求 | 用途 |
|---|---|---|
| akshare | >=1.14.0 | 获取 A 股 ETF 历史数据(免费、无需注册) |
| pandas | >=2.0.0 | 数据处理和分析(DataFrame 操作) |
| numpy | >=1.24.0 | 数学计算(向量化运算) |
| pyyaml | >=6.0 | 读取 config.yaml 配置文件 |
| matplotlib | >=3.7.0 | 绘制回测图表(净值曲线、回撤) |
| requests | >=2.31.0 | HTTP 请求(企业微信/飞书 webhook 通知) |
| tabulate | >=0.9.0 | 格式化表格输出(通知消息的排版) |
| schedule | >=1.2.0 | Python 层面的定时任务调度 |
23. 详细使用指南
23.1 下载数据
python download_data.py
首次运行会从新浪财经(通过 AkShare 库)下载所有 13 只 ETF 的全部历史日线数据,存储为 data/{代码}.parquet 格式(一种高效的列式存储格式,比 CSV 快很多)。后续运行只追加新交易日的数据(增量更新)。
23.2 运行回测
# 默认回测(2019-01-01 至今,10万初始资金)
python run_backtest.py
# 自定义日期区间
python run_backtest.py --start 2020-01-01 --end 2024-12-31
# 自定义初始资金
python run_backtest.py --capital 500000
# 强制重新下载数据(不用本地缓存)
python run_backtest.py --no-cache
23.3 获取实盘信号
# 今日信号
python run_live.py
# 指定当前持仓(如果你之前手动买了某些 ETF)
python run_live.py --holding 159915,518880
# 启动定时模式(09:50 和 15:05 自动运行)
python run_live.py --schedule
23.4 参数优化
# 运行全部 6 项测试
python param_optimize.py
# 快速模式(缩小搜索空间)
python param_optimize.py --fast
# 只跑指定模块
python param_optimize.py --only grid,ablation
python param_optimize.py --only wf # 只跑 Walk-Forward
23.5 设置通知推送
在 config.yaml 中填入 webhook 地址:
notify:
wecom_webhook: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=你的KEY"
feishu_webhook: "https://open.feishu.cn/open-apis/bot/v2/hook/你的KEY"
如何获取 webhook:
- 企业微信:群聊 → 右上角设置 → 群机器人 → 添加 → 复制 webhook 地址
- 飞书:群聊 → 设置 → 群机器人 → 添加自定义机器人 → 复制 webhook 地址
23.6 安装每日定时任务
bash setup_cron.sh
这会在 macOS 上创建 launchd 定时任务,每个工作日 09:50 和 15:05 自动运行。程序内部会自动判断是否为真实 A 股交易日(使用新浪交易日历 + 节假日 API),非交易日自动跳过。
24. 参数说明:每个数字的含义
所有参数集中在 config.yaml 文件中。
策略参数
| 参数 | 当前值 | 含义 | 调大 | 调小 |
|---|---|---|---|---|
momentum_windows |
20/60/120 天 | 计算动量用的回看窗口 | 更关注长期(慢、稳) | 更关注短期(快、噪音多) |
top_n |
3 | 同时持有几只 ETF | 更分散、稳定但收益稀释 | 更集中、弹性大但风险高 |
trend_filter_ma |
200 天 | 趋势判断均线长度 | 更慢的牛熊切换,减少假信号 | 更快反应,但更多 whipsaw |
min_hold_days |
15 天 | 最短持有时间 | 更少交易、省手续费 | 更灵敏但可能频繁换仓 |
switch_threshold |
8% | 新标的必须领先多少才换 | 更难换仓、减少噪音交易 | 更易换仓、可能追涨杀跌 |
corr_threshold |
0.60 | 两只同持 ETF 的相关性上限 | 允许更相似的 ETF 同持 | 要求更低相关性、真分散 |
trailing_stop |
25% | 从最高点回撤多少止损 | 更难触发(给更多空间) | 更易触发(更早止损) |
safe_haven |
511010 | 避风港 ETF 代码 | - | - |
风控参数
| 参数 | 当前值 | 含义 |
|---|---|---|
max_position_pct |
50% | 单只 ETF 最大仓位占比 |
回测参数
| 参数 | 当前值 | 含义 |
|---|---|---|
start_date |
2019-01-01 | 回测起始日期 |
initial_capital |
100000 | 初始资金(元) |
commission_rate |
0.0003 | 券商手续费率(万三,即 0.03%) |
slippage |
0.001 | 假设滑点(0.1%) |
25. 实盘运行:每天自动推送信号
工作流程
每日 09:50(定时触发)
│
├─ 判断是否为交易日(查交易所日历 → 节假日 API → weekday 兜底)
│ 非交易日 → 记录日志,退出
│
├─ 获取最新 ETF 数据
│
├─ 检查追踪止损(每天都检查,不受 min_hold_days 限制)
│ 触发 → 生成卖出信号 + 设置 15 天冷却期
│
├─ 计算动量排名和调仓信号
│
├─ 应用冷却期过滤(被止损的 ETF 不允许立即重买)
│
├─ 保存状态到 state.yaml
│
└─ 推送通知(企业微信 / 飞书)
state.yaml 状态文件
holdings: # 当前持仓的 ETF 代码列表
holding_names: # 当前持仓名称
peak_prices: # 每只持仓的买入后最高价(用于追踪止损计算)
last_entry_date: # 上次建仓日期(控制 min_hold_days)
cooldown_until: # 止损冷却期记录(ETF代码: 冷却到期日期)
last_run_date: # 上次成功运行日期
交易日判断的三层数据源
- 新浪交易所日历(最权威):包含所有 A 股交易日,4 小时缓存刷新
- 节假日 API(备选):
holiday.dreace.top+timor.tech - Weekday 判断(兜底):如果前两个 API 都挂了,按周一到周五处理
26. 项目结构:每个文件是干什么的
etf-momentum/
│
├── config.yaml # 策略配置(ETF池 + 参数 + 回测 + 通知)
├── requirements.txt # Python 依赖
│
├── download_data.py # 数据下载(首次全量 + 增量更新)
├── run_backtest.py # 回测入口(历史模拟 + 绩效 + 图表)
├── run_live.py # 实盘信号(每日运行 + 通知推送)
├── param_optimize.py # 参数优化(6个研究模块)
├── setup_cron.sh # 定时任务安装(macOS/Linux)
│
├── src/ # 核心源代码
│ ├── config_loader.py # 读取配置文件
│ ├── data.py # 数据获取、缓存、收盘价矩阵
│ ├── strategy.py # 策略引擎(动量+排名+过滤+信号)
│ ├── backtest.py # 回测引擎(模拟买卖+净值+指标)
│ ├── risk.py # 风控模块
│ ├── notify.py # 通知推送(企业微信/飞书)
│ └── visualize.py # 图表绘制
│
├── data/ # 本地数据(.parquet 格式)
├── output/ # 回测图表 + 优化结果CSV
├── state.yaml # 实盘运行状态
└── logs/ # 定时任务日志
数据流
AkShare (新浪财经)
│
▼
download_data.py → data/*.parquet (本地持久化)
│
▼
build_close_matrix() → 收盘价宽表 (行=日期, 列=ETF代码)
│
├──→ run_backtest.py → 回测结果 + 图表
├──→ param_optimize.py → 参数研究
└──→ run_live.py → 实盘信号 → 通知推送
第六部分:附录
27. 常见问题
Q: 数据下载失败怎么办?
AkShare 从新浪财经获取数据,偶尔会被限流。等 2-3 分钟再试。如果持续失败,可能是 AkShare 版本需要更新:pip install --upgrade akshare
Q: 回测和实盘结果会不一样吗?
会有小的差异,来源:
- 滑点差异:回测假设 0.1%,实际可能更大或更小
- 执行时间:回测用收盘价,你下单时的价格和收盘价不同
- 人为延迟:信号 09:50 出来后你多久能下单
Q: 我应该投多少钱?
建议从 1-5 万元开始。先模拟跟踪 3 个月,确认实际信号和回测基本一致后再逐步加仓。总投入不建议超过可投资资产的 20%。
Q: 每天需要操作吗?
不需要。大部分时间信号是"继续持有"。只有在以下情况需要操作:
- 调仓日(约每 15+ 天)且排名发生显著变化
- 追踪止损被触发
- MA200 紧急退出被触发
Q: 手续费怎么算?
- 券商佣金:万三(0.03%),买和卖各收一次
- 印花税:ETF 免征(这是 ETF 的一大优势)
- 滑点:约 0.1%
7 年 129 笔交易,总手续费约 ¥2,566,占初始资金 2.5%。
Q: 如何修改 ETF 池?
编辑 config.yaml 的 etf_pool 部分。每只 ETF 需要 code、name、market(sh/sz)、category。修改后重新下载数据:python download_data.py
Q: 如果某只 ETF 停牌了怎么办?
系统使用前向填充(ffill)处理缺失数据——停牌期间使用最后一个交易日的价格。因此动量得分会逐渐"过期",该 ETF 可能在排名中下降并被自动替换。
Q: 策略适合什么类型的投资者?
- 能接受 20-30% 的账户回撤
- 有 3 年以上的投资耐心
- 能严格遵守机器信号,不凭感觉操作
- 不需要每天盯盘
28. 风险提示
-
回测收益不代表未来收益。 过去 7 年年化 15.6%、Sharpe 0.90 不保证未来也能做到。市场环境会变化。
-
最大回撤 -19.45% 是历史最差情况,未来可能更差。 做好心理准备:你的账户可能从高点跌 20-30%。
-
不要把全部资产投入。 建议用可承受损失的资金,占总资产 5-20%。
-
系统只提供信号,不自动下单。 人为因素(犹豫、贪婪、恐惧)可能导致偏离策略。
-
A 股 ETF 存在特殊风险:
- 跨境 ETF(纳指、日经)有时区差和折溢价问题
- 长假期间无法交易但海外市场在波动
- 某些 ETF 流动性不足时买卖价差可能很大
-
过拟合风险始终存在。 尽管通过 Walk-Forward 验证了参数稳定性,市场结构的根本性变化仍可能导致策略失效。
-
建议的使用方式:
- 先跑回测,理解策略特性
- 用 Walk-Forward 验证参数不是过拟合
- 模拟跟踪 3 个月,对比实际信号和回测
- 小资金实盘,逐步放大
- 严格按信号操作,不自作主张修改
- 每年重新运行一次 Walk-Forward 验证参数有效性
29. 延伸阅读
如果你想更深入地理解量化交易和本系统背后的理论:
入门书籍
- 《漫步华尔街》(Burton Malkiel)— 理解市场的基本运作
- 《聪明的投资者》(Benjamin Graham)— 价值投资的基础
- 《量化投资策略与技术》— 国内量化入门教材
进阶书籍
- 《Dual Momentum Investing》(Gary Antonacci)— 本系统动量部分的直接理论来源
- 《Trend Following》(Michael Covel)— 趋势跟踪策略的圣经
- 《Advances in Financial Machine Learning》(Marcos Lopez de Prado)— 现代量化研究方法
学术论文
- Jegadeesh & Titman (1993) “Returns to Buying Winners and Selling Losers” — 动量效应的开创性论文
- Asness, Moskowitz & Pedersen (2013) “Value and Momentum Everywhere” — 动量在全球各资产类别的证据
- Baltas & Kosowski (2013) “Momentum Strategies in Futures Markets and Trend-following Funds” — 趋势跟踪的系统化研究
Python / 量化工具
- AkShare 文档 — 本系统使用的数据源
- Pandas 文档 — 数据处理核心库
- Backtrader — 另一个 Python 回测框架(本系统自研引擎)
免责声明
本文档及相关策略仅供学习和研究目的,不构成任何投资建议。
- 历史回测结果不代表未来表现。 文中展示的 15.62% 年化收益率、0.90 夏普比率等数据均为历史回测结果,基于理想化的执行假设,实际投资可能产生与回测完全不同的结果,包括本金的重大损失。
- 源代码不对外公开。 为防止不了解策略原理的人直接照搬代码造成亏损,本项目源代码仅限内部使用。
- 投资有风险,入市需谨慎。 任何人基于本文档中的信息做出的投资决策,需自行承担全部风险和责任。
- 过拟合风险始终存在。 尽管我们通过 Walk-Forward 验证、随机扰动、滑点压力测试等多种方法检验了策略的鲁棒性,但无法完全排除过拟合的可能。
- 市场结构会变化。 当前参数基于 2019-2025 年数据,未来市场环境可能根本性改变。