Lead-Lag Networks

Hayashi-Yoshida correlation, cross-correlation lags, and Granger causality

Markets don’t move in isolation. Bitcoin moves before altcoins, SPY moves before sector ETFs, Polymarket moves before Kalshi on the same event. Lead-lag analysis finds these relationships and quantifies how much predictive signal one market gives about another. Horizon provides three tools: Hayashi-Yoshida asynchronous correlation, cross-correlation lag analysis, and Granger causality testing.

API

Hayashi-Yoshida correlation

Standard correlation requires synchronized timestamps. The Hayashi-Yoshida estimator works on irregularly sampled data — it computes correlation from overlapping time intervals, which is how real tick data arrives.

python
corr = hz.hayashi_yoshida(ts1, ts2)
# ts1, ts2: list of (timestamp, price) tuples
# Returns: float in [-1, 1]

Cross-correlation lags

Find the lag at which two time series are most correlated. Positive lag means x leads y.

python
lags = hz.cross_correlation_lags(x, y, max_lag=20)
# Returns: list of (lag, correlation) tuples, sorted by |correlation|

best_lag, best_corr = lags[0]
print(f"x leads y by {best_lag} periods (corr={best_corr:.3f})")

Granger causality

Tests whether past values of x help predict y beyond what past values of y alone provide.

python
result = hz.granger_causality(x, y, max_lag=10)
# result.f_statistic: float
# result.p_value: float
# result.optimal_lag: int
# result.significant: bool (p_value < 0.05)

Building a lead-lag network

Combine pairwise analysis into a directed graph of market relationships:

python
markets = ["BTC", "ETH", "SOL", "AVAX", "MATIC"]
edges = []

for i, m1 in enumerate(markets):
    for j, m2 in enumerate(markets):
        if i == j:
            continue
        result = hz.granger_causality(returns[m1], returns[m2], max_lag=5)
        if result.significant:
            edges.append((m1, m2, result.optimal_lag))
            print(f"{m1} -> {m2} (lag={result.optimal_lag}, p={result.p_value:.4f})")

# Result: a directed graph where edges indicate predictive relationships

Cross-market signal extraction

Use the lead-lag structure to generate trading signals:

python
# If BTC leads ETH by 2 periods with high correlation:
lags = hz.cross_correlation_lags(btc_returns, eth_returns, max_lag=10)
best_lag, best_corr = lags[0]

if best_lag > 0 and abs(best_corr) > 0.3:
    # BTC moved but ETH hasn't caught up yet
    btc_move = btc_returns[-best_lag:]
    expected_eth_move = sum(btc_move) * best_corr
    # Trade ETH in the direction of expected_eth_move

When to use

  • Cross-exchange arbitrage: detect which venue leads on a given contract (e.g., Polymarket vs. Kalshi for the same event).
  • Crypto signal propagation: build a directed graph of which tokens lead others and trade the followers.
  • Sector rotation: find which sector ETFs lead the broader market and position early.
  • Asynchronous data: use Hayashi-Yoshida when your data sources have different update frequencies or irregular timestamps.

Next