DCC-GARCH: динамические корреляции для парного трейдинга и риска портфеля
Спросите большинство крипто-деском о корреляции между BTC и ETH — и вы получите одно число: 0.8, может быть 0.75, посчитанное на каком-то окне, выбор которого уже никто не помнит. Это число — ложь, или как минимум опасное упрощение. Выборочная корреляция — это среднее за период, в течение которого истинная структура зависимости постоянно менялась. В спокойные периоды BTC и ETH расходятся достаточно, чтобы рыночно-нейтральная пара выглядела привлекательно. В каскаде ликвидаций они смыкаются друг с другом и со всем остальным рынком, и диверсификация, за которую вы заплатили, испаряется именно в тот момент, когда она нужнее всего.
Это не тонкий эффект. Возьмите любую просадку 2022 года — коллапс LUNA в мае, разворачивание 3AC в июне, крах FTX в ноябре — и вы увидите, как средняя попарная корреляция среди топ-20 токенов за несколько дней уходит из диапазона 0.4-0.6 к уровню 0.9+. Корреляция — не константа, которую иногда плохо оценивают; это временной ряд со своей динамикой, своей кластеризацией и своими режимами. Считать ее скаляром — это многомерный аналог допущения о постоянной волатильности, ошибки, которую мы уже разобрали для одного актива в первой части этой серии.
Эта статья — третья часть серии из четырех статей о волатильности. Часть 1 построила одномерный GARCH(1,1) с библиотекой arch и показала, как волатильность кластеризуется и возвращается к среднему. Часть 2 добавила асимметрию (GJR-GARCH, EGARCH) и инновации Стьюдента для учета эффекта левериджа и толстых хвостов. Здесь мы переходим к многомерному случаю: моделируем всю условную ковариационную матрицу по мере ее эволюции, используя модель динамической условной корреляции (DCC) Энгла. Это дает нам две вещи, которых никогда не даст скалярная корреляция — динамический хедж-коэффициент для парного трейдинга и честную, изменяющуюся во времени дисперсию портфеля для распределения активов на основе риска. Часть 4 завершает серию бэктестом стратегии таргетирования волатильности, которая связывает одномерные и многомерные прогнозы в правило сайзинга позиций.
Мы предполагаем, что вы уже прочли части 1 и 2, поэтому заново выводить одномерный GARCH не будем. Если вам нужно совместное хвостовое поведение — вероятность того, что два актива одновременно пробьют свой 1%-й квантиль, — это вопрос копул, и мы разбираем его в статье Модели копул для совместного риска. DCC и копулы дополняют друг друга: копула дает статичную, но гибкую структуру хвостовой зависимости, а DCC — трактуемый временной ряд всей корреляционной матрицы. Эта статья — про второе.
Почему статичная корреляция ломается в крипте
Прежде чем перейти к механике, точно опишем, что именно ломается. Одна выборочная корреляция на окне оценивает
Это несет три неявных допущения, все из которых ложны для крипты:
- Стационарность зависимости. У окна есть одно истинное . На деле зависимость проходит через режимы — режим спокойного рынка около 0.5 и стрессовый режим около 0.95 — и смешивает их в бессмысленное среднее.
- Постоянная маргинальная волатильность. Корреляция Пирсона — это нормированная ковариация. Если и сами по себе меняются (а они меняются — в этом весь смысл частей 1 и 2), то даже постоянная ковариация порождает изменяющуюся во времени корреляцию, и наоборот. Разделить их без базовой модели волатильности невозможно.
- Симметрия относительно направления рынка. Корреляция растет при просадках сильнее, чем при ралли. Это многомерный аналог эффекта левериджа. Скользящее окно не способно это выразить, не становясь настолько коротким, что превращается в чистый шум.
Исправление через скользящее окно — пересчитывать за последние 30 или 60 дней — меняет одну проблему на другую. Короткие окна отзывчивы, но зашумлены и отстают от реального разлома; длинные — стабильны, но устаревают. Хуже того, скользящая корреляционная матрица по активам не гарантированно остается положительно полуопределенной, как только вы начинаете ее сжимать или латать, что ломает любой последующий оптимизатор. Нам нужна модель, которая (а) управляется корректным процессом волатильности по каждому активу, (б) на каждом шаге по построению дает валидную корреляционную матрицу и (в) имеет параметры, которые можно оценить методом максимального правдоподобия, а не подбором длины окна наугад. Такая модель — DCC-GARCH.
Многомерная задача: условная ковариационная матрица
Пусть — вектор доходностей для активов в момент , с условным средним (часто просто константа или небольшой AR-член) и остатком . Предполагаем
где — условная ковариационная матрица при информационном множестве , а — некоторое условное распределение (гауссово или, что лучше для крипты, многомерное Стьюдента). Все многомерное моделирование волатильности сводится к разным ответам на один вопрос: как параметризовать динамику так, чтобы она на каждом шаге оставалась симметричной положительно определенной без взрывного роста числа параметров?
Два классических ответа показывают, насколько сложна задача.
VECH
Модель VECH (Боллерслев, Энгл, Вулдридж, 1988) записывает полувекторизацию как линейную функцию прошлых квадратов остатков и прошлых ковариаций:
где укладывает нижний треугольник симметричной матрицы в вектор длины . Это максимально общая модель — каждая дисперсия и ковариация зависит от каждой прошлой дисперсии и ковариации — и максимально бесполезная после . Для активов и — это матрицы размера каждая. При это две матрицы , примерно 450 параметров, плюс ограничения положительной определенности, которые тяжело даже сформулировать. Поверхность правдоподобия — это болото.
BEKK
Модель BEKK (Энгл и Кронер, 1995) гарантирует положительную определенность по построению через квадратичную форму:
где верхнетреугольная. Поскольку каждое слагаемое — квадратичная форма, автоматически, пока . BEKK экономнее VECH, но все еще масштабируется как параметров — матрицы и каждая размера . При вы оцениваете методом максимального правдоподобия совместно порядка 200+ параметров на зашумленных дневных крипто-данных без гарантии, что оптимизатор сойдется к чему-то осмысленному. На практике полный BEKK ограничен , и даже тогда используют "диагональные" или "скалярные" ограничения, отбрасывающие большую часть кросс-динамики.
Это и есть проклятие размерности для многомерного GARCH: число параметров растет квадратично, а объем информации в данных — нет. Степени свободы заканчиваются задолго до того, как заканчиваются интересующие вас активы. Любая крипто-книга из 10-30 токенов совершенно недостижима для VECH или BEKK.
Выход, найденный Энглом, — перестать пытаться моделировать напрямую и вместо этого разложить ее на факторы, которые мы уже умеем дешево оценивать.
DCC Энгла (2002): двухшаговая декомпозиция
Модель постоянной условной корреляции (CCC) Боллерслева (1990) была первой экономной факторизацией. Она записывается как
где — диагональная матрица условных стандартных отклонений (один одномерный GARCH на актив), а — постоянная корреляционная матрица. Это огромное упрощение: вы подгоняете независимых одномерных моделей GARCH, затем оцениваете одну выборочную корреляционную матрицу стандартизованных остатков. Положительная определенность гарантируется автоматически, пока — валидная корреляционная матрица, а все .
Проблема CCC прямо в названии — корреляция постоянна, а именно это допущение мы отвергли в начале статьи. Динамическая условная корреляция Энгла (2002) сохраняет красивую факторизацию CCC, но позволяет корреляционной матрице "дышать":
Теперь изменяется во времени. Гениальность в том, что волатильности и корреляции оцениваются в два отдельных шага, поэтому нам никогда не приходится решать полную совместную оптимизацию .
Шаг 1: одномерный GARCH для каждого актива
Для каждого актива подгоняем одномерную модель GARCH точно так же, как в частях 1 и 2 — GARCH(1,1), GJR-GARCH или EGARCH с инновациями Стьюдента, в зависимости от того, что лучше подходит данному ряду. Это дает условные дисперсии и, следовательно, .
Из подогнанных моделей извлекаем стандартизованные остатки:
По построению каждый имеет (приблизительно) единичную условную дисперсию. Складываем их в вектор . Эти стандартизованные остатки — сырье для шага корреляции: из них уже вычтена индивидуальная динамика волатильности, поэтому оставшееся совместное движение — чистая зависимость, а не артефакт волатильности. (Это та же логика PIT-преобразования, что используется в статье про копулы перед подгонкой маргиналов; здесь мы останавливаемся на стандартизации, не доходя до равномерного распределения.)
Шаг 2: рекурсия корреляции DCC
Моделируем вспомогательный процесс — симметричную положительно определенную матрицу — с GARCH-подобной рекурсией, управляемой внешними произведениями стандартизованных остатков:
где:
- — безусловная корреляционная матрица стандартизованных остатков (это таргетирование корреляции — подробнее ниже),
- управляет тем, насколько сильно сегодняшний шок тянет корреляцию,
- управляет персистентностью — какая доля вчерашней переносится вперед,
- а ограничение возврата к среднему — это (при ), прямая аналогия в одномерном GARCH.
Обратите внимание, структура идентична скалярной рекурсии GARCH(1,1), но на матрицах: долгосрочный якорь , шоковый член и персистентный член. Поскольку это выпуклая комбинация положительно полуопределенных матриц (, ранг-1 внешнее произведение и предыдущая ), остается положительно определенной, пока и веса неотрицательны. Именно это бесплатно дает нам гарантированно валидные ковариационные матрицы.
— это почти корреляционная матрица, но не совсем: ее диагональ не в точности равна 1. Поэтому нормируем ее:
Поэлементно условная корреляция между активами и равна
Эта — корректная корреляционная матрица (единичная диагональ, внедиагональные элементы в , положительная определенность) на каждом временном шаге, по построению. Восстанавливаем полную условную ковариацию:
Эта последняя поэлементная форма — та, которую вы будете использовать постоянно: условная ковариация двух активов равна их динамической корреляции, умноженной на каждую из их динамических волатильностей. Каждый ингредиент справа изменяется во времени и берется из модели, которую можно оценить.
Вся модель имеет только два параметра корреляции, и , независимо от того, или . Волатильностная часть масштабируется линейно (один одномерный GARCH на актив, у каждого ~4-5 параметров, все подгоняются независимо и тривиально параллелятся). Именно поэтому DCC масштабируется там, где BEKK и VECH не могут: проклятие размерности локализовано в , которая таргетируется (подставляется как выборочная оценка), а не оптимизируется.
Скалярное ограничение и его цена
Скаляры означают, что каждая пара активов разделяет одну и ту же динамику корреляции — одинаковую скорость адаптации и одинаковую персистентность. Корреляция BTC-ETH и корреляция DOGE-SHIB движутся в одном ритме, хотя их экономика различается. Это цена трактуемости, и обычно она приемлема. Обобщения (Generalized DCC с матрицами ; асимметричная DCC Каппьелло-Энгла-Шеппарда) ослабляют это ограничение ценой параметров и устойчивости оценки. Об aDCC — ниже.
Квази-логарифм правдоподобия DCC
Чтобы оценить и , нужно правдоподобие. Ключевой результат Энгла в том, что гауссов логарифм правдоподобия разделяется на волатильностную часть и корреляционную часть, что и обосновывает двухшаговый оценщик. Предполагая , вклад логарифма правдоподобия в момент равен
Подставим . Тогда и , и, используя :
Теперь разделим ее, добавив и вычтя :
Волатильностная часть зависит только от параметров одномерных GARCH (через ) — ее максимизация в точности эквивалентна подгонке независимых одномерных моделей GARCH, что мы сделали на шаге 1. Корреляционная часть зависит от и (через ), при заданных стандартизованных остатках из шага 1. Поэтому на шаге 2 мы максимизируем только
(член не зависит от , поэтому мы его отбрасываем). Это двухпараметрическая оптимизация вне зависимости от числа активов — в этом весь смысл. Она называется квази-правдоподобием, потому что двухшаговый оценщик состоятелен, но не полностью эффективен; стандартные ошибки нуждаются в коррекции (Энгл и Шеппард, 2001), но для генерации сигналов важны точечные оценки.
Для крипты гауссовы инновации занижают хвостовой риск. Замена на многомерное правдоподобие Стьюдента — это простая замена в (заменить гауссово ядро на плотность многомерного распределения Стьюдента и добавить параметр степеней свободы ). Мы оставляем гауссово квази-правдоподобие в оценщике ниже для ясности и отмечаем, где входит — стандартизация из частей 1-2 уже использовала t-инновации на маргиналах, что захватывает большую часть хвостового выигрыша.
Реализация на Python
Резкий, но важный факт: библиотека arch не поддерживает многомерный GARCH или DCC. arch — превосходный одномерный движок (мы опираемся на него именно для этого), но в нем нет dcc_model. Ваши практические варианты:
- Написать свой DCC поверх
arch— подогнать одномерные модели с помощьюarch, извлечь стандартизованные остатки, реализовать рекурсию и квази-правдоподобие корреляции в NumPy/SciPy, оптимизировать два скаляра. Это то, что мы делаем ниже. Около 60 строк и полностью прозрачно. - Пакет
mgarchиз PyPI — легковесная чисто питоновская реализация DCC-GARCH. Удобна для быстрой подгонки, менее гибкая, если нужны маргиналы GJR или точно настроенные t-инновации. rmgarchдля R (Алексиос Галанос) — эталонная реализация.dccspec/dccfitподдерживают DCC, aDCC, GARCH-копулу, распределение Стьюдента и корректные стандартные ошибки. Если вы занимаетесь серьезными исследованиями многомерной волатильности,rmgarch(вызываемый из Python черезrpy2, если необходимо) — золотой стандарт.
Мы строим вариант 1, потому что он делает каждый движущийся элемент явным и переиспользует одномерные навыки из частей 1-2.
Шаг 1: подгонка одномерных маргиналов GARCH с arch
import numpy as np
import pandas as pd
from arch import arch_model
from scipy.optimize import minimize
def fetch_returns(symbols, start="2022-01-01", end="2025-12-31"):
"""
Daily log returns for a list of crypto symbols.
Replace with your data source (ccxt for 24/7 exchange data,
yfinance for a quick sketch).
"""
import yfinance as yf
px = yf.download([f"{s}-USD" for s in symbols],
start=start, end=end)["Close"]
px.columns = symbols
rets = np.log(px / px.shift(1)).dropna()
return rets
symbols = ["BTC", "ETH", "SOL", "BNB"]
returns = fetch_returns(symbols)
def fit_univariate(series, dist="t"):
"""
Fit GJR-GARCH(1,1) with Student-t innovations (Part 2 model).
Returns the fitted result and the *scaled* series it was fit on.
We scale returns by 100 for the optimizer's numerical health,
exactly as in Parts 1 and 2.
"""
scaled = series * 100.0
model = arch_model(scaled, mean="Constant",
vol="GARCH", p=1, o=1, q=1, dist=dist)
res = model.fit(disp="off")
return res
fits = {s: fit_univariate(returns[s]) for s in symbols}
Z = pd.DataFrame({s: fits[s].std_resid for s in symbols}).dropna()
Sigma = pd.DataFrame({s: fits[s].conditional_volatility
for s in symbols}).loc[Z.index]
print(Z.describe())
Быстрая проверка стандартизованных остатков имеет значение. Если у какого-то столбца стандартное отклонение сильно отличается от 1, или остается сильная автокорреляция в его квадрате (тест Льюнга-Бокса на ), одномерный маргинал специфицирован неверно, и шаг DCC унаследует эту ошибку. Сначала исправьте маргинал — для этого и была часть 2.
Шаг 2: рекурсия DCC и квази-логарифм правдоподобия
def dcc_negloglik(params, Z):
"""
Negative DCC quasi-log-likelihood (Gaussian) in (a, b).
Z : (T, d) array of standardized residuals from Step 1.
Implements:
Q_t = (1-a-b) Qbar + a z_{t-1} z_{t-1}' + b Q_{t-1}
R_t = diag(Q_t)^{-1/2} Q_t diag(Q_t)^{-1/2}
LL = -1/2 sum_t ( log|R_t| + z_t' R_t^{-1} z_t )
with correlation targeting: Qbar = sample corr of Z.
"""
a, b = params
if a <= 0 or b <= 0 or a + b >= 1.0:
return 1e10
Z = np.asarray(Z)
T, d = Z.shape
Qbar = np.cov(Z, rowvar=False, bias=True) # unconditional (targeted)
dinv = np.diag(1.0 / np.sqrt(np.diag(Qbar)))
Qbar = dinv @ Qbar @ dinv
Q = Qbar.copy() # initialize Q_1 at the target
ll = 0.0
for t in range(T):
q_diag = np.sqrt(np.diag(Q))
R = Q / np.outer(q_diag, q_diag)
sign, logdet = np.linalg.slogdet(R)
if sign <= 0:
return 1e10
z = Z[t]
Rinv_z = np.linalg.solve(R, z)
ll += -0.5 * (logdet + z @ Rinv_z)
Q = (1 - a - b) * Qbar + a * np.outer(z, z) + b * Q
return -ll
def fit_dcc(Z):
"""Estimate (a, b) by maximizing the DCC quasi-log-likelihood."""
res = minimize(
dcc_negloglik, x0=[0.03, 0.94], args=(np.asarray(Z),),
method="L-BFGS-B",
bounds=[(1e-6, 0.5), (1e-6, 0.999)],
)
a, b = res.x
print(f"DCC estimates: a = {a:.4f}, b = {b:.4f}, a+b = {a+b:.4f}")
print(f"log-likelihood: {-res.fun:.2f}")
return a, b
a_hat, b_hat = fit_dcc(Z)
Запуск этого на книге BTC/ETH/SOL/BNB за несколько лет дневных данных дает результат вот такого вида (числа ниже иллюстративны, не из конкретного датированного эксперимента — запустите на своих данных):
DCC estimates: a = 0.0287, b = 0.9401, a+b = 0.9688
log-likelihood: -3812.44
Как это читать:
- мало — корреляционная матрица не дергается от шока одного дня. Каждый день сдвигает к внешнему произведению лишь примерно на 3%.
- велико — корреляции сильно персистентны. Как только книга сцепляется в стрессовом событии, она остается сцепленной некоторое время, медленно затухая обратно к . Это соответствует реальному опыту крипто-просадок: корреляции не отскакивают обратно в тот момент, когда цена стабилизируется.
- подтверждает возврат к среднему. Процесс корреляции имеет стационарный долгосрочный уровень (), к которому он возвращается, с периодом полураспада примерно дня. Если вы когда-нибудь получите оценку , практически равную 1, процесс корреляции интегрирован — у него нет долгосрочного якоря, что обычно является симптомом структурного разлома внутри вашей выборки, который модель поглощает как бесконечную персистентность.
Почти единичная персистентность и крошечная нагрузка на шок — это канонический отпечаток DCC во всех классах активов, и крипта не исключение. Именно поэтому 30-дневная скользящая корреляция — такая плохая замена: скользящее окно неявно предполагает и , которые вообще не соответствуют этой структуре затухания.
Несколько заметок по реализации, которые экономят реальное время на отладке:
- Инициализация. Старт с
[0.03, 0.94]отражает типичную крипто-оценку: небольшое (корреляции реагируют на шоки, но не резко), большое (корреляции персистентны). Если оптимизатор уходит в , процесс корреляции интегрирован — обычно признак структурного разлома в выборке (смена режима, которую модель с трудом подгоняет как персистентность). - Соглашение о таймингах. Внутри цикла мы оцениваем относительно , а затем обновляем с помощью для следующего шага. Это удерживает функцией информации только до момента — без забегания вперед. Ошибиться в этом сдвиге на единицу — самая частая ошибка DCC, и она незаметно раздувает внутривыборочное качество подгонки.
- Таргетирование корреляции. Мы подставляем как выборочную корреляцию, а не оцениваем ее. Именно это делает оптимизацию двумерной. Цена в том, что использует всю выборку, поэтому при строгой walk-forward-оценке нужно переоценивать ее только на обучающем окне (см. ниже).
Шаг 3: восстановление траекторий корреляции и ковариации
Как только зафиксированы, запускаем рекурсию еще раз, на этот раз сохраняя полную траекторию (и ), чтобы последующие стратегии могли ее использовать.
def dcc_filter(Z, Sigma, a, b):
"""
Run the DCC recursion with fixed (a,b) and return the full paths:
R_path : (T, d, d) conditional correlation matrices
H_path : (T, d, d) conditional covariance matrices (scaled units)
Sigma : (T, d) conditional volatilities aligned with Z.
"""
Z = np.asarray(Z); Sig = np.asarray(Sigma)
T, d = Z.shape
Qbar = np.cov(Z, rowvar=False, bias=True)
dinv = np.diag(1.0 / np.sqrt(np.diag(Qbar)))
Qbar = dinv @ Qbar @ dinv
Q = Qbar.copy()
R_path = np.empty((T, d, d))
H_path = np.empty((T, d, d))
for t in range(T):
q_diag = np.sqrt(np.diag(Q))
R = Q / np.outer(q_diag, q_diag)
R_path[t] = R
Dt = np.diag(Sig[t]) # D_t = diag(sigma_i,t)
H_path[t] = Dt @ R @ Dt # H_t = D_t R_t D_t
z = Z[t]
Q = (1 - a - b) * Qbar + a * np.outer(z, z) + b * Q
return R_path, H_path
R_path, H_path = dcc_filter(Z, Sigma, a_hat, b_hat)
i, j = symbols.index("BTC"), symbols.index("ETH")
rho_btc_eth = pd.Series(R_path[:, i, j], index=Z.index, name="rho_BTC_ETH")
print(rho_btc_eth.describe())
print("min/max correlation:", rho_btc_eth.min().round(3),
rho_btc_eth.max().round(3))
Ряд rho_btc_eth — это результат всего упражнения: вместо одного числа у вас теперь есть дневная корреляция, которую можно построить на графике, применить к ней порог или подать в стратегию. На реальных крипто-данных она обычно варьируется от примерно 0.5 в спокойные периоды до выше 0.9 во время стресса — тот самый разброс, который одна выборочная корреляция усредняет и теряет.
Прогноз на один шаг вперед
Для живой торговли вам нужна на следующий период на основе доступной сейчас информации. Волатильностная сторона берется из одношагового прогноза каждой модели arch; корреляционная сторона — это еще один оборот рекурсии:
def dcc_forecast_next(Z, a, b, fits, symbols):
"""One-step-ahead H_{t+1} using info through the last observation."""
Z = np.asarray(Z); T, d = Z.shape
Qbar = np.cov(Z, rowvar=False, bias=True)
dinv = np.diag(1.0 / np.sqrt(np.diag(Qbar)))
Qbar = dinv @ Qbar @ dinv
Q = Qbar.copy()
for t in range(T):
z = Z[t]
Q = (1 - a - b) * Qbar + a * np.outer(z, z) + b * Q
q_diag = np.sqrt(np.diag(Q))
R_next = Q / np.outer(q_diag, q_diag)
sig_next = np.array([
np.sqrt(fits[s].forecast(horizon=1, reindex=False)
.variance.iloc[-1, 0])
for s in symbols
])
Dt = np.diag(sig_next)
H_next = Dt @ R_next @ Dt
return R_next, H_next, sig_next
R_next, H_next, sig_next = dcc_forecast_next(Z, a_hat, b_hat, fits, symbols)
Помните, что все находится в масштабированных (×100) единицах, потому что мы подгоняли arch на series * 100. Разделите волатильности на 100 (а ковариации на ), чтобы вернуться к единицам исходной доходности, прежде чем подавать данные в стратегию. Удержание масштабирования в порядке утомительно, но это частый источник незаметных ошибок.
Применение 1: динамический хедж-коэффициент для парного трейдинга
Классическая рыночно-нейтральная пара — лонг одного актива, шорт другого с весом бета — живет и умирает вместе с хедж-коэффициентом . Оцените его статичным OLS на обучающем окне — и вы унаследуете ровно ту проблему устаревшей корреляции, о которой вся эта статья: хедж, нейтрализовавший рыночную экспозицию в прошлом квартале, неверен в этом квартале.
DCC дает вам хедж-коэффициент как временной ряд. Хедж минимальной дисперсии для экспозиции ETH с помощью BTC — это условный коэффициент регрессии
Каждый член справа — это вывод DCC. Хедж-коэффициент движется по двум различным причинам, и DCC аккуратно их разделяет: корреляция меняется (активы сцепляются или расцепляются), и соотношение волатильностей меняется (один актив становится относительно более волатильным). Скользящая OLS-бета смазывает оба эффекта с задержкой; DCC их разделяет.
def dynamic_hedge_ratio(R_path, Sigma, base="BTC", target="ETH",
symbols=symbols, index=Z.index):
"""
beta_t to hedge `target` exposure with `base`:
beta_t = rho_t * sigma_target,t / sigma_base,t
(Scaling cancels in the ratio, so scaled units are fine here.)
"""
i = symbols.index(target)
j = symbols.index(base)
rho = R_path[:, i, j]
sig = np.asarray(Sigma)
beta = rho * sig[:, i] / sig[:, j]
return pd.Series(beta, index=index, name=f"beta_{target}_{base}")
beta_t = dynamic_hedge_ratio(R_path, Sigma)
print(beta_t.describe())
spread = (returns["ETH"] - beta_t.shift(1) * returns["BTC"]).dropna()
Подайте spread в любой ваш движок парного трейдинга. Динамический хедж сам по себе не создает преимущества — он делает торгуемый спред по-настоящему рыночно-нейтральным во времени, чтобы ваш сигнал возврата к среднему не был загрязнен дрейфующей направленной экспозицией. Если вы строите парные стратегии, это встраивается напрямую в фреймворки из статей Статистический арбитраж и парный трейдинг в крипте и дистанционный подход к парному трейдингу, заменяя их фиксированный хедж-коэффициент. Сам ряд корреляции также является более чистым входом для сигнала пар на основе корреляции, чем любое скользящее окно — вы получаете сглаженное, согласованное с моделью вместо шумной оценки на окне.
Две предосторожности при использовании вживую. Во-первых, применяйте с лагом — торгуйте на , никогда на текущем , иначе вы подсматриваете в будущее. Во-вторых, хедж-коэффициент, дергающийся каждый день, генерирует оборот и комиссии; на 24/7 крипто-рынке с расходами на фандинг по короткой ноге сверхреактивный хедж может съедать больше, чем корректируемый им дрейф. Сглаживайте (EWMA, или перебалансируйте хедж только когда он выходит за пределы полосы) и разумно сайзите всю позицию — сайзинг позиций на основе шумного сигнала — отдельная дисциплина, разобранная в статье про сайзинг стратегий по критерию Келли.
Применение 2: изменяющаяся во времени дисперсия портфеля
Для портфеля с вектором весов условная дисперсия равна
Со статичной ковариационной матрицей — стандарт Марковица — это число константа, посчитанная один раз и выдаваемая за все еще истинную. Это не так. Риск портфеля дышит вместе с рынком, и он дышит сильнее всего именно тогда, когда корреляции взлетают, потому что при просадке и члены , и члены растут одновременно и перемножаются. Портфель, выглядевший как 40% годовой волатильности в спокойные периоды, может работать на 80%+ в стрессовую неделю, а статичная ковариационная матрица скажет вам, что ничего не изменилось.
def portfolio_vol_path(H_path, weights, index=Z.index, unscale=1e4):
"""
Conditional portfolio volatility sigma_{p,t} = sqrt(w' H_t w).
H_path is in scaled (x100) units, so covariances carry a 100^2
factor: divide by unscale=1e4 to return to raw-return variance.
"""
w = np.asarray(weights)
var_t = np.einsum("i,tij,j->t", w, H_path, w) / unscale
return pd.Series(np.sqrt(var_t), index=index, name="port_vol")
w = np.array([0.4, 0.3, 0.2, 0.1]) # BTC, ETH, SOL, BNB
pv = portfolio_vol_path(H_path, w)
pv_annual = pv * np.sqrt(365)
print(pv_annual.describe())
Эта изменяющаяся во времени — тот честный вход, который нужен распределению активов на основе риска. Оптимизация среднего-дисперсии (Марковиц для крипты) со статичной выборочной ковариацией оптимизирует относительно вымысла; подача ей (или ее краткосрочного прогноза) делает эффективную границу саму по себе изменяющейся во времени и заставляет оптимизатор снижать риск во время растущей корреляции, а не после нее. Подходы риск-паритета и иерархические подходы — конвейер HRP + CVaR — еще более чувствительны к входной ковариации, поскольку все распределение является функцией матрицы риска. И если вы сравниваете аллокаторы напрямую, как в статье сравнение алгоритмов оптимизации портфеля, то то, потребляют ли они статичную или динамическую ковариацию, часто является большим драйвером реализованного риска, чем выбор алгоритма.
Прямое применение — таргетирование волатильности всего портфеля: выбираете целевую годовую волатильность и масштабируете валовую экспозицию на на каждом периоде, чтобы реализованный риск оставался примерно постоянным, а не раздувался в кризисы. Это замыкает круг с частью 4, которая строит и бэктестит именно это правило.
Применение 3: корреляция как сигнал режима
Помимо хеджирования и сайзинга, корреляционная матрица несет макро-сигнал. Самый полезный скаляр, который можно из нее извлечь, — это средняя попарная корреляция:
Когда растет по всей книге, рынок входит в режим risk-off — идиосинкратические истории перестают иметь значение, и все торгуется как одна макро-бета. Это количественный отпечаток фразы "корреляции стремятся к 1 в кризис". Это часто опережает просадки или совпадает с ними, что делает данный показатель применимым индикатором режима, а не запаздывающим постфактум-анализом.
def avg_pairwise_corr(R_path, index=Z.index):
T, d, _ = R_path.shape
iu = np.triu_indices(d, k=1) # upper-triangle off-diagonals
avg = R_path[:, iu[0], iu[1]].mean(axis=1)
return pd.Series(avg, index=index, name="avg_corr")
avg_corr = avg_pairwise_corr(R_path)
roll_q = avg_corr.rolling(365, min_periods=90).quantile(0.80)
risk_off = (avg_corr > roll_q)
Вы можете использовать risk_off как самостоятельный ограничитель (снижать валовую экспозицию, расширять стопы, приостанавливать стратегии возврата к среднему, которые сминаются, когда все движется в одном направлении) или как признак в более формальной модели режимов. Он естественно сочетается со скрытыми марковскими моделями из статьи определение режимов с помощью HMM: средняя корреляция DCC — одна из наиболее информативных наблюдаемых переменных, которые можно передать HMM, потому что она смотрит вперед на системный стресс так, как запаздывающие доходности не могут. Честная оговорка: рост корреляции говорит о том, что диверсификация проваливается, но не о том, в какую сторону пойдет рынок. Это сигнал риска, а не сигнал альфы, и сайзить его нужно соответственно — см. асимметрию убытков и прибылей о том, почему обращение с риск-режимом как с направленной ставкой плохо заканчивается.
Практические соображения
Устойчивость оценки и число активов
DCC масштабируется намного лучше, чем BEKK, но "масштабируется" не значит "бесплатно". Таргетирующая корреляцию матрица — это выборочная корреляция , и выборочные корреляционные матрицы становятся плохо обусловленными, когда приближается к числу наблюдений. При 4 активах и 1000 днях все в порядке. При 60 активах и 400 днях почти вырождена, ее обратная матрица в правдоподобии взрывается, и может из-за численного шума уходить в неположительно определенную область. Смягчающие меры, примерно в порядке частоты необходимости:
- Сжимать к структурированной цели (Ледойт-Вольф, или к единичной матрице / матрице постоянной корреляции) перед запуском рекурсии. Это самое эффективное решение для больших книг.
- Группировать активы в несколько секторов (мейджоры, L1, DeFi, мемы), моделировать внутри и между на уровне секторов, или запускать DCC на факторах главных компонент вместо сырых активов.
- Предпочитать больше данных, а не больше активов. DCC ненасытен к длинной, чистой, синхронной истории — а именно этого нет у самых молодых и интересных токенов.
Реалистично держать прямой DCC на уровне не более нескольких десятков активов. Для большой вселенной активов стандартный обходной путь — DCC на факторных доходностях плюс идиосинкратические остатки.
Таргетирование корреляции — это упрощение с ценой
Таргетирование делает оценку трактуемой, но встраивает полновыборочную безусловную корреляцию в каждую . В строгом бэктесте это утечка заглядывания в будущее: ваша корреляционная матрица дня "знает" среднюю корреляцию всей выборки, включая будущее. Для честной оценки нужно переоценивать только на обучающем окне и держать ее фиксированной вне выборки, либо переносить вперед постепенно. Это та же дисциплина, которую навязывает весь фреймворк walk-forward-оптимизации, и ее легко случайно нарушить удобным np.cov(Z) по всему массиву — как делает наш учебный код выше. Исправьте это, прежде чем доверять хотя бы одному числу P&L.
Периодичность переподгонки и дисциплина против заглядывания в будущее
Не нужно переоптимизировать каждый день — это стабильные параметры. Разумная производственная периодичность:
- Переоценивать и параметры одномерных GARCH еженедельно или ежемесячно.
- Запускать фильтр (обновлять , ) на каждом периоде с замороженными параметрами, чтобы получать свежие и . Фильтрация дешева; подгонка — нет.
- Всегда прогнозировать, никогда не сглаживать. Используйте , построенную на информации до момента , чтобы торговать в момент . Двухпроходная структура (подгонка на окне, затем фильтрация вперед) — это то, что удерживает вас честными.
Разрыв между бэктестом DCC и живой торговлей почти всегда — это утечка заглядывания в будущее: полновыборочная , текущая или переподгонка на данных, включающих сделку, которую вы оцениваете. Дисциплина соответствия бэктеста живым условиям — отдельная тема в статье про паритет бэктеста и живой торговли, и DCC — модель, которая наказывает небрежность здесь сильнее большинства других. Если после чистой walk-forward-оценки динамическая корреляция не дает ничего сверх простой скользящей оценки для вашей стратегии — это реальный и достойный публикации отрицательный результат — подход из статьи честные отрицательные результаты применим напрямую.
Асимметричная DCC (aDCC)
Так же как одномерный эффект левериджа (часть 2) означает, что плохие новости повышают волатильность сильнее, чем хорошие, корреляции растут сильнее после совместных негативных шоков, чем после совместных позитивных. Каппьелло, Энгл и Шеппард (2006) захватывают это с помощью асимметричной DCC, добавляя член, управляемый внешним произведением стандартизованных остатков отрицательной части :
где , а измеряет дополнительный всплеск корреляции от совместных нисходящих движений. Для крипты, где корреляция краха доминирует в риске, член асимметрии обычно значим и стоит одного дополнительного параметра. rmgarch подгоняет aDCC из коробки (model="aDCC"); добавление члена в наш NumPy-оценщик — несложное упражнение.
Сравнение: DCC на фоне альтернатив
Где DCC находится среди способов получить ковариационную матрицу для крипто-книги? Честная сводка:
| Подход | Параметры | Масштабируется до | Изменяющаяся во времени ? | Гарантия PD? | Хвостовая зависимость? |
|---|---|---|---|---|---|
| Выборочная / скользящая ковариация | 0 (длина окна) | любое | грубо (с лагом, шумно) | нет (нужна латка) | нет |
| EWMA (RiskMetrics) | 1 () | любое | да (единичное затухание) | да | нет |
| CCC-GARCH | маргиналов + | десятки | нет (постоянная ) | да | нет |
| DCC-GARCH | маргиналов + 2 | десятки | да | да | нет |
| aDCC-GARCH | маргиналов + 3 | десятки | да, асимметрично | да | частично |
| BEKK | да (богато) | да | нет | ||
| VECH | да (наиболее богато) | болезненно | нет | ||
| GARCH-копула | маргиналов + копула | десятки (виноградные структуры) | статичная копула | да | да |
Несколько выводов из этой таблицы:
- EWMA — дешевый базовый вариант, который должен превзойти любой, кто утверждает, что DCC помогает. По духу это однопараметрический частный случай — единое экспоненциальное затухание, применяемое прямо к ковариации, — и для многих книг его удивительно сложно улучшить вне выборки. Если DCC не превосходит EWMA на чистой walk-forward-оценке, используйте EWMA.
- CCC против DCC — это весь смысл данной статьи: та же факторизация, но CCC замораживает , а DCC позволяет ей двигаться. Два дополнительных параметра () — вся разница, и в крипте они окупаются.
- BEKK/VECH дают более богатую динамику — каждая ковариация может реагировать на каждый прошлый шок, — но цена параметров ограничивает их крошечными книгами. Для чего-либо свыше 4 активов это не реальный вариант.
- GARCH-копула — единственная строка с "да" в столбце хвостовой зависимости. Это та же взаимодополняемость: DCC моделирует динамический центр совместного распределения, копулы моделируют его статичные хвосты. Если ваш вопрос о риске звучит как "что произойдет, если все сломается одновременно", обращайтесь к конвейеру копул; если это "каков мой хедж-коэффициент / дисперсия портфеля прямо сейчас", обращайтесь к DCC.
Практический вариант по умолчанию для систематического крипто-деска: DCC (или aDCC) для хедж-коэффициентов и динамической ковариации в основе, оверлей копулы для хвостового риска и CVaR, и EWMA как базовая проверка на здравомыслие, которая держит вас честными относительно того, окупается ли дополнительная сложность.
Ограничения
- Скалярная динамика. Одно и одно для всех пар — сильное ограничение. BTC-ETH и две малоизвестные альткоины разделяют одну и ту же скорость адаптации. Обобщенная DCC ослабляет это, но возвращает взрыв параметров, от которого DCC был призван избавить.
- Потеря эффективности двухшагового метода. Оценщик квази-правдоподобия состоятелен, но не полностью эффективен, а наивные стандартные ошибки неверны. Используйте коррекцию Энгла-Шеппарда, если вам важен статистический вывод; для генерации сигналов точечных оценок достаточно.
- Гауссовы хвосты по умолчанию. Простое гауссово квази-правдоподобие занижает совместный хвостовой риск. Инновации Стьюдента помогают; для настоящей хвостовой зависимости (вероятности одновременных экстремальных движений) DCC — неправильный инструмент, и правильным является модель копулы. DCC дает вам динамическое тело корреляции; копулы дают вам статичный хвост. Серьезные дески используют оба подхода.
- Корреляция — не причинность и не направление. Растущая предупреждает, что диверсификация проваливается; она ничего не говорит о направлении рынка. Не перегружайте сигнал риска направленными ожиданиями.
- Голод по данным. Все вышеизложенное предполагает длинную, чистую, синхронизированную историю. Самые новые и интересные токены крипты нарушают все три условия.
Резюме
- Статичная корреляция — это ложь в крипте. Корреляции кластеризуются, персистентны и устремляются к 1 при просадках — именно тогда, когда диверсификация должна помогать. Одна выборочная усредняет процесс со сменой режимов в бессмысленное среднее.
- Полный многомерный GARCH (VECH, BEKK) не масштабируется. Число параметров растет как ; оба ограничены горсткой активов на практике.
- DCC (Энгл, 2002) факторизует задачу: , где — из независимых подгонок одномерного GARCH (переиспользуем части 1-2), а — из двухпараметрической рекурсии. Она масштабируется до десятков активов, потому что оптимизируются только .
- Рекурсия , нормированная до , производит валидную положительно определенную корреляционную матрицу на каждом шаге, при , .
archне поддерживает DCC. Подгоните маргиналы с помощьюarch, затем реализуйте здесь ~60-строчный оценщик на NumPy/SciPy, либо используйтеmgarch(Python) илиrmgarch(R, эталонная реализация).- Три конкретных результата: динамический хедж-коэффициент для парного трейдинга; честная изменяющаяся во времени дисперсия портфеля для распределения на основе риска; и средняя попарная корреляция как сигнал режима risk-off.
- Дисциплина — это все. Таргетирование корреляции просачивает полновыборочное среднее, поэтому переоценивайте только на обучающих данных; применяйте любой хедж-коэффициент с лагом; фильтруйте вперед, никогда не сглаживайте. Walk-forward-оценка не подлежит обсуждению.
- aDCC добавляет член нисходящей асимметрии и обычно того стоит в крипте, где доминирует корреляция краха.
- Часть 4 использует эти прогнозы для построения и бэктестирования стратегии с таргетированием волатильности.
Список литературы:
- Engle, R. (2002). Dynamic Conditional Correlation: A Simple Class of Multivariate Generalized Autoregressive Conditional Heteroskedasticity Models. Journal of Business & Economic Statistics, 20(3), 339-350. DOI
- Engle, R. & Sheppard, K. (2001). Theoretical and Empirical Properties of Dynamic Conditional Correlation Multivariate GARCH. NBER Working Paper 8554. DOI
- Bollerslev, T. (1990). Modelling the Coherence in Short-Run Nominal Exchange Rates: A Multivariate Generalized ARCH Model. Review of Economics and Statistics, 72(3), 498-505. DOI
- Cappiello, L., Engle, R., & Sheppard, K. (2006). Asymmetric Dynamics in the Correlations of Global Equity and Bond Returns. Journal of Financial Econometrics, 4(4), 537-572. DOI
- Engle, R. & Kroner, K. (1995). Multivariate Simultaneous Generalized ARCH. Econometric Theory, 11(1), 122-150. DOI
- Bollerslev, T., Engle, R., & Wooldridge, J. (1988). A Capital Asset Pricing Model with Time-Varying Covariances. Journal of Political Economy, 96(1), 116-131. DOI
- Galanos, A. (2022). rmgarch: Multivariate GARCH Models. R package. CRAN.
MarketMaker.cc Team
Количественные исследования и стратегии