← К списку статей
July 10, 2026
5 мин. чтения

GARCH(1,1): прогнозирование волатильности крипторынка

#volatility
#GARCH
#risk
#forecasting
#crypto
#algorithmic-trading

Откройте график дневных доходностей BTC — и вы заметите то, к чему учебники о случайном блуждании вас не готовили: спокойствие и хаос приходят кластерами. Дневное падение на 6% редко бывает одиноким. Оно сидит внутри недели колебаний в 4-8%, а затем рынок выдыхает и дрейфует через месяц сонных сессий по 1%, прежде чем разразится следующая буря. Сами доходности выглядят почти непредсказуемыми — вы не можете надежно сказать, будет завтра рост или падение, — но их величина глубоко предсказуема. Сегодняшняя турбулентность многое говорит о завтрашней.

Почти любой инструмент риск-менеджмента, к которому тянется трейдер, молчаливо предполагает, что это неверно. Black-Scholes оценивает опцион с единственной постоянной σ\sigma. Статичное значение Value-at-Risk умножает одну оценку волатильности на квантиль нормального распределения. Фиксированный стоп-лосс в 3% относится к мертвому боковику во вторник и к часам вокруг публикации FOMC или депеггинга крупной биржи так, будто они несут одинаковый риск. Каждый из этих инструментов ломается одинаково: он сворачивает изменяющуюся во времени величину в константу, а затем удивляется, когда константа начинает двигаться.

Эта статья — первая часть из четырех в серии о моделировании волатильности для крипторынка. Она закладывает фундамент: модель GARCH(1,1), почему она так хорошо подходит для доходностей крипты, как честно оценить ее методом максимального правдоподобия с помощью библиотеки arch, и как превратить прогноз условной дисперсии в две сразу полезные вещи — размер позиции и ширину стопа, которые дышат вместе с рынком. Часть 2 добавляет асимметрию и тяжелые хвосты, часть 3 переходит к многомерному случаю, а часть 4 собирает полный бэктест таргетирования волатильности. Здесь мы намеренно держим применение простым; честная, провалидированная walk-forward стратегия — тема части 4.

Стилизованные факты доходностей крипторынка

Прежде чем моделировать что-либо, стоит точно определить, что мы пытаемся воспроизвести. Эмпирические финансовые доходности — акции, форекс и особенно крипта — разделяют небольшой набор устойчивых статистических закономерностей, документированных на протяжении десятилетий. Их обычно называют стилизованными фактами, и три из них определяют все, что последует дальше.

1. Кластеризация волатильности. За крупными движениями, как правило, следуют крупные движения (любого знака), а за мелкими — мелкие. Мандельброт заметил это на ценах хлопка в 1963 году. Формально, хотя доходности rtr_t почти не коррелированы во времени, квадраты доходностей rt2r_t^2 (прокси для реализованной дисперсии) показывают сильную, медленно затухающую положительную автокорреляцию.

2. Тяжелые хвосты (лептокуртозис). Безусловное распределение доходностей имеет гораздо больше массы в хвостах, чем гауссово. Там, где у нормального распределения эксцесс равен 3, дневные логарифмические доходности BTC регулярно оказываются выше 8-10, а более высокочастотные доходности крипты могут быть еще хуже. Дни с отклонением в шесть сигм, которые по нормальной модели должны происходить примерно раз в миллион лет, случаются по несколько раз за десятилетие.

3. Отсутствие линейной автокорреляции в доходностях, сильная автокорреляция в квадратах доходностей. Это тот отпечаток, который отличает подлинный процесс волатильности от тривиального тренда. Если регрессировать rtr_t на его собственные лаги, вы не получите ничего пригодного для использования. Если регрессировать rt2r_t^2 на его лаги, вы найдете четкий, устойчивый сигнал. Именно эту структуру должна улавливать модель дисперсии — и именно ее выбрасывает модель с постоянной σ\sigma.

Все три факта можно увидеть в нескольких строках кода. Здесь не требуется особый источник данных; в продакшене используйте ccxt, но для воспроизводимого фрагмента подойдет и yfinance.

import numpy as np
import pandas as pd
import yfinance as yf
from statsmodels.graphics.tsaplots import plot_acf
from statsmodels.stats.diagnostic import acorr_ljungbox
from scipy import stats

px = yf.download("BTC-USD", start="2021-01-01", end="2025-12-31")["Close"]
ret = np.log(px / px.shift(1)).dropna()          # log returns
ret = ret.rename("btc")

print(f"Observations:     {len(ret)}")
print(f"Ann. volatility:  {ret.std() * np.sqrt(365):.2%}")
print(f"Skewness:         {stats.skew(ret):.2f}")
print(f"Excess kurtosis:  {stats.kurtosis(ret):.2f}")   # 0 == Gaussian

lb_ret  = acorr_ljungbox(ret,        lags=[10], return_df=True)
lb_ret2 = acorr_ljungbox(ret ** 2,   lags=[10], return_df=True)
print("\nLjung-Box p-value, returns   (lag 10):", float(lb_ret["lb_pvalue"].iloc[0]))
print("Ljung-Box p-value, squared   (lag 10):", float(lb_ret2["lb_pvalue"].iloc[0]))

Типичная картина (иллюстративная — у вас окно будет другим): избыточный эксцесс значительно выше 3, p-значение теста Льюнга-Бокса на сырых доходностях, которое не отвергает гипотезу "нет автокорреляции", и p-значение на квадратах доходностей, которое практически равно нулю. Именно этот контраст — вся суть игры. На дневном горизонте нет ничего, что можно было бы торговать в знаке доходностей, но в их дисперсии присутствует значительная структура, и эта структура прогнозируема.

Замечание о круглосуточной природе крипты. В отличие от акций, здесь нет ночного гэпа и выходного закрытия, поэтому "день" — это чистый 24-часовой бар, а коэффициент аннуализации — 365\sqrt{365}, а не 252\sqrt{252}. Кластеризация волатильности также сохраняется на внутридневных масштабах, что важно, если вы запускаете GARCH на часовых барах — переключения ставки финансирования и каскады ликвидаций впрыскивают резкие, кластеризованные всплески дисперсии, которые дневная модель сглаживает.

От ARCH к GARCH

Теперь проблема поставлена четко: смоделировать дисперсию, которая не постоянна, а зависит от недавнего прошлого. Первой моделью, которая сделала это правильно, стал ARCH Энгла (Autoregressive Conditional Heteroskedasticity, 1982), за которую он получил Нобелевскую премию в 2003 году.

Запишем доходность как условное среднее плюс шок:

rt=μt+εt,εt=σtzt,zti.i.d. (0,1)r_t = \mu_t + \varepsilon_t, \qquad \varepsilon_t = \sigma_t z_t, \qquad z_t \sim \text{i.i.d. } (0, 1)

Здесь σt2\sigma_t^2 — это условная дисперсия — дисперсия rtr_t при заданной всей информации, известной до момента t1t-1, — а ztz_t — стандартизированная инновация (стандартная нормальная в простейшем случае). Слово "условная" делает всю работу: безусловно дисперсия может быть постоянной, но при условии на вчерашний день она движется.

ARCH(qq) Энгла делает сегодняшнюю дисперсию взвешенной суммой последних qq квадратов шоков:

σt2=ω+i=1qαiεti2\sigma_t^2 = \omega + \sum_{i=1}^{q} \alpha_i \, \varepsilon_{t-i}^2

где ω>0\omega > 0 и αi0\alpha_i \ge 0, чтобы дисперсия оставалась положительной. Это напрямую улавливает кластеризацию: крупный шок εt12\varepsilon_{t-1}^2 повышает σt2\sigma_t^2, что повышает вероятность следующего крупного шока, что удерживает дисперсию на повышенном уровне. Проблема — в эмпирическом затухании. Персистентность волатильности на реальных рынках растягивается на много лагов, поэтому для ее подгонки модели ARCH требуется большое qq — часто 8, 10 или больше, — а это означает оценку длинного, нестабильного вектора αi\alpha_i, склонного к переобучению.

Идея Боллерслева в 1986 году состояла в том, чтобы добавить член, поглощающий всю эту персистентность одним параметром. Рекурсия GARCH(1,1) — Generalized ARCH — выглядит так:

σt2=ω+αεt12+βσt12\sigma_t^2 = \omega + \alpha \, \varepsilon_{t-1}^2 + \beta \, \sigma_{t-1}^2

Три параметра, три ясные интерпретации:

  • ω>0\omega > 0базовый уровень, или пол. Константа, закрепляющая долгосрочный уровень дисперсии. Дисперсия никогда не опускается ниже того, что поддерживает ω\omega.
  • α0\alpha \ge 0реакция на новости. Насколько бурно дисперсия реагирует на вчерашний сюрприз εt12\varepsilon_{t-1}^2. Большое α\alpha означает, что условная дисперсия дергается и чувствительна к шокам.
  • β0\beta \ge 0персистентность, или память. Сколько от вчерашней дисперсии переносится в сегодняшний день. Большое β\beta означает, что волатильность плавная и медленно затухает — спокойствие остается спокойствием, бури остаются бурями.

Изящество кроется в рекурсии. Поскольку сама σt12\sigma_{t-1}^2 содержала член βσt22\beta \sigma_{t-2}^2, разворачивание назад показывает, что GARCH(1,1) — это ARCH(\infty) с геометрически затухающими весами αβk\alpha \beta^{k} на прошлые квадраты шоков:

σt2=ω1β+αk=0βkεt1k2\sigma_t^2 = \frac{\omega}{1-\beta} + \alpha \sum_{k=0}^{\infty} \beta^{k}\, \varepsilon_{t-1-k}^2

Так что единственное β\beta покупает вам бесконечную, экспоненциально взвешенную память о прошлых шоках. Именно поэтому простой GARCH(1,1) — три параметра — регулярно превосходит модели ARCH с десятью, и именно поэтому он стал рабочей лошадкой прикладного моделирования волатильности. Фактически, это близкий родственник оценщика дисперсии RiskMetrics EWMA, который является частным случаем ω=0\omega = 0, α+β=1\alpha + \beta = 1 при фиксированном β=0.94\beta = 0.94. GARCH обобщает его, позволяя данным выбирать α\alpha, β\beta и настоящий уровень возврата к среднему.

Свойства: стационарность, долгосрочная дисперсия и период полураспада

У рекурсии GARCH(1,1) есть несколько свойств, которые стоит вывести, потому что именно они позволяют рассуждать о модели, а не просто слепо ее подгонять.

Безусловная (долгосрочная) дисперсия. Предположим, что процесс ковариационно-стационарен, так что безусловная дисперсия σˉ2=E[εt2]=E[σt2]\bar{\sigma}^2 = \mathbb{E}[\varepsilon_t^2] = \mathbb{E}[\sigma_t^2] существует и постоянна во времени. Возьмем ожидания обеих сторон рекурсии. Поскольку E[εt12]=E[σt12]=σˉ2\mathbb{E}[\varepsilon_{t-1}^2] = \mathbb{E}[\sigma_{t-1}^2] = \bar{\sigma}^2:

σˉ2=ω+ασˉ2+βσˉ2        σˉ2=ω1αβ\bar{\sigma}^2 = \omega + \alpha\, \bar{\sigma}^2 + \beta\, \bar{\sigma}^2 \;\;\Longrightarrow\;\; \bar{\sigma}^2 = \frac{\omega}{1 - \alpha - \beta}

Это тот уровень, к которому возвращается волатильность. Он существует — и только положителен — когда α+β<1\alpha + \beta < 1.

Условие стационарности. То же самое неравенство,

α+β<1,\alpha + \beta < 1,

является условием ковариационной стационарности для GARCH(1,1). Величина α+β\alpha + \beta — это персистентность процесса дисперсии: это коэффициент AR(1), управляющий тем, как шок дисперсии затухает обратно к σˉ2\bar{\sigma}^2. Если α+β1\alpha + \beta \ge 1, безусловная дисперсия бесконечна (или не определена), и шоки никогда полностью не затухают.

Возврат к среднему можно увидеть явно. Определим отклонение дисперсии σt2σˉ2\sigma_t^2 - \bar{\sigma}^2. Немного алгебры над рекурсией (подставляя ω=σˉ2(1αβ)\omega = \bar{\sigma}^2(1 - \alpha - \beta)) дает в математическом ожидании:

Et[σt+k2]σˉ2=(α+β)k(σt+12σˉ2)\mathbb{E}_t[\sigma_{t+k}^2] - \bar{\sigma}^2 = (\alpha + \beta)^{k}\,\bigl(\sigma_{t+1}^2 - \bar{\sigma}^2\bigr)

Разрыв между текущей дисперсией и ее долгосрочным уровнем сжимается на коэффициент (α+β)(\alpha + \beta) на каждом шаге. Это в точности тот многошаговый прогноз, который мы используем далее.

Период полураспада волатильности. Сколько времени требуется, чтобы шок дисперсии затух наполовину обратно к норме? Положим (α+β)h=1/2(\alpha+\beta)^{h} = 1/2 и решим:

h1/2=ln0.5ln(α+β)h_{1/2} = \frac{\ln 0.5}{\ln(\alpha + \beta)}

Для α+β=0.95\alpha + \beta = 0.95 период полураспада составляет около 13.5 дня; для 0.980.98 — около 34 дней; для 0.990.99 — около 69 дней. Это единственное число часто более интуитивно понятно, чем сырые параметры — оно говорит вам, в единицах ваших баров, насколько "липкая" волатильность.

Проблема близости к IGARCH в крипте. Вот специфическая для крипты особенность. Когда вы подгоняете GARCH(1,1) к доходностям BTC или ETH, вы почти всегда обнаруживаете, что α+β\alpha + \beta очень близко к 1 — значения 0.98, 0.99, иногда 0.995 — обычное дело. Это режим, близкий к IGARCH (Integrated GARCH). У него есть реальные последствия:

  • Период полураспада становится огромным (недели-месяцы), поэтому модель считает волатильность очень персистентной и едва возвращающейся к среднему.
  • Оценка σˉ2=ω/(1αβ)\bar{\sigma}^2 = \omega/(1-\alpha-\beta) становится чрезвычайно чувствительной: небольшое изменение α+β\alpha+\beta с 0.99 до 0.995 удваивает предполагаемую долгосрочную дисперсию. Никогда не доверяйте точечной оценке долгосрочной волатильности в этом режиме без доверительного интервала.
  • Многошаговые прогнозы возвращаются к среднему настолько медленно, что для практических горизонтов до нескольких недель GARCH ведет себя почти как случайное блуждание в дисперсии (что и предполагает EWMA).

Является ли близость к интегрированности подлинной или артефактом структурных сдвигов (постоянного сдвига уровня волатильности, который модель считывает как один длинный персистентный эпизод) — реальный предмет спора. Это еще одна причина переоценивать модель на скользящих окнах, а не подгонять один раз на всей истории — к этому мы вернемся в разделе о подводных камнях. Структура режимов конкретно лучше обрабатывается явной переключающейся моделью — см. обнаружение режимов с помощью скрытых марковских моделей, которая дополняет GARCH, а не заменяет его.

Оценка методом максимального правдоподобия

Параметры GARCH оцениваются методом максимального правдоподобия. Логика прямая: при заданных θ=(μ,ω,α,β)\theta = (\mu, \omega, \alpha, \beta) рекурсия дает полную траекторию условных дисперсий σt2(θ)\sigma_t^2(\theta), и при предполагаемом распределении инноваций ztz_t мы можем записать, насколько вероятны наблюдаемые доходности. Затем мы выбираем θ\theta, максимизирующее это правдоподобие.

Предположим гауссовы инновации ztN(0,1)z_t \sim \mathcal{N}(0,1), так что rtFt1N(μ,σt2)r_t \mid \mathcal{F}_{t-1} \sim \mathcal{N}(\mu, \sigma_t^2). Условная плотность одного наблюдения:

f(rtFt1)=12πσt2exp ⁣((rtμ)22σt2).f(r_t \mid \mathcal{F}_{t-1}) = \frac{1}{\sqrt{2\pi\sigma_t^2}}\exp\!\left(-\frac{(r_t - \mu)^2}{2\sigma_t^2}\right).

Поскольку модель записана условно, совместное правдоподобие раскладывается в произведение одношаговых плотностей, а логарифмическое правдоподобие — это простая сумма:

(θ)=12t=1T[ln(2π)+lnσt2(θ)+(rtμ)2σt2(θ)].\ell(\theta) = -\frac{1}{2}\sum_{t=1}^{T}\left[\ln(2\pi) + \ln \sigma_t^2(\theta) + \frac{(r_t - \mu)^2}{\sigma_t^2(\theta)}\right].

Стоит заметить два структурных факта. Во-первых, σt2\sigma_t^2 появляется и как штраф (lnσt2\ln \sigma_t^2 — модель штрафуется за заявление высокой дисперсии), и в стандартизированном остатке ((rtμ)2/σt2(r_t-\mu)^2/\sigma_t^2 — модель штрафуется за то, что оказалась удивлена). Оптимум балансирует эти два фактора, что и заставляет дисперсию отслеживать реальность. Во-вторых, рекурсии нужен начальный посев σ12\sigma_1^2; обычный выбор — выборочная дисперсия доходностей, и при нескольких тысячах наблюдений начальное значение почти не имеет значения.

Замкнутой формы для максимизатора не существует, поэтому оптимизация выполняется численно (arch использует квазиньютоновский метод с аналитическими или численными градиентами). Поверхность правдоподобия обычно ведет себя хорошо для GARCH(1,1), но на практике кусаются две вещи: ограничения положительности (ω,α,β0\omega,\alpha,\beta \ge 0) и поведение вблизи границы, когда α+β1\alpha+\beta \to 1, где оптимизатор может ползти медленно. Обе проблемы решаются хорошей библиотекой за вас — и ею стоит пользоваться. Написание GARCH MLE вручную — неплохое учебное упражнение, но плохой выбор для продакшена.

Библиотека arch

Пакет arch авторства Kevin Sheppard — стандартный инструмент в Python. Вся подгонка занимает четыре строки.

from arch import arch_model

r = ret * 100.0

model  = arch_model(r, mean="Constant", vol="Garch", p=1, q=1, dist="normal")
res    = model.fit(disp="off")
print(res.summary())

Пара слов об именах аргументов, потому что они — частый источник путаницы. В arch p — это число лагов дисперсии (β\beta-члены, порядок GARCH), а q — число лагов квадратов остатков (α\alpha-члены, порядок ARCH). Так что p=1, q=1 — это как раз выведенный нами GARCH(1,1). (Оригинальная нотация Боллерслева записывает его как GARCH(p,qp,q), где pp — порядок ARCH — эти две конвенции переставлены местами. Доверяйте документации самой библиотеки, а не своей памяти.)

Читая summary, таблица коэффициентов выглядит примерно так (иллюстративные значения для дневных доходностей BTC, не реальный эксперимент):

                     Volatility Model
==========================================================
                 coef    std err      t      P>|t|
----------------------------------------------------------
omega          0.4821     0.201    2.40    0.016
alpha[1]       0.0912     0.021    4.34    0.000
beta[1]        0.8994     0.024   37.5     0.000
==========================================================

Как это читать:

  • alpha[1] + beta[1] = 0.0912 + 0.8994 = 0.9906. Персистентность чуть меньше 1 — режим, близкий к IGARCH, как и предупреждали. Период полураспада ln(0.5)/ln(0.9906)73\approx \ln(0.5)/\ln(0.9906) \approx 73 дня.
  • omega = 0.4821, поэтому долгосрочная дисперсия равна 0.4821/(10.9906)=51.30.4821 / (1 - 0.9906) = 51.3 в единицах процент-в-квадрате, то есть долгосрочная дневная волатильность 51.37.2%\sqrt{51.3} \approx 7.2\%, или примерно 7.2%×365138%7.2\%\times\sqrt{365}\approx 138\% в годовом выражении. Это правдоподобное число для BTC.
  • И alpha, и beta статистически значимы. То, что alpha мала относительно beta, типично: дисперсия крипты состоит в основном из персистентности (памяти), с умеренной, но реальной реакцией на свежие шоки.

Ловушка масштабирования ×100

Это самый распространенный способ получить бессмыслицу из arch, поэтому он заслуживает отдельного подраздела. Оптимизатор работает лучше всего, когда числа, которые он видит, имеют порядок O(1)O(1)-O(100)O(100). Дневные логарифмические доходности имеют порядок O(0.01)O(0.01), поэтому их квадраты — O(0.0001)O(0.0001), а ω\omega оказывается около 10610^{-6} — в диапазоне, где численные градиенты теряют точность, и подгонка может незаметно не сойтись или вернуть мусорные стандартные ошибки.

Решение — подгонять на доходностях, масштабированных на 100 (то есть в процентах), как показано выше. arch даже выдаст предупреждение DataScaleWarning, если вы об этом забудете. Все, что вы читаете из модели, тогда находится в единицах процентов или процент-в-квадрате, и вы должны согласованно демасштабировать:

sigma_pct     = np.sqrt(res.forecast(horizon=1).variance.iloc[-1, 0])
sigma_decimal = sigma_pct / 100.0
print(f"1-day-ahead conditional vol: {sigma_decimal:.2%}")

Смешивание масштабированных и немасштабированных величин — например, подача процентной волатильности в формулу размера позиции, которая ожидает десятичные дроби, — приводит к ошибкам ровно в 100 раз, которые легко пропустить, потому что код прекрасно выполняется. Выберите конвенцию (я держу все в десятичных дробях за пределами подгонки и масштабирую только на границе с arch) и никогда ее не нарушайте.

Прогнозирование условной дисперсии

Подогнанная модель полезна только если она прогнозирует. GARCH дает чистые, аналитические прогнозы на любой горизонт.

На один шаг вперед. В момент TT (конец выборки) мы знаем εT\varepsilon_T и σT2\sigma_T^2, поэтому следующая дисперсия детерминирована:

σT+12=ω+αεT2+βσT2.\sigma_{T+1}^2 = \omega + \alpha\,\varepsilon_T^2 + \beta\,\sigma_T^2.

Никакого ожидания не требуется — все справа наблюдаемо.

На несколько шагов вперед. Для h2h \ge 2 мы еще не знаем промежуточных шоков, поэтому берем условные ожидания. Используя ET[εT+k2]=ET[σT+k2]\mathbb{E}_T[\varepsilon_{T+k}^2] = \mathbb{E}_T[\sigma_{T+k}^2] (потому что E[z2]=1\mathbb{E}[z^2]=1), рекурсия сворачивается в простой AR(1) для прогнозируемой дисперсии:

ET[σT+h2]=ω+(α+β)ET[σT+h12].\mathbb{E}_T[\sigma_{T+h}^2] = \omega + (\alpha + \beta)\,\mathbb{E}_T[\sigma_{T+h-1}^2].

Итерируя это от одношагового прогноза, получаем замкнутую форму, которая является результатом возврата к среднему, выведенным ранее, но записанным явно:

ET[σT+h2]=σˉ2+(α+β)h1(σT+12σˉ2),σˉ2=ω1αβ.\mathbb{E}_T[\sigma_{T+h}^2] = \bar{\sigma}^2 + (\alpha+\beta)^{\,h-1}\bigl(\sigma_{T+1}^2 - \bar{\sigma}^2\bigr), \qquad \bar{\sigma}^2 = \frac{\omega}{1-\alpha-\beta}.

Прочитайте это внимательно, потому что это геометрия любого прогноза GARCH. Срочная структура дисперсии начинается с сегодняшней условной дисперсии σT+12\sigma_{T+1}^2 и затухает геометрически к долгосрочному уровню σˉ2\bar{\sigma}^2. Если сегодня спокойнее среднего, кривая прогноза растет к σˉ2\bar\sigma^2; если сегодня кризис, она падает к нему. Скорость этого затухания полностью задается (α+β)(\alpha+\beta) — и в режиме, близком к IGARCH в крипте, где α+β0.99\alpha+\beta \approx 0.99, затухание настолько медленное, что для горизонтов до пары недель прогноз едва сдвигается от сегодняшнего уровня. Это стоит запомнить: для коротких периодов удержания позиции прогноз GARCH в крипте — по сути "завтра будет как сегодня, только очень медленно возвращаясь к среднему".

Агрегация до горизонта удержания. Трейдеров редко волнует дисперсия одного будущего дня. Если вы держите позицию HH дней, а доходности условно некоррелированы (стилизованный факт с самого начала), дисперсия кумулятивной HH-дневной доходности — это сумма одношаговых прогнозов дисперсии:

σT2(H)=h=1HET[σT+h2],σT(H)=σT2(H).\sigma_{T}^{2}(H) = \sum_{h=1}^{H} \mathbb{E}_T[\sigma_{T+h}^2], \qquad \sigma_T(H) = \sqrt{\sigma_T^2(H)}.

Именно под это число вы реально размеряете позицию — волатильность P&L за период удержания. Заметьте, что это категорически не наивное масштабирование HσT+1\sqrt{H}\,\sigma_{T+1}, которое верно только если дисперсия постоянна. Когда сегодняшняя дисперсия выше σˉ2\bar\sigma^2, возвращающийся к среднему прогноз делает истинную HH-дневную волатильность ниже, чем по правилу квадратного корня; когда сегодня спокойно — выше. Правильное понимание этого — разница между стопом, который учитывает срочную структуру, и тем, который ее не учитывает.

В коде:

H = 10
fc = res.forecast(horizon=H, reindex=False)

var_path_pct2 = fc.variance.iloc[-1].values        # [E_T sigma^2_{T+1}, ..., T+H]
var_path      = var_path_pct2 / (100.0 ** 2)       # back to decimal variance

daily_vol   = np.sqrt(var_path)
print("Forecast daily vol path:", np.round(daily_vol * 100, 2), "%")

H_day_var = var_path.sum()
H_day_vol = np.sqrt(H_day_var)
print(f"{H}-day holding-period vol: {H_day_vol:.2%}")

naive = np.sqrt(var_path[0] * H)
print(f"Naive sqrt(H) * sigma_1:   {naive:.2%}")

Для более длинных горизонтов GARCH также поддерживает прогнозы через симуляцию (method="simulation"), которые продвигают распределение инноваций вперед и дают полную плотность прогноза, а не только ее дисперсию — полезно, когда инновации негауссовы, как это будет, когда мы перейдем к распределениям Student-t и skewed в части 2. Для приведенных выше линейных по дисперсии величин аналитический путь точен и бесплатен.

Диагностика: сработала ли модель на самом деле?

Подгонка модели — не то же самое, что ее валидация. Весь смысл GARCH — поглотить условную гетероскедастичность (кластеризацию волатильности), так чтобы то, что осталось, было (близко к) i.i.d. Правильная проверка поэтому — посмотреть на стандартизированные остатки

z^t=rtμ^σ^t\hat{z}_t = \frac{r_t - \hat\mu}{\hat\sigma_t}

и спросить: исчезла ли кластеризация? Если модель уловила динамику дисперсии, у z^t\hat z_t должна быть единичная дисперсия, и, что критично, их квадраты z^t2\hat z_t^2 не должны показывать оставшейся автокорреляции. Проведем три теста.

1. Тест Льюнга-Бокса на стандартизированных остатках. Проверяет, что в уровне z^t\hat z_t не осталось линейной автокорреляции (это на самом деле тест модели среднего, а не модели дисперсии). Не должен отвергаться.

2. Тест Льюнга-Бокса на квадратах стандартизированных остатков. Это важный тест. Если z^t2\hat z_t^2 все еще имеет значимую автокорреляцию, модель дисперсии не смогла устранить кластеризацию — есть структура, которую GARCH(1,1) не уловил, и вам может понадобиться более высокий порядок, асимметричный вариант или другое распределение инноваций. Не должен отвергаться.

3. Тест ARCH-LM (тест множителей Лагранжа Энгла). Регрессирует z^t2\hat z_t^2 на его собственные лаги и проверяет совместную значимость. По сути это формальная версия теста 2, напрямую спрашивающая "остался ли эффект ARCH?" Незначимый результат подтверждает, что условная гетероскедастичность была смоделирована.

from statsmodels.stats.diagnostic import acorr_ljungbox
from arch.unitroot.cointegration import engle_granger  # (unrelated; shown for import clarity)

z  = res.std_resid.dropna()          # standardized residuals
z2 = z ** 2

lb_z  = acorr_ljungbox(z,  lags=[10, 20], return_df=True)
lb_z2 = acorr_ljungbox(z2, lags=[10, 20], return_df=True)
print("Ljung-Box on standardized residuals:\n", lb_z, "\n")
print("Ljung-Box on SQUARED standardized residuals:\n", lb_z2, "\n")

lm = res.arch_lm_test(lags=10, standardized=True)
print(lm)

print(f"\nStd-resid excess kurtosis: {stats.kurtosis(z):.2f}")

Как выглядит хороший результат: p-значения теста Льюнга-Бокса на z^t2\hat z_t^2 подскакивают от почти нуля (на сырых квадратах доходностей) до комфортно выше 0.05, а тест ARCH-LM не отвергается. Это ваше доказательство, что модель справилась со своей работой на втором моменте.

Как выглядит несовершенный результат — и чего вам стоит ожидать от обычного гауссова GARCH(1,1) на крипте, — так это того, что тесты на кластеризацию проходят, но эксцесс стандартизированных остатков все еще повышен (скажем, 4-6 вместо 0). GARCH устраняет кластеризацию, но остается единое распределение с тяжелыми хвостами, потому что гауссовы инновации не могут воспроизвести хвосты. Эта остаточная тяжелохвостость — не баг, который нужно чинить здесь; это мотивация для части 2, асимметричный GARCH и эффект левериджа в крипте, где инновации Student-t и skewed-t, а также асимметричный член GJR/EGARCH решают именно эту задачу.

Применение: масштабирование позиций и стопов по волатильности

Теперь у нас есть прогноз завтрашней (и следующих HH дней) волатильности. Что с ним делать? Два простейших, самых ценных применения — размер позиции и размещение стопа. Здесь мы намеренно держим оба базовыми — полная стратегия таргетирования волатильности со всей практической машинерией — часть 4.

Размер позиции, таргетированный по волатильности

Идея — держать позицию, чей вклад в риск примерно постоянен во времени, а не позицию с постоянным номиналом. Если вы всегда используете одинаковый долларовый размер, ваш риск раздувается в режимах высокой волатильности и съеживается в спокойные периоды — противоположность желаемому. Таргетирование волатильности переворачивает это: стремитесь к фиксированной целевой волатильности P&L и позвольте прогнозу диктовать размер.

Для целевой годовой волатильности σtarget\sigma_{\text{target}} (скажем, 20%) и прогнозной годовой волатильности σ^t\hat\sigma_t вес позиции равен

wt=σtargetσ^t.w_t = \frac{\sigma_{\text{target}}}{\hat{\sigma}_t}.

Когда прогнозная волатильность высока, вы уменьшаете масштаб; когда она низка — увеличиваете. Это весь механизм. Поскольку σ^t\hat\sigma_t — это прогноз, известный в момент tt до того, как реализуется доходность в момент t+1t+1, здесь нет заглядывания в будущее — при условии дисциплинированного отношения к тайминг у (подробнее об этом в разделе о подводных камнях).

def vol_target_weight(sigma_forecast_annual, sigma_target_annual=0.20,
                      w_max=3.0):
    """Volatility-scaled position weight. Inputs/outputs in decimals.
    w_max caps leverage so a tiny forecast vol can't demand insane size."""
    w = sigma_target_annual / sigma_forecast_annual
    return float(np.clip(w, 0.0, w_max))

sigma_1d   = np.sqrt(res.forecast(horizon=1).variance.iloc[-1, 0]) / 100.0
sigma_ann  = sigma_1d * np.sqrt(365)
w          = vol_target_weight(sigma_ann, sigma_target_annual=0.20)
print(f"Forecast annual vol: {sigma_ann:.1%}  ->  position weight: {w:.2f}x")

Это близкий родственник настоящих правил распределения капитала. Таргетирование волатильности отвечает на вопрос "насколько риск должен масштабироваться с волатильностью", тогда как критерий Келли отвечает на вопрос "насколько риск должен масштабироваться с преимуществом" — и эти два фактора перемножаются в полном стеке размерения: размер \propto преимущество / дисперсия. Заметьте, что член дисперсии в формуле Келли — это в точности тот прогноз GARCH, который вы только что вычислили, поэтому живая модель волатильности существенно улучшает размерение по Келли по сравнению со статичной исторической оценкой. Если ваша оценка преимущества сама несет количественную неопределенность, конформное предсказание дает свободный от распределения способ расширить или сжать размер под нее, и он хорошо сочетается с таргетированием волатильности.

Ограничение w_max не является опциональным. В режиме, близком к IGARCH, спокойный период может опустить прогнозную волатильность довольно низко, и σtarget/σ^t\sigma_{\text{target}}/\hat\sigma_t потребует плеча, которое прекрасно выглядит на бумаге и разорительно, когда спокойствие заканчивается — а согласно кластеризации волатильности, оно рано или поздно заканчивается, часто резко. Ограничение плеча — это грубое, но эффективное признание того, что ваш прогноз — условное среднее, а не гарантия, и что выигрыш от ошибки асимметричен. Эта асимметрия — взорвавшийся счет не восстанавливается симметричным выигрышем — это в точности та же асимметрия убытка и прибыли, которая должна делать вас систематически более консервативным, чем предполагает правило, основанное только на дисперсии.

Стопы, масштабированные по волатильности

Фиксированный процентный стоп страдает той же болезнью, что и фиксированный размер позиции: стоп в 3% — это спусковой крючок на волоске в спокойном рынке и статистическая погрешность в бурном. Он выбивает вас из хороших позиций обычным шумом в режимах высокой волатильности и отдает слишком много во время переходов. Решение — задавать расстояние стопа в единицах прогнозной волатильности.

расстояние стопаt=kσ^t(H)\text{расстояние стопа}_t = k \cdot \hat\sigma_t^{(H)}

где σ^t(H)\hat\sigma_t^{(H)} — прогнозная волатильность за ваш ожидаемый горизонт удержания HH (агрегированная величина из раздела прогнозирования), а kk — множитель, обычно от 1.5 до 3, выбранный так, чтобы стоп находился вне обычных колебаний, но внутри подлинного неблагоприятного движения.

def vol_scaled_stop(entry_price, side, sigma_H, k=2.0):
    """
    entry_price : fill price
    side        : +1 long, -1 short
    sigma_H     : forecast volatility over the holding horizon (decimal)
    k           : stop width in vol units
    Returns the stop price.
    """
    stop_frac = k * sigma_H
    return entry_price * (1.0 - side * stop_frac)

var_path = res.forecast(horizon=10, reindex=False).variance.iloc[-1].values / (100.0 ** 2)
sigma_H  = np.sqrt(var_path.sum())

entry = float(px.iloc[-1])
stop  = vol_scaled_stop(entry, side=+1, sigma_H=sigma_H, k=2.0)
print(f"Entry {entry:,.0f}  |  10-day vol {sigma_H:.2%}  |  2-sigma stop {stop:,.0f}")

Поскольку σ^t(H)\hat\sigma_t^{(H)} использует возвращающийся к среднему прогноз срочной структуры, а не плоское историческое число, стоп автоматически расширяется, входя в турбулентные режимы, и сужается, когда волатильность спадает, — срочная структура сама подстраивается за вас. Это тот же прогноз, что питает и размер, и стоп, и это особенность, а не совпадение: в режиме высокой волатильности вы одновременно держите меньше и даете позиции больше пространства, и эти два эффекта складываются в существенно более низкий хвостовой риск. Размер и стопы — это две проекции одного взгляда на волатильность, а не два независимых рычага.

Это все, до чего мы доводим применение в части 1. Реальной стратегии нужно справляться с транзакционными издержками от постоянного ребалансирования, таймингом между вычислением прогноза и размещением сделки, контролем оборота и, прежде всего, честной оценкой вне выборки. Все это — часть 4: стратегия таргетирования волатильности на GARCH, где мы строим и тестируем всю систему методом walk-forward.

Подводные камни

GARCH легко подогнать и легко себя обмануть. Режимы отказа стабильны.

Масштабирование доходностей. Уже разобрано выше, но это баг номер один, поэтому стоит повторить: подгоняйте arch на доходностях × 100 и демасштабируйте каждый выход (дисперсию на 1002100^2, волатильность на 100100). Тихая ошибка в 100 раз здесь отравляет все последующие расчеты размера и стопа.

Заглядывание в будущее при подгонке. Тонкий убийца. Если вы подгоняете модель на всей истории, а затем вычисляете "прогнозы" по этой же истории, каждый прогноз тайно видел будущее — параметры были оценены с использованием данных, наступивших после даты прогноза. Внутривыборочная подгонка будет выглядеть прекрасно, а живая производительность не будет иметь с ней ничего общего. Каждый прогноз в бэктесте должен исходить из модели, подогнанной только на данных, доступных в этот момент: переподгоняйте на расширяющемся или скользящем окне, прогнозируйте на один шаг, сдвигайтесь вперед. Это неотъемлемое требование, и это целиком тема walk-forward оптимизации. Разрыв между внутривыборочным GARCH и правильным walk-forward GARCH — это разрыв между демонстрацией и системой, которая переживет контакт с живыми рынками — см. также паритет бэктеста и живой торговли.

Тайминг прогноза. Связано, но отдельно. Прогноз на день t+1t+1 должен вычисляться из информации, доступной на закрытии дня tt (или когда бы ни закрывался ваш бар), а позиция должна быть исполнима по цене, которую вы действительно могли получить. Вычисление прогноза с использованием закрытия дня t+1t+1 и последующая "торговля" по открытию дня t+1t+1 — это заглядывание в будущее, которое тихо завышает каждый результат.

Переусложнение высокими порядками. GARCH(1,1) почти всегда достаточно. Соблазн подогнать GARCH(2,2) или GARCH(3,1), потому что это слегка поднимает внутривыборочное логарифмическое правдоподобие, обычно означает подгонку под шум; дополнительные параметры редко улучшают внесвыборочные прогнозы и часто делают оптимизатор нестабильным вблизи границы. Предпочитайте экономную модель, и если вам нужно сравнить порядки, сравнивайте их по внесвыборочным потерям прогноза на walk-forward разбиении, а не по внутривыборочному AIC. Когда диагностика остатков все еще показывает проблему, решение обычно — лучшее распределение инноваций или член асимметрии (часть 2), а не более высокий порядок.

Структурные сдвиги, читаемые как персистентность. Как уже отмечалось, постоянный сдвиг уровня волатильности (новый рыночный режим, изменение микроструктуры рынка) может быть поглощен GARCH как ложно высокая персистентность, толкая α+β\alpha+\beta к 1. Если ваша оценка долгосрочной волатильности выглядит нестабильной в разных окнах, подозревайте разрыв, а не доверяйте точечной оценке, близкой к IGARCH. Скользящие переподгонки и, где уместно, явная модель режимов защищают от этого.

Восприятие прогнозов волатильности как прогнозов доходности. GARCH прогнозирует величину движений, а не их направление. Он говорит вам, насколько велик вероятный завтрашний размах, но не в какую сторону. Именно поэтому его естественный дом — риск-менеджмент: размер позиции, стопы, VaR, — а не генерация сигналов. Не путайте хороший прогноз дисперсии с преимуществом.

Куда это ведет дальше

GARCH(1,1) — фундамент, и он намеренно неполон. Серия развивает его в трех направлениях:

  • Асимметрия и тяжелые хвосты — реальная волатильность крипты сильнее реагирует на движения вниз, чем вверх (эффект левериджа), а гауссовы инновации не могут воспроизвести хвосты. GJR-GARCH, EGARCH и инновации Student-t / skewed-t рассмотрены в части 2.
  • Многомерная волатильность — корреляции между крипто-активами сами изменяются во времени и резко возрастают при крахах. Динамическое моделирование всей ковариационной матрицы — это часть 3: DCC-GARCH, которая напрямую связана с теорией среднего-дисперсии Марковица и распределением на основе CVaR, как только ковариация становится динамической.
  • Полная стратегия — размер позиции, стопы, издержки, оборот и честная walk-forward оценка объединяются в части 4.

И там, где маргиналы GARCH питают совместный риск: одномерная модель условной дисперсии здесь — это в точности первая стадия пайплайна GARCH-EVT-копула для VaR/CVaR портфеля. Как только у вас есть стандартизированные остатки от подгонки GARCH по каждому активу, вы преобразуете их и склеиваете вместе копулой — маргиналы это GARCH, зависимость это копула. Эта конструкция, включая хвостовую зависимость и обработку хвостов EVT, подробно рассмотрена в моделях копул для совместного риска крипты; эта статья — одномерный движок, лежащий в ее основе.

Резюме

  • Доходности крипты демонстрируют кластеризацию волатильности, тяжелые хвосты и отсутствие автокорреляции доходностей при сильной автокорреляции квадратов доходностей. Любой инструмент, предполагающий постоянную волатильность — Black-Scholes с единственной σ\sigma, статичный VaR, фиксированные процентные стопы — неверно специфицирован против этих фактов.
  • GARCH(1,1), σt2=ω+αεt12+βσt12\sigma_t^2 = \omega + \alpha\varepsilon_{t-1}^2 + \beta\sigma_{t-1}^2, моделирует изменяющуюся во времени условную дисперсию тремя параметрами: базовый уровень ω\omega, реакция на шок α\alpha и персистентность β\beta. Это ARCH(\infty) с геометрически затухающей памятью, поэтому он превосходит ARCH высокого порядка.
  • Стационарность требует α+β<1\alpha+\beta<1; долгосрочная дисперсия равна ω/(1αβ)\omega/(1-\alpha-\beta), персистентность равна α+β\alpha+\beta, а период полураспада волатильности — ln0.5/ln(α+β)\ln 0.5 / \ln(\alpha+\beta). Крипта находится в режиме, близком к IGARCH (α+β0.99\alpha+\beta\approx 0.99): очень персистентном, медленно возвращающемся к среднему, с хрупкой оценкой долгосрочной дисперсии.
  • Оценивайте методом максимального правдоподобия. Гауссово логарифмическое правдоподобие — это сумма одношаговых плотностей; подгоняйте с помощью arch_model(r*100, vol="Garch", p=1, q=1). Помните про масштабирование ×100 и согласованно демасштабируйте каждый выход.
  • Прогнозы возвращаются к среднему геометрически к долгосрочной дисперсии со скоростью (α+β)h1(\alpha+\beta)^{h-1}. Агрегируйте дневные прогнозы дисперсии, чтобы получить волатильность горизонта удержания — а не наивное правило H\sqrt{H}.
  • Валидируйте тестом Льюнга-Бокса на квадратах стандартизированных остатков и тестом ARCH-LM. Прохождение этих тестов подтверждает, что кластеризация была смоделирована; оставшиеся тяжелые хвосты остатков мотивируют часть 2.
  • Применяйте это к размеру позиции, таргетированному по волатильности (wt=σtarget/σ^tw_t = \sigma_{\text{target}}/\hat\sigma_t, с ограничением), и к стопам, масштабированным по волатильности (kσ^t(H)k\cdot\hat\sigma_t^{(H)}). Один прогноз управляет обоими, поэтому режимы высокой волатильности одновременно получают меньший размер и более широкие стопы.
  • Подводные камни, которые важны: масштабирование доходностей, заглядывание в будущее при подгонке (подгоняйте только на прошлых данных, всегда walk-forward), тайминг прогноза, переусложнение порядком, и никогда не путайте прогноз дисперсии с прогнозом направления.

Ссылки:

  • Engle, R. F. (1982). Autoregressive Conditional Heteroscedasticity with Estimates of the Variance of United Kingdom Inflation. Econometrica, 50(4), 987-1007. DOI
  • Bollerslev, T. (1986). Generalized Autoregressive Conditional Heteroskedasticity. Journal of Econometrics, 31(3), 307-327. DOI
  • Mandelbrot, B. (1963). The Variation of Certain Speculative Prices. The Journal of Business, 36(4), 394-419. DOI
  • Nelson, D. B. (1991). Conditional Heteroskedasticity in Asset Returns: A New Approach. Econometrica, 59(2), 347-370. DOI
  • Katsiampa, P. (2017). Volatility estimation for Bitcoin: A comparison of GARCH models. Economics Letters, 158, 3-6. DOI
  • Chu, J., Chan, S., Nadarajah, S., & Osterrieder, J. (2017). GARCH Modelling of Cryptocurrencies. Journal of Risk and Financial Management, 10(4), 17. DOI
  • Sheppard, K. (2023). arch: Autoregressive Conditional Heteroskedasticity (ARCH) and other tools for financial econometrics in Python. GitHub.
Дисклеймер: Информация в этой статье предоставлена исключительно в образовательных и ознакомительных целях и не является финансовым, инвестиционным или торговым советом. Торговля криптовалютами сопряжена с высоким риском убытков.

MarketMaker.cc Team

Количественные исследования и стратегии

Обсудить в Telegram
Newsletter

Будьте в курсе событий

Подпишитесь на нашу рассылку, чтобы получать эксклюзивную аналитику по AI-трейдингу и обновления платформы.

Мы уважаем вашу конфиденциальность. Отписаться можно в любой момент.