Cross-Impact Matrix

Multi-market price impact estimation and contagion channels

Cross-impact quantifies how trading in one market moves prices in correlated markets. When you buy heavily in market A, you affect not just A’s price but also markets B and C if they share common risk factors. Horizon estimates an N-by-N impact matrix separating self-impact (diagonal) from cross-impact (off-diagonal).

API

Estimate from historical data

python
import numpy as np

# returns: (T, N) matrix of N market returns over T periods
# volumes: (T, N) matrix of signed trade volumes (positive = buy)
returns = np.array([...])
volumes = np.array([...])

impact = hz.estimate_cross_impact(returns, volumes)

impact.matrix         # (N, N) impact matrix G
impact.self_impact    # diagonal entries [G_11, G_22, ...]
impact.cross_impact   # off-diagonal entries as dict {(i,j): G_ij}
impact.eigenvalues    # eigenvalues of G (check for stability)
impact.condition_num  # condition number (high = fragile estimate)

Estimator with rolling updates

python
estimator = hz.CrossImpactEstimator(
    n_markets=4,
    window=500,          # rolling estimation window
    regularization=0.01, # shrinkage toward diagonal
)

# Incremental updates
estimator.update(returns_row, volumes_row)

# Current estimate
G = estimator.matrix()

# Predict impact of a trade vector on all markets
trade = [100, 0, -50, 0]  # buy 100 of market 0, sell 50 of market 2
predicted_moves = estimator.predict_impact(trade)

Interpretation

The impact matrix G maps a trade vector q to expected price changes dp:

dp = G @ q
  • G[i][i] (diagonal): self-impact. How much trading market i moves its own price.
  • G[i][j] (off-diagonal): cross-impact. How much trading market j moves market i’s price.

Large off-diagonal entries indicate contagion channels. If G[BTC][ETH] is large, heavy ETH selling will drag BTC down.

Example: prediction market contagion

python
# Three correlated election markets
returns = np.column_stack([pres_returns, senate_returns, house_returns])
volumes = np.column_stack([pres_volume, senate_volume, house_volume])

impact = hz.estimate_cross_impact(returns, volumes)

# Check: does trading the presidential market move senate odds?
print(f"Pres -> Senate impact: {impact.cross_impact[(1, 0)]:.4f}")
print(f"Pres self-impact:      {impact.self_impact[0]:.4f}")

When to use

  • Execution optimization: if you need to trade two correlated markets, sequence trades to minimize total impact (trade the less-impactful one first).
  • Portfolio rebalancing: estimate total market impact of a multi-leg rebalance before executing.
  • Contagion detection: monitor off-diagonal entries over time. Spikes indicate increased market coupling, often before a volatility event.
  • Market making: adjust quotes in market B when you see large flow in correlated market A.
python
# Optimal execution: minimize total impact across two markets
trade_a, trade_b = 200, -150
total_impact = (
    G[0][0] * trade_a + G[0][1] * trade_b,  # impact on A
    G[1][0] * trade_a + G[1][1] * trade_b,   # impact on B
)

Next