Vine Copulas
C-vine and D-vine decompositions for multi-market tail risk
Vine copulas extend bivariate copula modeling to three or more markets. Instead of fitting one giant multivariate copula (which forces a single dependence shape on all pairs), vines decompose the joint distribution into a tree of bivariate copulas, each of which can be a different family. This lets you capture the fact that markets A and B crash together (Clayton) while B and C rally together (Gumbel).
API
Fit a vine
python
import numpy as np
# Returns matrix: rows = observations, columns = markets
returns = np.column_stack([returns_a, returns_b, returns_c, returns_d])
vine = hz.fit_vine(returns, vine_type="c-vine")
vine.tree_structure # list of tree levels with pair assignments
vine.pair_copulas # dict mapping (i, j) -> {family, param, tau}
vine.log_lik # total log-likelihood
vine.aic # model AIC
Vine types
- C-vine (canonical vine): one central node per tree level. Use when one market dominates the dependence structure (e.g., SPY drives everything).
- D-vine (drawable vine): sequential chain. Use when markets have a natural ordering (e.g., along a yield curve or a supply chain).
python
# C-vine: SPY as the center
vine_c = hz.fit_vine(returns, vine_type="c-vine")
# D-vine: sequential pairing
vine_d = hz.fit_vine(returns, vine_type="d-vine")
Risk monitoring
python
monitor = hz.vine_risk_monitor()
# Configure with a fitted vine
monitor.set_vine(vine)
# On new data, compute joint tail probability
joint_tail = monitor.joint_tail_prob(
quantiles=[0.05, 0.05, 0.05, 0.05] # all four markets in 5th percentile
)
# Conditional dependence
cond = monitor.conditional_dependence(
target=0, # market index
given={1: 0.02}, # conditioning: market 1 at 2nd percentile
)
Tree structure example
For four markets (A, B, C, D) in a C-vine with A as center:
Tree 1: A-B A-C A-D (3 bivariate copulas)
Tree 2: B-C|A B-D|A (2 conditional copulas)
Tree 3: C-D|AB (1 conditional copula)
Each edge is a bivariate copula fitted to (possibly conditional) uniform margins. The vine captures 6 pairwise dependence structures with only 6 bivariate fits.
When to use
- Multi-market tail risk: compute the probability that 3+ correlated markets all crash simultaneously, accounting for asymmetric tail dependence.
- Portfolio stress testing: condition on one market dropping to its 5th percentile and compute the implied distribution of the rest.
- Prediction market contagion: election outcomes, sports events, or crypto markets often have dependence structures that change across the distribution. A vine captures this without forcing Gaussian assumptions.
python
# Stress test: what happens to markets C, D if A drops to 1st percentile?
stressed = monitor.conditional_dependence(
target=2, # market C
given={0: 0.01}, # market A at 1st percentile
)
print(f"P(C < 5th pct | A at 1st pct) = {stressed.prob_below_05:.3f}")