【量化交易】避开四次熔断的标普500择时模型:趋势+波动率+信用利差

1.策略思路

1.1 核心逻辑

根据趋势,波动率期限结构,信贷条件构造一个市场状态滤波器,将标普500的市场状态划分为三种:

  • 风险偏好:全仓做多
  • 谨慎:半仓做多
  • 风险规避:全部平仓,离场观望

参考文章:

1.2 三个指标

趋势

标普500价格是否高于 200 天 SMA。二元分类:高于视为牛市,低于视为熊市。

波动率期限结构

VIX(30天标普500期权的隐含波动率)与 VIX3M(3个月标普500期权的隐含波动率)比较。通常 VIX 低于 VIX3M,属于正常的市场结构。若 VIX 高于 VIX3M,说明短期风险飙升,股市下跌风险显著增加。

信用状况

用 HYG/IEF 比率作为信用利差的代理变量:

  • HYG:高收益垃圾债 ETF
  • IEF:7-10 年国债 ETF

信用市场对风险变化最敏感,当投资者从高收益债券转向低风险国债时,说明市场风险偏好正在恶化,这是风险资产下跌的领先指标。

1.3 综合评分

将三个指标合并为一个综合评分,划分三种市场状态:

评分 市场状态 仓位
3 风险偏好 全仓做多
2 谨慎 半仓做多
0 或 1 风险规避 全部平仓

2. 准备数据

从 Yahoo Finance 获取日历史数据。数据质量不高,但用于验证策略原型完全足够。

美股历史数据获取:Yahoo Finance 转 Zorro 回测格式

3. 配置资产列表

回测工具:Zorro。

先准备资产列表AssetsIBdemo.csv。

策略加载多个资产的历史数据,但只交易 SPY,因此只需设置 SPY 的资产参数:

参数 含义 设置
spread 最优卖价与最优买价之差 0.02
rolllong / rollshort 隔夜利息,股票不适用 0
pip 最小价格增量 0.01
pipcost 1 手资产波动 1 个点的盈亏价值(计价货币) 0.01
margincost 持有 1 手的保证金,-100表示不用杠杆 -100
market 时区与开收盘时间,仅影响日内交易 EST:0930-1600
multiplier / lotamount 1 手对应的实际订单量 1(1 手 = 1 股)
commission 一笔完整交易(开仓+平仓)的佣金 0.01

关于 commission 的补充说明:IB 按股数收费,并有单笔最低/最高费用限制。固定层级费用为 0.005 美元/股,每单最低 1 美元,上限为交易额的 1%。例如交易 80 股,佣金 = 0.005 × 80 × 2 = 0.8 美元。为保持简单,回测忽略了上限和下限。

此外滑点将使用 Zorro 内置的滑点模型,假设延迟5秒成交,实际成交价会轻微偏离当时的市场价。

4. 回溯检验

c 复制代码
// Market Regime Model for sp500

#include <utils.c>

var assetPrice(string Name)
{
	asset(Name);
	var Price = priceC();
	asset(AssetPrev);
	return Price;
}

int marketDir(int TimePeriod)
{
	asset("SPY");
	return priceC() > SMA(seriesC(),TimePeriod);
}

int marketVolatility()
{
	return assetPrice("VIX") < assetPrice("VIX3M");
}

var marketCC(int TimePeriod)
{
	var Ratio = assetPrice("HYG")/fix0(assetPrice("IEF"));
	return zscore(Ratio,TimePeriod);
}

function run()
{
    // zorro 设置
	set(LOGFILE,PLOTNOW);
	// Verbose = 3;
	setf(PlotMode,PL_DIFF);
	BarPeriod = 1440;  // 日图
	StartDate = 2008;  // 回溯开始
	EndDate = 2026;    // 回溯结束
	LookBack = 200;    // 回溯开始前预留数据,预计算指标
	History = "?.t6";  // SPY.t6, VIX.t6
	Capital = 10000;   // 初始资本
	Leverage = 1;      // 杠杆水平
	Fill = 3;          // 1:模拟收盘价成交;3:次日开盘价成交

	// 加载资产列表,交易SPY
	assetList("AssetsIBdemo");
	asset("SPY");  // 因为 SPY 历史数据最全,所以先调用,当其它资产有缺失向前填充

	// 计算指标
	var CreditRatio = marketCC(100);
	int Score = marketDir(200) + marketVolatility() + (CreditRatio > -2);

	// 仓位调整:0=空仓(score<2)1=半仓(score=2)2=全仓(score=3)
	int Regime = clamp(Score - 1, 0, 2);
	vars Regimes = series(Regime, 2);
	int Exposure = (Capital + ProfitTotal) / priceC() * Regime / 2;

	if(is(LOOKBACK)) return;

	// 订单逻辑
    if(Regimes[0] != Regimes[1] || (Exposure > 0 && LotsPool == 0)) {
        log(strf("Regime: %d -> %d, Exposure = %d, LotsPool = %d",
            (int)Regimes[1], (int)Regimes[0], Exposure, LotsPool));
        if(Exposure > LotsPool)
            enterLong(Exposure - LotsPool);
        else if(Exposure < LotsPool)
            exitLong(0, 0, LotsPool - Exposure);
    }

    // 图表
	plot("Score", Score, NEW, BLUE);
	plot("#0", 0, NEW, WHITE);
	if(Score == 3)
		plot("Bullish", 1, BARS, GREEN);
	else if(Score == 2)
		plot("Caution", 1, BARS, ORANGE);
	else
		plot("Risk", 1, BARS, RED);
}

要点说明

评分计算的核心代码:

c 复制代码
var CreditRatio = marketCC(100);
int Score = marketDir(200) + marketVolatility() + (CreditRatio > -2);
  • marketDir:标普500是否高于 200 天均线。是返回 1,否返回 0。
  • marketVolatility:波动率期限结构。VIX < VIX3M 返回 1,否则返回 0。
  • marketCC:高收益债与国债的标准化价格比率。若大于 -2 返回 1,否则返回 0。比率低于 -2 说明信贷市场风险飙升,是风险资产暴跌的领先信号。
  • Score:三个指标的等权重求和,取值 0-3:
    • 0 或 1:至少两个指标发出危险信号 → 全部平仓。
    • 2:仅一个指标看空,市场处于上涨或转跌的中间阶段 → 半仓做多。
    • 3:全部指标看多,继续上涨概率最高 → 全仓做多。

5. 回测结果

测试区间为 2008 年 10 月 - 2026 年 10 月。部分 ETF 历史数据不足,因此只能从 2008 年 10 月开始。

主要指标如下:

  • 最大回撤:14.6%,最长回撤持续 85 周。
  • 交易次数:234 笔,胜率约 52%。(Zorro 按平仓统计交易:若先全仓做多,中途减仓 50%,最后全部平仓,则计为两笔交易。)
  • 收益:复合年化增长率(CAGR)10.7%;年均资本收益率(ROI,年均利润/初始资本)29.3%。
  • 风险调整收益:盈利因子 2.66,PRR 2.16,年化夏普比率 0.78。

总体来看,策略表现优秀。虽然回测中没有将买入持有作为对照组,但基于经验可以初步判断:这个趋势滤波器确实帮助交易者规避了大量回撤。

6. 评估趋势滤波器

6.1 2018 年四季度:噪音较多

背景:加息 + 贸易战 + 增长放缓,标普500跌近 20%,圣诞前夜一度接近熊市。

表现:滤波器分数在 1-3 之间反复横跳,产生了一些亏损。12 月基本保持空仓,避开了最深的下跌,并在 2019 年 1 月初发出半仓买入信号。

结论:整体表现一般,趋势转换初期噪音较多。

6.2 2020 年 2-3 月:成功避开闪崩

背景:疫情爆发,美股 4 次熔断(3/9、3/12、3/16、3/18),标普在 33 个交易日内下跌 34%。

表现:滤波器在 2 月 24 日发出减仓信号,25 日发出全平信号,成功避开这轮史上最快的下跌。

6.3 2022 年:表现最差的一年

背景:2 月俄乌战争爆发;3 月至 2023 年 7 月,美联储开启史上最快加息周期;标普500全年下跌,熊市贯穿全年。

表现:策略全年亏损 18%,是整个回测周期中表现最差的一年。整个 2022 年,滤波器基本处于"谨慎"状态,维持半仓做多。

分析信号可以发现两个问题:

  1. 第一次进场信号其实不差,基本能在中期下跌筑底后做多。
  2. 第二次做多(评分从 2 升到 3)买在了最高点,且平仓机制很糟糕------几乎等到趋势完全反转后,才亏损离场。

个人认为,如果优化平仓机制,并加入止损/跟踪止损/盈亏平衡等风控,应该能明显改善该年度表现,至少做到不亏损。

6.4 2025 年 3-4 月:及时规避关税冲击

背景:标普500下跌,主因可能是特朗普关税战引发的广泛担忧。

表现:滤波器过滤了 4 月的深跌,4 月最后一周半仓做多,5 月第一周全仓做多。

6.5 小结

从历史交易来看,这个趋势滤波器:

  • 能有效避开快速且持续的深跌。
  • 牛熊转换期间可能产生亏损,但幅度不大,基本是回吐上一轮牛市的部分盈利。
  • 面对锯齿式波动(下跌时间短,行情反复)会失效,例如2022年。

后续改进方向:

  • 用 lowpass 趋势跟随策略作为对照组,检验该滤波器能否跑赢简单的趋势指标。
  • 改善平仓机制,增加风控机制。
  • 优化参数,并进行 WFA 检验。
相关推荐
quantdash_cc8 小时前
ETF 行情数据清洗实战:字段语义拆解、标的池整理与五个校验清单
python·数据分析·pandas·量化交易·股票数据·quantdash
benchmark_cc1 天前
用 Python 拉 A 股全市场实时快照:Notebook 请求、结果校验与易错点
python·数据分析·pandas·量化交易·股票数据·quantdash
量化炼金 (CodeAlchemy)2 天前
【量化研究】美股历史数据获取:Yahoo Finance 转 Zorro 回测格式
python·量化研究·量化交易
2601_966949653 天前
Python 实战:如何统计五档盘口买卖盘总挂单量?附计算公式与代码
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
2601_966949653 天前
为什么不应该把 QuantDash API Key 直接写进公开代码仓库?从 Git 提交历史理解凭证泄露风险
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
quantdash_cc4 天前
如何检查滚动收益率计算中的窗口长度不足?——从数学定义到 Pandas 实现
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
2601_966949655 天前
如何根据研究的起止时间截取分钟级行情?Python 实战与 QuantDash 数据处理指南
开发语言·python·pandas·量化交易·1024程序员节·股票数据·quantdash
不脱发的程序猿5 天前
红利ETF量化策略
人工智能·python·ai·程序员·量化交易·etf·策略回测
benchmark_cc5 天前
如何为 QuantDash Python SDK 编写一个最小化的连接验证脚本?
python·数据分析·pandas·量化交易·股票数据·quantdash