07_MACD金叉 · 回测实录
12只ETF各自判断MACD金叉买入、死叉卖出,最多同时持有3只。
策略类型:趋势跟踪 / 指标
回测批次:2026-10-06(本地 QuantStudio 回测引擎)
数据来源:QuantStudio 本地行情库(etf_daily/stock_daily)
一、策略思路
MACD是最经典的趋势指标:快线 EMA12 上穿慢线 EMA26 叫"金叉",视为趋势转多;反向下穿叫"死叉",视为趋势结束。策略把这套判断分别套在12只ETF上——谁出金叉就买谁,谁出死叉就卖谁。最多同时持有3只;如果同一天有超过3只出现金叉,就按 DIF 值(快线减慢线的差值)排序,优先买趋势更强的那几只,每只占总资产的约1/3。
关键参数
| 参数 | 取值 |
|---|---|
FAST | 12 |
SLOW | 26 |
SIGNAL | 9 |
MAX_HOLDINGS | 3 |
EXPOSURE | 0.98 |
二、回测设置
| 项目 | 设置 |
|---|---|
| 策略文件 | 07_MACD金叉.py |
| 回测区间 | 2022-01-01 ~ 2026-09-01 |
| 初始资金 | 100000 元 |
| 佣金费率 | 0.00035(最低 5.0 元) |
| 印花税率 | 0.001 |
| 过户费率 | 1e-05 |
| 滑点 | 0.0 |
| 撮合价格 | close |
| 基准 | 000300 |
| 交易日数 | 1130 |
三、回测结果
净值曲线会非常"趋势策略":2022、2023连续两年小幅磨损,2025年跟着一轮上涨快速拉升(+37.1%),2026年又吐回一部分。请把"累计收益"和"最大回撤"两个数字放在一起看:4年半赚22%,中途却出现过30%的回撤,年化波动率17.9%,风险调整后收益(夏普0.088)几乎为零。这就是趋势策略的真实面目——不是不赚,而是赚得极不稳定。
绩效指标
| 指标 | 数值 |
|---|---|
| 累计收益 | 22.04% |
| 年化收益 | 4.51% |
| 最大回撤 | 30.01% |
| 年化波动率 | 17.85% |
| 夏普比率 | 0.088 |
| 索提诺比率 | 0.132 |
| 卡玛比率 | 0.150 |
| 回合胜率 | 44.06% |
| 日胜率 | 50.18% |
| 盈亏比 | 132.2% |
| 盈利回合数 | 63 |
| 亏损回合数 | 80 |
| 平均持仓天数 | 80.5 |
| 成交笔数 | 315 |
「盈亏比」= 平均盈利 ÷ 平均亏损 > 100%,表示平均每笔赚的比亏的多。
「回合」指一次完整的买入→卖出(round_trips),「成交笔数」是买卖双方分开计数的原始成交记录条数。
⚠️本窗口基准数据不完整:引擎的基准序列尾部为占位填充值,据此算出的沪深300收益为 0.00%,该数字不可信;净值图中的基准曲线已截断至有效区间(至 2026-07-31)。因此本策略的α、β、超额收益、信息比率等相对指标一律不可引用,只能用绝对收益与回撤来判断。
分年度收益
| 年份 | 区间收益 | 交易日 |
|---|---|---|
| 2022 | -11.25% | 242 |
| 2023 | -3.02% | 242 |
| 2024 | 11.50% | 242 |
| 2025 | 37.14% | 243 |
| 2026 | -4.65% | 161 |
四、交易明细
- 完整交易回合数:143个(盈利 63 / 亏损 80)
- 单笔平均盈亏:+227.73 元;最大单笔盈利+10974.54 元;最大单笔亏损-5382.51 元
- 持仓天数:平均80.5 天,最长1336 天,最短1 天
盈利最多的 5 个回合
| 买入日 | 卖出日 | 标的 | 盈亏(元) | 持仓天数 |
|---|---|---|---|---|
| 2022-05-05 | 2022-07-04 | 516160.SH | +10974.54 | 60 |
| 2026-04-02 | 2026-05-06 | 515880.SH | +10323.38 | 34 |
| 2024-09-09 | 2024-10-24 | 512880.SH | +10002.25 | 45 |
| 2025-06-09 | 2025-08-08 | 515880.SH | +9798.39 | 60 |
| 2025-12-01 | 2026-01-21 | 512660.SH | +9311.18 | 51 |
亏损最多的 5 个回合
| 买入日 | 卖出日 | 标的 | 盈亏(元) | 持仓天数 |
|---|---|---|---|---|
| 2022-01-04 | 2022-03-16 | 512170.SH | -5382.51 | 71 |
| 2023-11-22 | 2024-01-18 | 512690.SH | -4566.53 | 57 |
| 2022-01-17 | 2022-02-11 | 516160.SH | -4026.28 | 25 |
| 2026-05-08 | 2026-06-09 | 518880.SH | -3884.07 | 32 |
| 2024-08-01 | 2024-09-24 | 512480.SH | -3810.24 | 54 |
五、完整回测代码
文件名:
07_MACD金叉.py(共 124 行)
引擎:QuantStudio 本地回测;全部为公开 API,无平台专有调用。
# -*- coding: utf-8 -*-""" 07_MACD金叉策略 (QuantStudio 本地回测版) ======================================== 核心逻辑:MACD金叉(DIF上穿DEA)买入,死叉卖出。 经典趋势指标,多标的独立判断,最多持3只。 参数:EMA12/EMA26/DEA9。 """importnumpyasnp ETF_POOL=['510300.SS','159915.SZ','510500.SS','512880.SS','512800.SS','512690.SS','512170.SS','512480.SS','515880.SS','512660.SS','516160.SS','518880.SS',]FAST=12SLOW=26SIGNAL=9MAX_HOLDINGS=3EXPOSURE=0.98definitialize(context):set_benchmark('000300.SS')run_daily(context,trade,time='09:30')log.info('07_MACD金叉初始化: 池=%d, 参数=%d/%d/%d, 最多持%d只',len(ETF_POOL),FAST,SLOW,SIGNAL,MAX_HOLDINGS)def_ema(arr,period):"""计算EMA序列"""iflen(arr)<period:returnNoneema=np.zeros_like(arr,dtype=float)ema[period-1]=np.mean(arr[:period])k=2.0/(period+1)foriinrange(period,len(arr)):ema[i]=arr[i]*k+ema[i-1]*(1-k)returnemadef_get_macd_cross(code):"""返回 (是否金叉, 是否死叉, DIF, DEA)"""try:n=SLOW+SIGNAL+5h=get_history(n,'1d',field=['close'],security_list=code,fq='pre',include=False,is_dict=True)ifhisNoneorcodenotinh:returnFalse,False,None,Nonecloses=np.asarray(h[code]['close'],dtype=float)closes=closes[np.isfinite(closes)]iflen(closes)<SLOW+SIGNAL+2:returnFalse,False,None,Noneema_fast=_ema(closes,FAST)ema_slow=_ema(closes,SLOW)ifema_fastisNoneorema_slowisNone:returnFalse,False,None,Nonedif=ema_fast-ema_slow# 从有效位置开始计算DEAvalid_start=SLOW-1dif_valid=dif[valid_start:]dea=_ema(dif_valid,SIGNAL)ifdeaisNone:returnFalse,False,None,None# 对齐dif_aligned=dif_valid[-len(dea):]# 判断金叉/死叉(最近两根)iflen(dif_aligned)<2orlen(dea)<2:returnFalse,False,None,Nonegolden=(dif_aligned[-2]<=dea[-2])and(dif_aligned[-1]>dea[-1])death=(dif_aligned[-2]>=dea[-2])and(dif_aligned[-1]<dea[-1])returngolden,death,float(dif_aligned[-1]),float(dea[-1])exceptException:returnFalse,False,None,Nonedeftrade(context):held=list(context.portfolio.positions.keys())# 1. 死叉卖出forcodeinheld:_,death,dif,dea=_get_macd_cross(code)ifdeath:order_target_value(code,0)log.info('MACD死叉卖出 %s (DIF=%.4f, DEA=%.4f)',code,difor0,deaor0)# 2. 金叉买入held=list(context.portfolio.positions.keys())iflen(held)>=MAX_HOLDINGS:returncandidates=[]forcodeinETF_POOL:ifcodeinheld:continuegolden,_,dif,dea=_get_macd_cross(code)ifgolden:candidates.append((code,difor0))ifnotcandidates:return# 按DIF值排序(DIF越大趋势越强)candidates.sort(key=lambdax:x[1],reverse=True)slots=MAX_HOLDINGS-len(held)buy_list=candidates[:slots]total_value=context.portfolio.total_value per_value=total_value*EXPOSURE/MAX_HOLDINGSforcode,difinbuy_list:order_target_value(code,per_value)log.info('MACD金叉买入 %s (DIF=%.4f, 目标市值=%.0f)',code,dif,per_value)defhandle_data(context,data):pass六、风险提示
MACD是滞后指标:金叉通常出现在一段上涨的中后段、死叉出现在下跌的中后段,趋势策略的固有代价是"吃到鱼身、丢掉鱼头鱼尾"。本策略回合胜率只有44.1%,靠132%的盈亏比(平均盈利是平均亏损的1.32倍)维持正收益,这意味着它必须容忍连续多次止损。更值得注意的是持仓时间:平均80天,最长一笔超过1300天——资金可能被一只长期横盘的ETF占住好几年,期间既没有收益、也失去了其他机会。另外12只标的里有7只是行业主题ETF,同时持有3只时可能出现"同一波行情重复押注"的情况,组合的实际波动高于"分散持3只"给人的印象。
免责声明:本文所有数字来自本地历史回测,回测收益不代表未来表现,也不构成任何投资建议或个股/基金推荐。策略代码仅供研究学习,实盘执行还需额外考虑滑点、冲击成本、流动性、涨跌停与平台差异等因素。投资有风险,决策需谨慎。