当前位置:首页>python>闲置资金别躺平:用 Python 回测黄金 + 债券「双引擎」idle 策略

闲置资金别躺平:用 Python 回测黄金 + 债券「双引擎」idle 策略

  • 2026-10-11 05:42:59
闲置资金别躺平:用 Python 回测黄金 + 债券「双引擎」idle 策略

用 Python 揭秘均值回归策略:你的收益从何而来?

2026年重磅升级已全面落地!欢迎加入专注财经数据与量化投研的【数据科学实战】知识星球!您将获取持续更新的《财经数据宝典》与《量化投研宝典》,双典协同提供系统化指引;星球内含 500 篇以上独有高质量文章,深度覆盖策略开发、因子分析、风险管理等核心领域,内容基本每日更新;同步推出的「量化因子专题教程」系列(含完整可运行代码与实战案例),系统详解因子构建、回测与优化全流程,并实现日更迭代。我们持续扩充独家内容资源,全方位赋能您的投研效率与专业成长。无论您是量化新手还是资深研究者,这里都是助您少走弯路、事半功倍的理想伙伴,携手共探数据驱动的投资未来!

引言

做量化策略时,很多人只盯着买入和卖出信号,却忽略了一个细节:当策略「空仓」的时候,那笔现金在干什么?

对于择时类策略(比如均值回归、趋势跟随),实际持有标的的天数往往只占一半左右,剩下大量时间资金都在「躺平」,收益率为 0。如果能让这部分闲置资金也「打工」,整体表现会不会更好?

本文用 26 年的 SPY 历史数据做了一次回测:把空仓时的闲置资金按趋势信号分配到「黄金 (GLD) + 中期国债 (IEF) + 短债 (SHV)」上,看看结果如何。全程基于 Python,涉及 pandas、yfinance、vectorbt 等常用库,非常适合正在学习 Python 量化的同学参考。

一、核心思路:让闲置资金「有条件地」赚钱

先说清楚一个前提:这套逻辑只作用于策略空仓的那些天。当策略持有 SPY 时,一切照旧,买卖点完全不变;只有在 SPY 不持仓时,才把这部分现金拿去做配置。

早期的思路是把闲置资金 75% 投黄金、25% 投短债,并用黄金自身的「黄金交叉」(50 日均线上穿 200 日均线) 作为开关。这次做了一个更分散的版本:

  • • 固定 25% 放短债 (SHV) 作为压舱石;
  • • 剩下 75% 在黄金 (GLD) 和中期国债 (IEF) 之间分配;
  • • 每个资产各自用自己的 50/200 金叉判断是否处于上升趋势。

二、四档配置逻辑

根据 GLD 和 IEF 各自是否金叉,一共有 4 种情况:

GLD 金叉
IEF 金叉
配置方案
✅
✅
37.5% GLD + 37.5% IEF + 25% SHV
✅
❌
75% GLD + 25% SHV
❌
✅
75% IEF + 25% SHV
❌
❌
100% SHV(最差情况)

思路很直观:两个都在涨,就平分那 75%;只有一个在涨,它就拿满 75%;两个都不涨,就全躲进短债里避险。

三、Python 实现要点(含中文注释)

1. 策略信号:RSI-2 均值回归

import vectorbt as vbt

# 计算 2 日 RSI(超短周期,对回调非常敏感)

rsi = vbt.RSI.run(df["Close"], window=2).rsi
sma_exit = vbt.MA.run(df["Close"], window=5).ma  # 5 日短均线,用于离场

# 超卖(RSI < 10)时买入

mr_entries = rsi < 10
# 超买(RSI > 70)或价格重新站上短均线时卖出

mr_exits = (rsi > 70) | (df["Close"] > sma_exit)

2. 策略信号:SMA 50/200 趋势跟随

sma_fast = vbt.MA.run(df["Close"], window=50).ma   # 快线
sma_slow = vbt.MA.run(df["Close"], window=200).ma  # 慢线

tf_entries = sma_fast.vbt.crossed_above(sma_slow)  # 金叉买入
tf_exits = sma_fast.vbt.crossed_below(sma_slow)    # 死叉卖出

3. 四档闲置资金收益的核心代码

import pandas as pd

# 分别用各自的 50/200 金叉判断是否处于上升趋势

both     = gld_golden & ief_golden        # 两者都金叉
gld_only = gld_golden & ~ief_golden       # 只有黄金金叉
ief_only = ~gld_golden & ief_golden       # 只有债券金叉
neither  = ~gld_golden & ~ief_golden      # 都没金叉

# 按四种情况分别计算闲置资金的每日收益

idle_ret = pd.Series(0.0, index=common_index)
idle_ret[both]     = 0.375 * gld_ret[both] + 0.375 * ief_ret[both] + 0.25 * shv_ret[both]
idle_ret[gld_only] = 0.75 * gld_ret[gld_only] + 0.25 * shv_ret[gld_only]
idle_ret[ief_only] = 0.75 * ief_ret[ief_only] + 0.25 * shv_ret[ief_only]
idle_ret[neither]  = shv_ret[neither]     # 最差情况:全部躲进短债

4. 两个容易踩坑的工程细节

坑一:脏数据会「毁掉」整条净值曲线。
行情接口偶尔会返回一根坏 K 线(收盘价为 0、负值或 NaN)。一个 -100% 的假跌,会让后续净值直接乘以 0 且再也回不来,哪怕真实市场什么都没发生。

# 把非正数 / 缺失的收盘价标记出来,用前一个有效价格前向填充
bad = px.isna() | (px <= 0)
px = px.mask(bad).ffill()  # ffill:forward fill,前向填充

同理,对单日涨跌超过 20% 的「异常波动」也做了裁剪——GLD、SHV、IEF 这类品种基本不可能单日暴动 20% 以上,遇到就当作数据毛刺清零处理。

坑二:不要盲目相信封装好的持仓掩码。
回测中发现,某些框架自带的「持仓掩码」虽然统计出的总仓位比例是对的,但逐日对齐时会把「哪几天在场内」标错,从而悄悄毁掉任何按天结合收益率的计算。更稳妥的做法是直接从成交记录表 (trades) 里,按每笔交易的入场、出场时间戳还原逐日持仓状态:

in_market = pd.Series(False, index=strat_ret_index)
for
 _, row in trades.iterrows():
    entry = row["Entry Timestamp"]
    # 未平仓的交易,出场时间用序列的最后一天兜底

    exit_ts = row["Exit Timestamp"] if row["Status"] == "Closed" else strat_ret_index[-1]
    in_market.loc[entry:exit_ts] = True  # 这段区间标记为「在场内」

这是一个很好的提醒:回测框架给的便捷方法不一定和你的收益序列逐日对齐,关键结果一定要用「数据源真相」交叉验证。

四、回测结果

先看 26 年里四种情况各自出现的天数占比:

  • • 两者都金叉:44.8%
  • • 仅债券金叉:21.4%
  • • 都不金叉(全短债):17.9%
  • • 仅黄金金叉:15.9%

「最差情况全短债」大约只占 17.9% 的时间,而黄金和债券单独金叉的天数分布也比较均衡,没有一头倒向某个资产。

均值回归 (RSI-2):提升显著

这类策略空仓时间高达 59.2%,闲置资金规模大,redeploy 的空间也最大:

指标
闲置资金 = 0%
加入 GLD/IEF/SHV
CAGR
5.70%
11.10%
最大回撤
33.25%
29.48%
夏普比率
0.573
0.796

年化收益几乎翻倍,回撤还略有下降,夏普明显抬升。空仓那些天里,这套闲置资金组合累计贡献了 275.41% 的收益。「收益更高 + 回撤更低」同时出现,对一个完全不改变原策略买卖点的叠加层来说,是相当漂亮的结果。

趋势跟随 (SMA 50/200):改善温和

这类策略只有 31.8% 的时间空仓,可动用的闲置资金少,效果自然打折:

指标
闲置资金 = 0%
加入 GLD/IEF/SHV
CAGR
6.15%
8.09%
最大回撤
34.26%
32.00%
夏普比率
0.669
0.677

年化从 6.15% 提升到 8.09%,回撤基本持平,夏普小幅上升。方向是对的,只是「原材料」不够多。

五、为什么有效,以及必须诚实面对的地方

核心逻辑是站得住脚的:本来收益为 0 的闲置资金,被投进了能产生真实收益的资产;同时用趋势信号做闸门,避免在黄金或债券的下跌趋势里硬扛。把 75% 拆给两个资产、而不是押注单一标的,是更保守的构造——44.8% 的时间两者同涨,此时也只各配 37.5%,用「放弃一部分单一赢家的上行空间」换「更低的集中度风险」。

但要诚实:

  1. 1. 本次回测并没有证明「双资产」一定比「单资产」更强,因为这个窗口里只测了双资产版本,缺少同口径的单资产对照。
  2. 2. 这只是一段特定的约 26 年历史,没有覆盖「黄金和债券连续数年一起阴跌」的极端场景,而那才是这类双资产趋势 idle 策略真正的压力测试。
  3. 3. 想进一步验证,合理的下一步是把同样的叠加层拆到不同子区间(比如 2004—2012、2013—2020)分别跑,看 CAGR 和夏普的改善是否稳健,而不是只依赖一次全样本结果。

总结

  • • 闲置资金不必躺平:择时策略空仓期往往占比很高,把这部分现金按趋势信号配置到黄金、债券、短债上,能实实在在地提升整体表现。
  • • 均值回归受益最大(CAGR 5.70% → 11.10%,夏普 0.573 → 0.796),趋势跟随受益温和,差别主要来自「空仓时间多少」。
  • • 分散优于孤注一掷:四档逻辑用固定短债打底、双资产分金叉配置,降低了集中度风险。
  • • 工程细节决定成败:脏数据清洗、单日异常波动裁剪、逐日持仓状态从成交记录还原——这些「不起眼」的处理,往往才是一个可信回测的关键。
  • • 回测≠承诺:单一历史窗口的漂亮结果,务必配合子区间验证和风险认知,切勿直接当成实盘依据。

对正在学 Python 量化的你,这篇最值得抄走的不只是那几行配置代码,更是「对框架保持怀疑、用数据源真相交叉验证」的工程习惯。

参考文章

加入专注于财经数据与量化投研的知识星球【数据科学实战】,获取本文完整研究解析、代码实现细节。

财经数据与量化投研知识社区

2026年全面升级已落地!【数据科学实战】知识星球核心权益如下:

  1. 1. 双典系统赋能:获赠《财经数据宝典》与《量化投研宝典》完整文档,凝练多年实战经验,构建系统化知识框架;
  2. 2. 量化因子日更教程(2026重磅新增):每日更新「量化因子专题教程」,配套完整可运行代码与实战案例,深度拆解因子构建、回测与优化全流程;
  3. 3. 量化文章专题教程库:500+篇星球独有高质量教程式文章,系统覆盖策略开发、因子研究、风险管理等核心领域,内容基本每日更新,并配套精选学习资料与实战参考;
  4. 4. 量化投研实战课程:赠送《AKQuant-入门及实战》《PyBroker-入门及实战》视频课程,手把手教学,快速掌握量化策略开发技能;
  5. 5. 财经数据支持:定期更新国内外财经数据,为策略研发提供精准、可靠的数据基础;
  6. 6. 顶尖学者与行业专家分享:年度邀请学术界博士与业界资深专家开展前沿论文精讲与实战案例分享,不少于4场,直击研究前沿与产业实践;
    专家直连答疑:与核心开发者及领域专家实时互动,高效解决投研实战难题;
  7. 7. 专业社群与专属福利:加入高质量交流社群,获取课程折扣及更多独家资源。

星球已沉淀丰富内容生态——涵盖量化文章专题教程库、因子日更系列、高频数据集、PyBroker实战课程、专家深度分享与实时答疑服务。无论您是初探量化的学习者,还是深耕领域的从业者,这里都是助您少走弯路、高效成长的理想平台。诚邀加入,共探数据驱动的投资未来!

好文推荐

1. 用 Python 打造股票预测系统:Transformer 模型教程(一)

2. 用 Python 打造股票预测系统:Transformer 模型教程(二)

3. 用 Python 打造股票预测系统:Transformer 模型教程(三)

4. 用 Python 打造股票预测系统:Transformer 模型教程(完结)

5. 揭秘隐马尔可夫模型:因子投资的制胜武器

6. YOLO 也能预测股市涨跌?计算机视觉在股票市场预测中的应用

7. 金融 AI 助手:FinGPT 让你轻松掌握市场分析

8. 量化交易秘籍:为什么专业交易员都在用对数收益率?

9. Python 量化投资利器:Ridge、Lasso 和 Elastic Net 回归详解

10. 掌握金融波动率模型:完整 Python 实现指南

好书推荐

最新文章

随机文章