14、因果推断方法:Granger因果检验、因果森林、双重差分法在联动分析中的应用

做量化这些年,我越来越觉得,相关性和因果性之间那道坎,才是真正区分「策略玩家」和「专业交易员」的分水岭。

你想想看,波动率曲面和宏观数据之间,经常出现「你涨我也涨」的情况。但这是真的因果关系吗?还是说,它们只是被同一个隐藏变量牵着鼻子走?

嗯,今天我们就来聊聊怎么用因果推断的方法,把这种「假关系」揪出来。

14.1 Granger因果检验:时间上的「谁先谁后」

Granger因果检验,说白了就是看一个时间序列能不能「预测」另一个。注意,我这里说的是「预测」,不是「导致」。它本质上是个统计上的先导-滞后关系。

我个人习惯在分析波动率曲面和宏观数据时,先用Granger检验做个「摸底」。比如,我想知道「美国非农就业数据」是不是「VIX指数」的Granger原因。

代码实现其实不复杂,我直接贴一段我常用的R代码:

library(lmtest)
library(vars)

# 假设我们有两个时间序列:macro_data 和 vol_surface
# 先确定最优滞后阶数
lag_selection <- VARselect(cbind(macro_data, vol_surface), lag.max = 10, type = "const")
best_lag <- lag_selection$selection["AIC(n)"]

# 进行Granger因果检验
granger_test <- grangertest(vol_surface ~ macro_data, order = best_lag)
print(granger_test)

避坑指南:我曾经在2018年做过一次测试,发现「中国PMI」和「人民币汇率波动率」之间Granger因果关系非常显著。但后来加入「美元指数」作为控制变量后,这个关系就消失了。所以,Granger检验对遗漏变量非常敏感,千万别只看p值就下结论。

为什么我强调「摸底」这个词?因为Granger检验只能告诉你「A对B有预测能力」,但无法解释背后的机制。它就像个侦察兵,告诉你「那边有动静」,但具体是什么,还得靠后面的方法。

14.2 因果森林:从「平均效应」到「异质性效应」

Granger检验只能给出一个「平均」的因果效应。但现实中,宏观数据对波动率曲面的影响,在不同市场状态下是完全不同的。

举个例子:美联储加息这个事件,在「市场恐慌期」和「市场平稳期」对波动率曲面的影响,能一样吗?显然不能。

这时候,因果森林就派上用场了。它本质上是把随机森林的思想用到了因果推断上,能帮我们找到「哪些样本的因果效应特别强」。

我记得在2020年3月,我用因果森林分析「VIX期货期限结构」和「美国失业金申请人数」的关系。结果发现,在波动率曲面处于「contango」状态时,失业金数据对短期端波动率的影响,是「backwardation」状态下的3倍多。

Python里有个叫econml的库,用起来很方便:

from econml.grf import CausalForest

# X: 特征矩阵(包含市场状态变量)
# T: 处理变量(宏观数据冲击)
# Y: 结果变量(波动率曲面变化)

cf = CausalForest(n_estimators=100, min_samples_leaf=10)
cf.fit(Y, T, X=X)

# 查看不同市场状态下的因果效应
treatment_effects = cf.effect(X_test)

核心要点:因果森林的价值不在于告诉你「有没有因果」,而在于告诉你「对谁有因果」。这在构建择时策略时特别有用——你可以只在因果效应强的状态下开仓。

14.3 双重差分法:事件驱动的「准实验」

双重差分法(DID)是我个人最喜欢的方法。它特别适合分析「某个宏观事件」对「波动率曲面」的冲击。

基本逻辑很简单:比较「受事件影响的组」和「未受事件影响的组」,在事件发生前后的差异。这个差异的差异,就是因果效应。

举个例子:假设2023年7月日本央行调整了YCC政策。我想知道这个事件对「亚洲货币波动率曲面」的影响。

处理组:亚洲货币(日元、韩元、泰铢等)
对照组:非亚洲货币(欧元、英镑等)
事件前:2023年6月
事件后:2023年8月

DID的回归模型长这样:

# 伪代码示意
Y = β0 + β1 * Post + β2 * Treat + β3 * (Post * Treat) + ε

# β3 就是我们关心的因果效应

注意:DID有一个关键假设——「平行趋势假设」。也就是说,如果没有这个事件,处理组和对照组的波动率曲面应该沿着相同的趋势走。我曾在做「英国脱欧对英镑波动率影响」的分析时,就因为对照组选得不好,导致结果完全失真。后来我改用「瑞士法郎」作为对照组,才通过了平行趋势检验。

实际操作中,我一般会画个图,看看事件前两组的变化趋势是否平行:

import matplotlib.pyplot as plt
import pandas as pd

# 假设 df 包含处理组和对照组的日度波动率数据
# event_date 是事件发生日

plt.figure(figsize=(10, 6))
plt.plot(df.index, df['treatment'], label='处理组')
plt.plot(df.index, df['control'], label='对照组')
plt.axvline(x=event_date, color='red', linestyle='--', label='事件日')
plt.legend()
plt.title('平行趋势检验')
plt.show()

14.4 三种方法的联动应用框架

在实际项目中,我不会只用一种方法。我有个「三步走」的习惯:

  1. 先用Granger检验:快速筛选出有「预测关系」的宏观变量,缩小范围。
  2. 再用因果森林:看看这些关系在不同市场状态下是不是「一视同仁」,找到异质性。
  3. 最后用DID:针对某个具体事件,做「准实验」验证,给出因果效应的量化估计。

这个流程,我用了好几年,效果还不错。你想想看,如果只用Granger检验,你可能会被「伪因果」误导;如果只用DID,你可能会错过那些「非事件驱动」的因果效应。

下面这张图,是我自己总结的联动分析框架:

波动率曲面与宏观数据联动分析框架 Step 1: Granger检验 筛选预测关系 Step 2: 因果森林 发现异质性效应 Step 3: DID 事件因果验证 输出:因果效应量化估计 + 异质性分布 用于构建择时策略、风险对冲方案 注:三种方法可独立使用,也可串联使用,取决于具体分析目标

实战建议:别想着一步到位。我刚开始做因果分析时,总想用一个「万能方法」解决所有问题。后来发现,每种方法都有自己的「舒适区」。Granger检验适合「探索」,因果森林适合「细分」,DID适合「验证」。把它们组合起来用,才是正道。

最后说一句:因果推断不是「银弹」。它不能告诉你「明天波动率曲面会怎么走」,但它能告诉你「如果宏观数据出现某种变化,波动率曲面大概会怎么反应」。这个「如果...那么...」的逻辑,才是我们做量化交易最需要的东西。


公众号:蓝海资料掘金营,微信deep3321