Toda-Yamamoto vs Differenced Granger: Does the BTC Lead-Lag Survive?
Bijna elk gepubliceerd Granger-causaliteitsresultaat op crypto wordt berekend op basis van log-returns. Die keuze is niet vrij. Door differentiëren wordt de serie stationair, wat de standaard F-test vereist, maar wordt ook de niveaurelatie genegeerd – en als twee munten worden samengevoegd, wordt de gedifferentieerde VAR verkeerd gespecificeerd en beantwoordt de test een iets andere vraag dan de vraag die u stelde.
Toda en Yamamoto (1995) bieden een uitweg: pas de VAR toe op niveaus met extra vertragingen, test alleen de originele en verkrijg een geldige ongeacht eenheidswortels of co-integratie. Het is algemeen bekend in de econometrie en wordt bijna nooit toegepast op crypto-lead-lag.
Dit artikel doet dus één ding: voer beide tests uit op dezelfde paren, in hetzelfde venster, en rapporteer of ze het er niet mee eens zijn. Pas vervolgens de eerlijke follow-up toe: een gecorreleerde familie-meervoudige testcorrectie op de resulterende matrix, en een voortschrijdende p-waarde om te zien of de "significante" vertraging stabiel genoeg is om te handelen of alleen maar over de drempel flikkert.
Onderstaande theorie is slechts zoveel als nodig is om de vergelijking leesbaar te maken. De blog behandelt al unitroots, co-integratie, het laden van gegevens, omvang en kosten; dat zijn links, geen secties.
Wat de causaliteit van Granger eigenlijk beweert

Granger-causaliteit is voorspellende prioriteit, geen mechanisme: Granger-oorzaken indien verleden vermindert de voorspellingsfoutvariant van voorbij wat voorbij is legt het al uit.
Granger-oorzaken als
Twee reeksen die worden aangestuurd door een gemeenschappelijke verborgen factor kunnen Granger-causaliteit aantonen zonder dat er een direct verband tussen bestaat. In crypto is dat voorbehoud niet academisch – BTC is een enkele dominante factor in het hele altcoin-complex, dus bijna elke alt-naar-alt ‘causaliteit’ is een kandidaat-artefact van verschillende reactiesnelheden op dezelfde BTC-schok.
Het VAR-framework
De test bevindt zich in een vector-autoregressie. Voor twee variabelen met blijft achter:
In matrixvorm een VAR(p) met variabelen:
Testen of Granger-oorzaken test de gezamenlijke beperking in de eerste vergelijking. De standaardroute is een F-test op beperkte versus onbeperkte restsommen van kwadraten,
met de asymptotisch equivalente Wald-vorm . Alles wat volgt is een vraag over op welke coëfficiënten die beperking wordt toegepast en op welke gegevens de VAR is toegepast.
Vertragingsselectie
Het is belangrijker dan de meeste artikelen toegeven: te weinig vertragingen missen de dynamiek, te veel verbranden de vrijheidsgraden en vernietigen de macht.
Redelijke zoekbereiken: 1-60 op secondegegevens, 1-30 op minuutgegevens, 1-48 op uurgegevens. BIC is hier de juiste standaard – het is het spaarzamere criterium, en lead-lag in vloeibare cryptoparen is een fenomeen van korte duur. Elk resultaat hieronder vermeldt de geselecteerde BIC per paar in plaats van één vertraging voor het hele universum vast te stellen, omdat een vaste vertraging een keuze voor een vertragingsselectie stilzwijgend omzet in een significantieclaim.
Waarom de gedifferentieerde test de verkeerde standaard is

Crypto-prijsreeksen zijn I(1). De gebruikelijke oplossing – log-rendementen nemen – koopt stationariteit ten koste van het co-integratieniveau, en als het paar een langetermijnevenwicht deelt, wordt de gedifferentieerde VAR verkeerd gespecificeerd. De unit-root- en co-integratiemachinerie achter die zin (ADF, Engle-Granger met zijn kritische waarden van Monte-Carlo, Johansen op een VAR-systeem) wordt al behandeld in statistische arbitrage en parenhandel; neem het hier maar aan. Het punt is alleen dat de gebruikelijke remedie – verschil, dan testen – een modelbeslissing is met consequenties, en Toda-Yamamoto de manier is om deze beslissing te vermijden.
De Toda-Yamamoto-procedure
Monteer een VAR met blijft achter, waar is de optimale lagvolgorde en is de maximale integratievolgorde van de reeks, test dan de beperkingen alleen op de eerste blijft achter. De extra vertragingen absorberen de niet-stationariteit; de Wald-statistiek op de eerste coëfficiënten volgt een standaard ongeacht of de reeksen I(0), I(1) of co-geïntegreerd zijn.
- Bepaal — ADF en KPSS voor elke serie. Voor cryptoprijzen bijna altijd.
- Selecteer — pas een VAR op niveaus toe, kies op BIC.
- Schat de verhoogde VAR() op niveaus, geen verschil.
- Wald-test de eerste blijft alleen achter, waarbij de extra's. Resultaat is .
Het resultaat: geen pre-test voor co-integratie, geen differentiatie en correcte testomvang – het afwijzingspercentage onder de nul blijft vrijwel nominaal, ongeacht de integratie-eigenschappen. De prijs is dat stap 4 niet is wat test_causality standaard gebeurt, en dat is waar de meeste implementaties stilletjes fout gaan.
Implementatie

Stel dat je al minutenbalken in een DataFrame hebt uitgelijnd: de ccxt-fetch-and-index-boilerplate bevindt zich in [regime-detectie met HMM] (/en/blog/post/regime-detection-hmm-adaptive-trading), en de ADF-wrapper die je zou gebruiken voor stap 1 bevindt zich in [statistische arbitrage en parenhandel] (/en/blog/post/statistical-arbitrage-pairs-trading-crypto).
Eén versieopmerking voordat dit wordt uitgevoerd: grangercausalitytests(..., verbose=False) is verouderd en vervolgens verwijderd in statsmodels 0.15. Laat het argument vallen (de functie wordt standaard niet meer afgedrukt) of pin statsmodels<0.15. De onderstaande code gaat uit van de moderne handtekening.
Toda-Yamamoto, correct gedaan
De beperking moet met de hand worden gebouwd. VARResults.test_causality test alle vertragingen van de veroorzakende variabele in het aangepaste model — op een uitgebreide VAR() inclusief de vertraging in de beperking, wat precies is wat Toda-Yamamoto zegt niet te doen. De oplossing is expliciet matrix tegen de volledige coëfficiëntcovariantie:
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,
}
Twee details die gemakkelijk fout kunnen gaan en die de test ongeldig maken als u dat wel doet. Ten eerste moet de indexberekening overeenkomen met de manier waarop statsmodellen platter worden params — controleer dat op een gemonteerd model beta[target_idx * n_per_eq + 1] gelijk aan res.params.iloc[1, target_idx] voordat u een p-waarde vertrouwt. Ten tweede: gebruik np.linalg.solve, niet pinv: als is enkelvoudig, de beperking is gedegenereerd en de run zou luid moeten mislukken in plaats van een plausibel ogend getal terug te geven. Een pseudo-inverse hier is hoe gebroken Wald-tests de codebeoordeling overleven.
Standaard gedifferentieerde Granger, ter vergelijking
De basislijn waartegen de vergelijking geldt: log-returns, dezelfde paren, dezelfde BIC-vertraging:
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}
Opmerking maxlag=[p] in plaats van maxlag=p: het passeren van een int loopt elke vertraging van 1 tot en verleidt u om de beste te rapporteren, wat een niet-gelogde meervoudige test is bovenop de meervoudige test die u al uitvoert.
De vergelijking
Voer voor elk paar de gedifferentieerde test uit op rendementen en Toda-Yamamoto op niveaus, op dezelfde BIC-geselecteerde , en maak een tabel waar de twee het niet eens zijn. Onenigheid is de interessante cel: een paar dat significant is op het gebied van verschillen, maar niet op niveaus, is een kandidaat-artefact om een co-integratierelatie weg te werken; het omgekeerde suggereert dat de niveaurelatie informatie bevat die de retourtest niet kan zien.
Meerdere vergelijkingen op een causaliteitsmatrix

De volledige matrix is waar dit gevaarlijk wordt. Een sweep met 20 activa en 10 vertragingen is 3.800 hypothesetests, en Bonferroni is de verkeerde correctie voor een gezin dat zo gecorreleerd is: de tests delen gegevens, delen de BTC-factor en zijn lang niet onafhankelijk, dus Bonferroni is tegelijkertijd te conservatief in totaal en misleidend over welke cellen overleven. Gebruik de effectieve-N-machinerie uit het leeggelopen Sharpe-artikel, die precies voor deze situatie is gebouwd: cluster de gecorreleerde testfamilie, tel onafhankelijke onderzoeken in plaats van ruwe, en drempel daartegen.
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
Het getal dat er toe doet is niet hoeveel cellen onder de 0,05 zijn; het gaat erom hoeveel cellen de effectieve-N-gecorrigeerde drempel overleven.
Lees de overgebleven matrix structureel, niet cel voor cel: rijen waarin één asset vele andere veroorzaakt, bevestigen een informatiehiërarchie; een kolom die door niets wordt veroorzaakt, suggereert eerder een idiosyncratische, token-specifieke dynamiek dan een ontdekking.
De eerlijke test: rolstabiliteit

Een enkele p-waarde in de steekproef is vrijwel waardeloos voor de handel. De relevante vraag is of de betekenis aanhoudt. Cross-asset relaties in crypto zijn afhankelijk van het regime – de correlatiestructuur verschilt scherp tussen kalmte en paniek, en het regime zelf is schatbaar (HMM regime detectie) – dus een lead-lag die over één venster wordt geschat, is een uitspraak over dat venster.
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")
Rapporteer twee dingen uit deze reeks: het aandeel vensters onder de 0,05 en het aantal drempeloverschrijdingen. Een relatie die significant is in 80% van de vensters met drie kruisingen is een ander object dan een relatie die significant is in 55% van de vensters met veertig kruisingen, zelfs als de gepoolde p-waarde identiek is. De tweede is niet verhandelbaar: u kunt geen positie inschatten op een signaal waarvan het bestaan elke paar honderd maten verandert, en de vertraging bij het opnieuw schatten garandeert dat u altijd op het vorige regime handelt.
De dataval die specifiek is voor Granger

Generieke crypto-datahygiëne wordt elders behandeld – hiaten en ontbrekende kaarsen in backtest-live parity, tijdstempeldiscipline in de look-ahead bias taxonomie en bewijst dat er geen vooruitblik is over tijdsbestekken. Eén faalwijze is echter Granger-specifiek en ernstig genoeg om te noemen:
Voorwaarts vullen zorgt voor het resultaat. Een voorwaarts gevulde kaars herhaalt de vorige afsluiting, waardoor pure autocorrelatie in de reeks wordt geïnjecteerd – en lag-1 autocorrelatie in dat mechanisch is uitgelijnd is volgens de F-test niet te onderscheiden van een oorzakelijk verband met één vertraging. Hetzelfde geldt voor alle locaties: een klokafwijking van 1 seconde tussen twee uitwisselingen op minutenbalken kan een lag-1-betekenis creëren of vernietigen, omdat het verschuift aan welke kant van de balkgrens een zet terechtkomt. Voordat u dit uitvoert, moet u controleren of er gaten zijn weggelaten in plaats van opgevuld, en of beide series uit dezelfde klok zijn gestempeld.
Gerapporteerde lead-lag-bevindingen in de literatuur

Dit zijn citaten, geen metingen uit dit artikel. Ze zijn hier om te zeggen wat het gepubliceerde record beweert, zodat de bovenstaande vergelijking iets bevat waar ze het mee eens of oneens zijn.
- BTC naar altcoins. Een onderzoek uit 2026 naar financiële markten in Azië en de Stille Oceaan (Springer) rapporteert hoogfrequente prijstransmissie van Bitcoin naar altcoins, waarbij small-cap-munten aanzienlijk vertraagde reacties vertonen en een lagere liquiditeit in verband met langzamere reacties. De vertragingsgrootten die gewoonlijk in dit vakgebied worden aangehaald – ruwweg 1-3 minuten BTC tot ETH, langer voor mid- en small-caps, en steeds meer unidirectioneel naarmate de marktkapitalisatie daalt – zijn geciteerde bevindingen, die hier niet opnieuw zijn afgeleid. De marktkapitalisatie waarop ze rusten is dezelfde ladder die wordt gebruikt in multi-symbol validation.
- CEX leidt DEX. Onderzoek naar crypto-microstructuur (MDPI) rapporteert gecentraliseerde platforms die de prijsontdekking domineren, waarbij de informatiestroom CEX-naar-DEX loopt en geen significante omgekeerde causaliteit – consistent met matching-engines van minder dan een milliseconde versus bloktijdafrekening.
- ETH als onafhankelijke munt. VAR-SVAR-werk (MDPI) vindt regimes waarin Ethereum fungeert als de bron en Bitcoin als de ontvanger van de overloop, met name tijdens door DeFi en NFT aangestuurde fasen.
Kort een uitwisseling
De vertraging op twee locaties op dezelfde munt is een echte opzet, maar de economische aspecten ervan – drempels voor vergoedingen, de latentieladder, waarom de vertraging überhaupt bestaat – zijn al uitgewerkt in [statistische arbitrage en handel in paren] (/en/blog/post/statistical-arbitrage-pairs-trading-crypto) en [de kimchi-premie] (/en/blog/post/kimchi-premium-arbitrage). Het enige dat Granger toevoegt is een stabiliteitsvraag: is de causaliteit tussen Binance en Coinbase aanhoudend significant, of flikkert het zoals al het andere? Voer de roltest uit op het locatiepaar; het antwoord is een tijdreeks met een p-waarde, geen ja.
Een overgebleven achterstand omzetten in een positie

Als een paar de gecorrigeerde drempelwaarde en de roltest overschrijdt, is het signaal zelf triviaal: cumulatieve voorspellerretour over het vertragingsvenster, met een drempelwaarde.
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
Drie zaken die geen deel uitmaken van dit artikel omdat ze hier al geregeld zijn:
- De kosten bepalen het. Een vertragingssignaal op minuutschaal op altcoins moet de spreiding, impact en kosten opruimen - zie slippage and cost models en maker-takereconomics, en wat er gebeurt als er kosten worden toegepast op een geselecteerde winnaar.
- Sizing is geen p-waarde-transformatie. Het schalen van de blootstelling omgekeerd aan de Granger-p-waarde is verkeerd: een p-waarde is bewijs tegen een nul, geen effectgrootte, en beweegt mee met de steekproeflengte. Grootte van het geschatte effect en de onzekerheid ervan — zie Kelly sizing.
- Validatie is walk-forward. Herschat op voortschrijdende basis en evalueer buiten de steekproef; walk-forward-optimalisatie is het protocol.
Beperkingen

Granger-causaliteit is geen causaliteit. Confounders (een macro-gebeurtenis die beide benen beweegt met een kleine verkeerde uitlijning van de tijdstempel), algemene drivers (twee alts die BTC beide met verschillende snelheden volgen) en weggelaten variabelen (het testen van BTC naar DOGE zonder ETH in het systeem) produceren allemaal significante statistieken zonder directe informatiestroom. Het beperken tot bivariate tests, zoals dit artikel doet, maakt het probleem van de weggelaten variabelen erger, niet beter.
Lineariteit. De test ziet alleen een lineaire voorspellende structuur in het voorwaardelijke gemiddelde. Crypto heeft volatiliteitsclustering, hefboomeffecten en regime-switches – zie GARCH volatility forecasting en DCC-GARCH dynamic correlatie voor het tweede verhaal. Niet-lineaire alternatieven die de moeite waard zijn om te weten: de kerneltest van Diks-Panchenko (2006), overdrachtsentropie als informatietheoretische analoog, en copula Granger-causaliteit over de volledige gezamenlijke distributie.
Structurele breuken. Elke relatie die op één raam wordt geschat, is afhankelijk van het regime van dat raam; de bovenstaande rolling test is de minimale diagnose, en het is een diagnose, geen oplossing.
Samenvatting

- Pas de VAR aan op niveaus, selecteer met BIC per paar, vermeerderd met , en Wald-test de eerste blijft alleen achter. Bouw de restrictiematrix met de hand – die van de bibliotheek
test_causalitybeperkt ook de toenemende vertraging, wat niet Toda-Yamamoto is. - Voer de gedifferentieerde retourtest uit als basislijn voor dezelfde paren en vertragingen, en rapporteer de meningsverschillen. Die tabel is de bevinding; een matrix van sterretjes is dat niet.
- Corrigeer de matrix voor een gecorreleerde testfamilie via effectieve N, niet Bonferroni, en rapporteer hoeveel cellen er overleven.
- Rol het. Rapporteer de fractie van significante vensters en het aantal kruisingen. Het is belangrijk dat flikkeringen geen verhandelbare vertraging zijn, hoe klein de gepoolde p-waarde ook is.
- Laat gaten weg in plaats van voorwaarts op te vullen, en controleer de uitlijning van de klok op alle locaties, voordat je een lag-1-resultaat gelooft.
Een perfect goede uitkomst van deze procedure is negatief: een BTC-alt-relatie die significant is in de steekproef, de correctie overleeft en nog steeds om de paar honderd maten de 0,05-lijn in beide richtingen overschrijdt, is een reëel resultaat over verhandelbaarheid en de moeite waard om als één resultaat te publiceren.
Referenties
- Granger, C.W.J. (1969). "Onderzoek naar causale relaties door econometrische modellen en cross-spectrale methoden." Econometrica, 37(3), 424-438.
- Toda, H.Y. en Yamamoto, T. (1995). "Statistische gevolgtrekking in vectorautoregressies met mogelijk geïntegreerde processen." Journal of Econometrics, 66(1-2), 225-250.
- Diks, C. en Panchenko, V. (2006). "Een nieuwe statistiek en praktische richtlijnen voor niet-parametrische Granger-causaliteitstests." Journal of Economic Dynamics and Control, 30(9-10), 1647-1669.
- Sifat, IM, Mohamad, A. (2019). "Lead-Lag-relatie tussen Bitcoin en Ethereum: bewijs uit gegevens per uur en per dag." Onderzoek in internationaal zakendoen en financiën, 50, 306-321.
- "Prijstransmissie van Bitcoin naar Altcoins: hoogfrequent bewijs en implicaties voor handelsstrategie." Financiële markten Azië-Pacific, Springer, 2026.
- "Overlooprisico's op cryptocurrency-markten: een blik van VAR-SVAR Granger Causaliteit." Journal of Risk and Financial Management, MDPI.
- "De tweeledige structuur van markten voor financieringstarieven voor cryptocurrency." Wiskunde, MDPI.
- "Gedecentraliseerde en gecentraliseerde uitwisselingen: welke digitale tokens vormen een groter besmettingsrisico?" ScienceDirect, 2023.
Auteurs
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.