← 返回文章列表
August 7, 2026
5 分钟阅读

Toda-Yamamoto vs Differenced Granger: Does the BTC Lead-Lag Survive?

Toda-Yamamoto vs Differenced Granger: Does the BTC Lead-Lag Survive?
#causal-inference
#Granger-causality
#lead-lag
#crypto
#VAR

几乎所有已发布的加密货币格兰杰因果关系结果都是根据对数返回计算的。这种选择不是自由的。差分使序列平稳,这是标准 F 检验所要求的,但它也放弃了水平关系 - 如果两个硬币是协整的,则差分 VAR 会被错误指定,并且测试回答的问题与您提出的问题略有不同。

Toda 和 Yamamoto (1995) 提供了一条出路:将 VAR 拟合到具有额外滞后的水平上,仅测试原始水平,并获得有效的 χ2\chi^2,无论单位根或协整如何。它在计量经济学中众所周知,但几乎从未应用于加密货币的超前滞后。

因此,本文做了一件事:**在同一窗口上对同一对进行这两项测试,并报告它们是否不一致。**然后应用诚实的后续措施 - 对结果矩阵进行相关系列多重测试校正,并滚动 p 值以查看“显着”滞后是否足够稳定以进行交易或只是在阈值上闪烁。

下面的理论仅是使比较清晰所需的内容。该博客已经涵盖了单位根、协整、数据加载、大小调整和成本;这些是链接,而不是部分。

格兰杰因果关系实际上主张什么

市场事件中的定向超前-滞后路径

格兰杰因果关系是预测优先级,而不是机制:XX 如果过去的 XX 减少了 YY 的预测误差方差超出了过去的 YY 已经解释的范围,则 XX 格兰杰因果关系 YY

XX 格兰杰原因 YY 如果 σ2(YtYt1,,Ytp)>σ2(YtYt1,,Ytp,Xt1,,Xtp)\sigma^2(Y_t \mid Y_{t-1}, \ldots, Y_{t-p}) > \sigma^2(Y_t \mid Y_{t-1}, \ldots, Y_{t-p}, X_{t-1}, \ldots, X_{t-p})

由共同隐藏因素驱动的两个序列可以显示格兰杰因果关系,但它们之间没有直接联系。在加密货币中,这一警告并不是学术性的——BTC 是整个山寨币复合体中的一个主导因素 ,因此几乎任何山寨币与山寨币之间的“因果关系”都是对同一 BTC 冲击的不同响应速度的候选产物。

VAR 框架

该测试位于向量自回归内。对于具有 pp 滞后的两个变量:

Yt=α0+i=1pαiYti+i=1pβiXti+ϵ1tY_t = \alpha_0 + \sum_{i=1}^{p} \alpha_i Y_{t-i} + \sum_{i=1}^{p} \beta_i X_{t-i} + \epsilon_{1t} Xt=γ0+i=1pγiXti+i=1pδiYti+ϵ2tX_t = \gamma_0 + \sum_{i=1}^{p} \gamma_i X_{t-i} + \sum_{i=1}^{p} \delta_i Y_{t-i} + \epsilon_{2t}

以矩阵形式,具有 kk 变量的 VAR(p):

yt=c+A1yt1++Apytp+ut\mathbf{y}_t = \mathbf{c} + \mathbf{A}_1 \mathbf{y}_{t-1} + \cdots + \mathbf{A}_p \mathbf{y}_{t-p} + \mathbf{u}_t

测试 XX 格兰杰原因 YY 是否正在测试第一个方程中的联合限制 H0:β1==βp=0H_0: \beta_1 = \cdots = \beta_p = 0。标准路线是对受限制与无限制残差平方和进行 F 检验,

F=(RSSrRSSu)/pRSSu/(T2p1)F = \frac{(RSS_r - RSS_u) / p}{RSS_u / (T - 2p - 1)}

具有渐近等价的 Wald 形式 W=T(RSSrRSSu)/RSSudχ2(p)W = T \cdot (RSS_r - RSS_u)/RSS_u \xrightarrow{d} \chi^2(p)。接下来的一切都是关于限制适用于哪些系数以及 VAR 拟合在哪些数据上的问题。

滞后选择

pp 比大多数文章所承认的更重要:太少的滞后会错过动态,太多的滞后会烧毁自由度并破坏力量。

AIC(p)=lnΣ^u(p)+2pk2T,BIC(p)=lnΣ^u(p)+pk2lnTT\text{AIC}(p) = \ln|\hat{\Sigma}_u(p)| + \frac{2pk^2}{T}, \qquad \text{BIC}(p) = \ln|\hat{\Sigma}_u(p)| + \frac{pk^2 \ln T}{T} HQIC(p)=lnΣ^u(p)+2pk2ln(lnT)T\text{HQIC}(p) = \ln|\hat{\Sigma}_u(p)| + \frac{2pk^2 \ln(\ln T)}{T}

合理的搜索范围:秒数据1-60,分钟数据1-30,每小时1-48。 BIC 在这里是正确的默认值——它是更简约的标准,而流动加密货币对中的超前滞后是一种短记忆现象。 下面的每个结果都报告了每对 BIC 选择的 pp,而不是修复整个宇宙中的一个滞后,因为固定滞后会默默地将滞后选择选择转换为显着性声明。

为什么差分检验不是正确的默认选择

差异可能会破坏超前-滞后关系

加密货币价格系列为 I(1)。通常的修复方法——采用对数回报——以协整水平为代价购买平稳性,如果货币对共享长期均衡,则差异 VAR 被错误指定。这句话背后的单位根和协整机制(ADF、Engle-Granger 及其 Monte-Carlo 临界值、Johansen 在 VAR 系统上)已包含在统计套利和配对交易;假设在这里。关键在于,通常的补救措施——差异,然后测试——是一个具有后果的建模决策,而户田山本是避免这样做的方法。

正确实施 Toda-Yamamoto

拟合具有 p+dmaxp + d_{max} 滞后的 VAR,其中 pp 是最优滞后阶数,dmaxd_{max} 是级数的最大积分阶数,然后测试限制仅对第一个 pp 滞后。额外的 dmaxd_{max} 滞后吸收了非平稳性;第一个 pp 系数的 Wald 统计量遵循标准 χ2(p)\chi^2(p),无论序列是 I(0)、I(1) 还是协整。

  1. 确定 dmaxd_{max} — 每个系列上的 ADF 和 KPSS。对于加密货币价格,dmax=1d_{max} = 1 几乎总是如此。
  2. 选择 pp — 在级别上拟合 VAR,按 BIC 选择。
  3. 估计水平上的增强VAR(p+dmaxp + d_{max}),无差异。
  4. Wald 测试第一个 pp 仅滞后,忽略 dmaxd_{max} 附加功能。结果是χ2(p)\chi^2(p)

回报:没有协整预测试,没有差异,并且测试大小正确 - 无论积分属性结果如何,零值下的拒绝率都保持在标称值附近。代价是步骤 4 并不是 test_causality 默认执行的操作,而这正是大多数实现悄悄出错的地方。

## 执行

滞后矩阵实现流程

假设您已经在 DataFrame 中对齐了分钟柱 — ccxt 获取和索引样板位于 使用 HMM 进行制度检测,并且您将用于步骤 1 的 ADF 包装器位于 统计套利和配对交易 ] 中。

在运行任何此操作之前有一个版本说明:grangercausalitytests(..., verbose=False) 已弃用,然后在 statsmodels 0.15 中删除。删除参数(默认情况下该函数不再打印)或固定 statsmodels<0.15。下面的代码采用现代签名。

###户田山本,正确完成

该限制必须手动构建。 VARResults.test_causality 测试拟合模型中导致变量的所有滞后 - 在增强 VAR(p+1p+1) 上,其中包括限制中的 dmaxd_{max} 滞后,这正是 Toda-Yamamoto 所说不要做的事情。修复方法是针对全系数协方差使用显式 RR 矩阵:

import numpy as np
from scipy.stats import chi2
from statsmodels.tsa.api import VAR


def toda_yamamoto_test(data, target, predictor, max_lag=15, d_max=1,
                       significance=0.05):
    """
    Toda-Yamamoto Granger causality on levels (no differencing).

    Fits VAR(p + d_max) and applies a Wald test to the predictor's
    coefficients at lags 1..p ONLY, leaving the d_max augmenting lags
    unrestricted. Statistic is chi2(p).
    """
    pair = data[[target, predictor]].dropna()
    n_vars = pair.shape[1]
    target_idx = list(pair.columns).index(target)
    pred_idx = list(pair.columns).index(predictor)

    model = VAR(pair)
    p = model.select_order(maxlags=max_lag).bic or 1
    res = model.fit(p + d_max)

    beta = res.params.values.ravel(order="F")
    cov = res.cov_params()
    cov = cov.values if hasattr(cov, "values") else np.asarray(cov)

    n_per_eq = res.params.shape[0]
    idx = [target_idx * n_per_eq + 1 + lag * n_vars + pred_idx
           for lag in range(p)]                      # first p lags only

    R = np.zeros((p, beta.size))
    R[np.arange(p), idx] = 1.0

    Rb = R @ beta
    V = R @ cov @ R.T
    wald = float(Rb @ np.linalg.solve(V, Rb))        # no pinv: V must be PD
    p_value = float(chi2.sf(wald, df=p))

    return {
        "target": target, "predictor": predictor,
        "p": p, "augmented_lag": p + d_max, "d_max": d_max,
        "wald_stat": wald, "p_value": p_value,
        "significant": p_value < significance,
    }

有两个细节很容易出错,一旦出错就会导致测试无效。首先,索引算术必须匹配 statsmodels 展平 params 的方式 — 在信任任何 p 值之前,在拟合模型上验证 beta[target_idx * n_per_eq + 1] 等于 res.params.iloc[1, target_idx]。其次,使用 np.linalg.solve,而不是 pinv:如果 VV 是单数,则限制是退化的,并且运行应该大声失败,而不是返回看起来合理的数字。这里的伪逆是破碎的 Wald 测试如何在代码审查中幸存下来。

标准差分格兰杰,用于比较

比较的基线 — 对数回报、相同的配对、相同的 BIC 滞后:

from statsmodels.tsa.stattools import grangercausalitytests


def differenced_granger(data, target, predictor, p):
    """Standard Granger test on log-returns at a fixed lag p."""
    pair = data[[target, predictor]].dropna()   # returns, not levels
    out = grangercausalitytests(pair, maxlag=[p])   # statsmodels >= 0.15
    f_stat, p_value = out[p][0]["ssr_ftest"][:2]
    return {"target": target, "predictor": predictor, "lag": p,
            "f_stat": f_stat, "p_value": p_value}

请注意 maxlag=[p] 而不是 maxlag=p:传递一个 int 会运行从 1 到 pp 的每个滞后,并诱使您报告最佳的一个,这是在您已经运行的多个测试之上进行的未记录的多个测试。

比较

对于每一对,在相同的 BIC 选择的 pp 上运行收益差异测试和 Toda-Yamamoto 水平测试,并将两者不一致的地方制成表格。分歧是一个有趣的单元:一对在差异上显着但在水平上不显着的对是差分协整关系的候选工件;相反,表明级别关系携带返回测试无法看到的信息。

因果矩阵上的多重比较

过滤大的因果关系矩阵

完整的 n×nn \times n 矩阵是危险的地方。 20 个资产、10 个滞后的扫描需要 3,800 个假设检验,而 Bonferroni 对于这种相关的系列来说是错误的修正——测试共享数据、共享 BTC 因子,而且远非独立,因此 Bonferroni 同时在总体上过于保守,并且误导了哪些细胞存活。使用收缩的 Sharpe 文章 ** 中的**有效-N 机制,该机制正是针对这种情况而构建的:对相关测试系列进行聚类,对独立试验而不是原始试验进行计数,并针对该情况设置阈值。

def granger_matrix(data, max_lag=15, d_max=1):
    """Toda-Yamamoto p-value matrix. Entry (i, j): does col_j cause col_i?"""
    cols = list(data.columns)
    out = pd.DataFrame(np.nan, index=cols, columns=cols, dtype=float)
    for target in cols:
        for predictor in cols:
            if target == predictor:
                continue
            r = toda_yamamoto_test(data, target, predictor,
                                   max_lag=max_lag, d_max=d_max)
            out.loc[target, predictor] = r["p_value"]
    return out

重要的数字不是有多少细胞低于 0.05,而是有多少细胞在有效 N 校正阈值下幸存下来。

从结构上而不是逐个单元地读取幸存矩阵:一项资产引起许多其他资产的行确认了信息层次结构;一篇无缘无故的专栏暗示着特殊的、特定于代币的动态,而不是一个发现。

诚实的测试:滚动稳定性

滚动窗口信号稳定

单个样本内 p 值对于交易来说几乎毫无价值。相关问题是重要性是否持续。加密货币中的跨资产关系是依赖于政权的——冷静和恐慌之间的相关结构差异很大,而且政权本身是可估计的(HMM政权检测)——因此在一个窗口上估计的超前滞后是关于该窗口的一种陈述。

def rolling_granger(data, target, predictor, window=500, lag=5, step=50):
    """Rolling-window p-value: when is the lead-lag active vs dormant?"""
    rows = []
    for start in range(0, len(data) - window, step):
        chunk = data.iloc[start:start + window][[target, predictor]].dropna()
        if len(chunk) < window * 0.8:
            continue
        try:
            out = grangercausalitytests(chunk, maxlag=[lag])
            f_stat, p_value = out[lag][0]["ssr_ftest"][:2]
        except Exception:
            f_stat, p_value = np.nan, np.nan
        rows.append({"timestamp": data.index[start + window - 1],
                     "f_stat": f_stat, "p_value": p_value})
    return pd.DataFrame(rows).set_index("timestamp")

报告本系列中的两件事:低于 0.05 的窗口比例,以及阈值交叉的数量。即使合并的 p 值相同,在 80% 具有 3 个交叉的窗口中显着的关系与在 55% 的具有 40 个交叉的窗口中显着的关系是不同的对象。第二个是不可交易的——您无法根据信号确定头寸大小,该信号的存在每隔几百条柱就会翻转一次,并且重新估计滞后保证您始终在之前的状态下进行交易。

Granger 特有的数据陷阱

不规则的加密货币蜱虫扰乱因果信号

其他地方涵盖了通用加密数据卫生——回测实时奇偶性中的差距和缺失蜡烛,前瞻偏差分类法中的时间戳规则]和证明跨时间范围没有前瞻。然而,一种故障模式是格兰杰特有的,并且严重到足以命名:

向前填充产生结果。 向前填充的蜡烛重复前一个收盘价,这将纯粹的自相关注入到序列中 - 并且 YY 中与 XX 机械对齐的滞后 1 自相关对于 F 测试来说与单滞后因果关系无法区分。这同样适用于不同场地:分钟柱上两次交易之间的 **1 秒时钟偏移可以直接创建或破坏 lag-1 显着性,因为它会改变移动落在柱边界的哪一侧。在运行任何此操作之前,请验证间隙是否被删除而不是被填充,并且两个系列都来自同一时钟。

文献中报告的领先-滞后关系

超前滞后研究的证据星座

这些是引文,而不是本文的测量结果。他们来这里是为了说出已发表的记录所声称的内容,因此上面的比较有一些同意或不同意的地方。

  • BTC 到山寨币。 亚太金融市场 (Springer) 中的一项 2026 年研究报告了从比特币到山寨币的高频价格传输,小盘币表现出明显的延迟响应和与较慢的反应相关的流动性较低。这一工作中经常引用的滞后幅度——BTC 到 ETH 大约 1-3 分钟,中小型股的时间更长,随着市值下跌而越来越单向——是引用的发现,而不是在此处重新得出。他们所依赖的市值分层与多交易品种验证中使用的阶梯相同。
  • CEX 领先 DEX。 对加密货币微观结构的研究(MDPI)报告称,中心化场所主导价格发现,信息流运行 CEX 到 DEX,并且没有显着的反向因果关系——与亚毫秒匹配引擎与区块时间结算一致。
  • ETH 作为一种独立的货币。 VAR-SVAR 工作(MDPI)发现了以太坊作为源、比特币作为溢出接收者的机制,特别是在 DeFi 和 NFT 驱动的阶段。

简述跨交易所情况

同币两个场所的滞后是一个真实的设置,但它的经济学——费用阈值、延迟阶梯、滞后存在的原因——已经在统计套利和配对交易泡菜溢价]中得到解决。 Granger 唯一添加的是稳定性问题:Binance 到 Coinbase 的因果关系是否“持续”显着,还是像其他一切一样忽隐忽现?对场地对进行滚动测试;答案是 p 值时间序列,而不是肯定的。

将保留下来的滞后关系转化为持仓

信号阈值成为受控位置

如果一对清除了校正阈值滚动测试,则信号本身是微不足道的:累积预测器在滞后窗口上返回,阈值化。

def lead_lag_signal(btc_returns, alt_returns, lag=5, threshold=0.001):
    """+1 / -1 / 0 on ALT from BTC's cumulative return over `lag` bars."""
    btc_cum = btc_returns.rolling(lag).sum()
    signal = pd.Series(0, index=alt_returns.index)
    signal[btc_cum > threshold] = 1
    signal[btc_cum < -threshold] = -1
    return signal

三件事不属于本文的一部分,因为它们已经在这里解决了:

限制

因果不确定性边界

格兰杰因果关系不是因果关系。 混杂因素(一个宏观事件移动两条腿,时间戳略有偏差)、共同驱动因素(两个替代品都以不同的速度跟随 BTC)和遗漏变量(在系统中没有 ETH 的情况下测试 BTC 到 DOGE)都会产生重要的统计数据,但没有直接的信息流。正如本文所做的那样,限制双变量测试会使遗漏变量问题变得更糟,而不是更好。

线性。 该检验仅在条件均值中看到线性预测结构。加密货币具有波动性集群、杠杆效应和机制切换——有关第二时刻的故事,请参阅GARCH波动性预测DCC-GARCH动态相关性]。值得了解的非线性替代方案:Diks-Panchenko (2006) 内核测试、传递熵作为信息论模拟,以及整个联合分布中的 copula Granger 因果关系。

结构中断。 在一个窗口上估计的任何关系都以该窗口的状态为条件;上面的滚动测试是最低限度的诊断,它是诊断,而不是修复。

## 概括

从噪声中提取的鲁棒超前滞后信号

  1. 将 VAR 拟合到级别,通过每对 BIC 选择 pp,通过 dmaxd_{max} 进行增强,并仅对第一个 pp 滞后进行 Wald 测试。手动构建限制矩阵 - 库的 test_causality 也限制了增广滞后,这不是 Toda-Yamamoto。
  2. 在相同的对和滞后上运行差异回报测试作为基线,并报告分歧。这张表就是我们的发现;星号矩阵不是。
  3. 通过有效 N(而不是 Bonferroni)纠正相关测试家族的矩阵,并报告有多少细胞存活。
  4. 卷起来。报告重要窗口的分数和交叉计数。无论汇总 p 值有多小,闪烁的显着性都不是可交易的滞后。
  5. 在相信任何 lag-1 结果之前,放弃间隙而不是向前填充,并检查场地之间的时钟对齐情况。

这一过程的完美结果是负面的——样本中显着的 BTC 与 alt 关系,经受住修正,并且每隔几百根柱仍然在两个方向上穿过 0.05 线,这是关于可交易性的真实结果,值得作为一个结果发布。

## 参考

免责声明:本文提供的信息仅用于教育和参考目的,不构成财务、投资或交易建议。加密货币交易涉及重大损失风险。

Authors

Eugen Soloviov
Eugen Soloviov

Trading-systems engineer

Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.

Newsletter

紧跟市场步伐

订阅我们的时事通讯,获取独家 AI 交易见解、市场分析和平台更新。

我们尊重您的隐私。您可以随时退订。