← 기사 목록으로
July 11, 2026
5분 소요

비대칭·두꺼운 꼬리 GARCH: EGARCH, GJR, Student-t

#volatility
#GARCH
#EGARCH
#risk
#VaR
#crypto
#algorithmic-trading

이 시리즈의 1부에서는 GARCH(1,1)를 기초부터 구축했다 — 변동성 군집화(volatility clustering)의 직관, 조건부 분산 재귀식, 최대우도법 추정, 예측, 그리고 arch 라이브러리를 이용한 표준 잔차 진단까지. 아직 읽지 않았다면 그곳부터 시작하라 — 이 글은 독자가 이미 일반 GARCH(1,1)를 적합하고 해석할 수 있다고 가정하며, 기초 내용을 다시 유도하지 않는다.

일반 GARCH(1,1)는 좋은 기준선이지만 최종 답으로는 부족하다. 백테스트에서는 무시하기 쉽지만 실제 자본으로는 무시하기 비싼 두 가지 구조적 결함이 있다. 첫째, 이 모델은 대칭적이다: 충격이 분산 재귀식에 제곱 형태 εt12\varepsilon_{t-1}^2로만 들어가기 때문에, 모델은 +5%+5\%인 날과 5%-5\%인 날에 정확히 동일하게 반응한다. 제곱을 취하면 부호 정보가 사라진다. 둘째, 이 모델은 **정규분포 혁신항(Gaussian innovations)**을 가정한다: GARCH가 변동성 군집화를 흡수한 후에도 BTC와 ETH의 표준화 잔차는 눈에 띄게 두꺼운 꼬리(fat-tailed)를 보이며, 정규분포 우도함수는 꼬리 부분을 체계적으로 과소평가한다. GARCH(1,1)-정규분포 99% VaR는 예상보다 훨씬 자주 초과될 것이다.

이 글은 두 결함을 모두 해결한다. GJR-GARCH와 EGARCH로 비대칭성을 추가하고, Student-tt 및 Hansen의 skewed-tt 혁신항으로 두꺼운 꼬리를 추가한다. 그런 다음 실제로 성과를 내는 작업을 한다: 적합된 조건부 분포를 1스텝 Value-at-Risk와 기대손실(Expected Shortfall) 예측으로 전환하고, Kupiec 및 Christoffersen 검정으로 그 예측을 정직하게 백테스트한다. 리스크 검증을 거치지 않은 변동성 모델은 장식품에 불과하다.

레버리지 효과, 그리고 암호화폐가 더 복잡한 이유

주식 시장에서 이 비대칭성에는 이름과 이야기가 있다. 레버리지 효과(Black, 1976)다: 기업의 주가가 하락하면 부채 대비 자기자본 비율이 상승하고, 자기자본이 기계적으로 더 위험해지며, 변동성이 증가한다. 나쁜 뉴스는 동일한 크기의 좋은 뉴스보다 미래 변동성을 더 크게 높인다. 실증적으로 이는 주식 변동성 문헌에서 가장 견고한 정형화된 사실(stylized fact) 중 하나다.

암호화폐에는 기업 회계상의 자기자본이나 부채 레버리지가 없지만, 대부분의 경우 회계가 아닌 강제 디레버리징(forced deleveraging)에 의해 레버리지 효과와 유사한 비대칭성이 여전히 나타난다. BTC가 급락하면 과담보 대출이 청산되고, 무기한 선물(perpetual futures)의 롱 포지션이 강제 청산되며, 펀딩비가 뒤집히고, 이 연쇄 작용이 변동성을 더욱 부추긴다. 즉 메커니즘은 다르지만 부호는 주식 시장과 종종 일치한다: 하락 움직임이 변동성을 더 크게 급등시킨다.

중요한 유의점: 암호화폐는 더 복잡하며, 비대칭성을 법칙이 아니라 실증적 질문으로 다뤄야 한다. 격렬한 상승 움직임 — 숏 스퀴즈, 레버리지가 촉발한 급등, ETF 승인 갭 — 역시 실현 변동성을 급등시킬 수 있다. 자산과 표본 구간에 따라 추정된 비대칭성은 강할 수도, 약할 수도, 때로는 "잘못된" 부호일 수도 있다. 이 글이 강조하는 원칙은 다음과 같다: 비대칭 모델을 적합시키고, 비대칭성 파라미터가 통계적으로 유의하고 예상 방향과 일치하는지 확인하며, 그 추가 파라미터가 제 몫을 할 때만 유지하라. 주식 시장의 이야기가 그대로 이전된다고 가정하지 말고 검증하라.

모델링 전에 비대칭성 검정하기

위의 요지는 "비대칭성을 실증적으로 다루라"는 것이었다 — 그러므로 비대칭 모델을 적합시키기 전에 비대칭성이 실제로 존재하는지에 대한 저비용의 공식 검정을 먼저 수행해야 한다. Engle-Ng 부호편향 검정(sign-bias tests, 1993)이 정확히 이 역할을 한다. 먼저 대칭 GARCH(1,1)를 적합시키고, 그 표준화 잔차의 제곱 zt2z_t^2을 취해, 직전 충격의 부호와 크기를 나타내는 지시변수에 회귀시킨다.

zt2=a0+a1St1+a2St1εt1+a3St1+εt1+utz_t^2 = a_0 + a_1 S_{t-1}^- + a_2 S_{t-1}^- \varepsilon_{t-1} + a_3 S_{t-1}^+ \varepsilon_{t-1} + u_t

여기서 St1=1{εt1<0}S_{t-1}^- = \mathbf{1}\{\varepsilon_{t-1} < 0\}이고 St1+=1St1S_{t-1}^+ = 1 - S_{t-1}^-이다. 논리는 다음과 같다: 대칭 모델이 이미 모든 것을 포착했다면, 어제 충격의 부호와 크기는 오늘의 잔차 제곱을 예측하지 못해야 하므로 a1=a2=a3=0a_1 = a_2 = a_3 = 0이어야 한다. 개별 tt-검정은 부호편향(a1a_1), 음의 크기편향(a2a_2), 양의 크기편향(a3a_3) 검정이며, 세 항 모두에 대한 결합 FF-검정이 옴니버스(omnibus) 검정이다. a1a_1 또는 a2a_2가 유의하다는 것은 대칭 모델이 음의 충격을 체계적으로 잘못 반영하고 있다는 신호로, GJR이나 EGARCH가 도움이 될 것이라는 단서다.

import statsmodels.api as sm

def sign_bias_test(symmetric_res):
    """Engle-Ng sign-bias tests on a fitted symmetric GARCH result."""
    z = symmetric_res.std_resid.dropna()
    z2 = (z ** 2).values[1:]
    eps_lag = z.values[:-1]                      # standardized shock proxy
    neg = (eps_lag < 0).astype(float)
    X = np.column_stack([
        np.ones_like(eps_lag),                   # intercept
        neg,                                     # sign bias
        neg * eps_lag,                           # negative size bias
        (1 - neg) * eps_lag,                     # positive size bias
    ])
    ols = sm.OLS(z2, X).fit()
    names = ["const", "sign_bias", "neg_size_bias", "pos_size_bias"]
    for nm, coef, t, p in zip(names, ols.params, ols.tvalues, ols.pvalues):
        print(f"{nm:16s} coef={coef:+.4f}  t={t:+.2f}  p={p:.3f}")
    print(f"Joint F p-value: {ols.f_pvalue:.4f}")
    return ols

sign_bias_test(models["GARCH-N"])

결합 FF-검정이 유의하지 않다면 대칭 모델을 유지하고 파라미터 두 개를 절약할 실증적 근거가 있는 것이다. 유의하다면 — BTC/ETH에서는 흔한 결과인데 — 실제 특징을 모델링하고 있다는 확신을 가지고 GJR/EGARCH로 넘어가면 된다(노이즈를 쫓는 것이 아니다). 이것이 이 글의 서두가 요구한 실증적 원칙이다: 주식의 레버리지 이야기를 가정하지 말고 검정하라.

GJR-GARCH: 임계값 항을 통한 비대칭성

Glosten-Jagannathan-Runkle 모델(1993) — TGARCH 또는 임계 GARCH(threshold GARCH)라고도 불린다 — 은 나쁜 뉴스와 좋은 뉴스가 서로 다른 효과를 갖도록 하는, GARCH(1,1)에 대한 가장 작은 수정이다. 1부의 대칭 조건부 분산 재귀식을 떠올려 보자.

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

GJR는 임계값 항 하나를 추가한다: 음의 충격 이후에만 켜지는 추가 분산량이다.

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

여기서 It1I_{t-1}는 지시함수다.

It1={1if εt1<00if εt10I_{t-1} = \begin{cases} 1 & \text{if } \varepsilon_{t-1} < 0 \\ 0 & \text{if } \varepsilon_{t-1} \geq 0 \end{cases}

경우를 나누어 재귀식을 읽어 보자. 양의 충격(εt10\varepsilon_{t-1} \geq 0) 이후에는 지시변수가 0이고, 다음 기간 분산에 대한 제곱 충격의 영향은 단지 α\alpha다. 음의 충격 이후에는 지시변수가 1이고 영향은 α+γ\alpha + \gamma가 된다. 파라미터 γ\gamma가 비대칭성 이야기 전체를 하나의 숫자로 담고 있다.

  • γ>0\gamma > 0: 음의 충격이 동일한 크기의 양의 충격보다 변동성을 더 크게 높인다. 이것이 레버리지 효과이며, 대부분의 경우 BTC/ETH에서 발견될 것으로 예상되는 패턴이다.
  • γ=0\gamma = 0: 모델이 대칭 GARCH(1,1)로 되돌아간다. 따라서 γ\gamma에 대한 우도비 검정 또는 tt-검정은 비대칭성이 애초에 존재하는지에 대한 직접적인 검정이다.
  • γ<0\gamma < 0: 양의 충격이 변동성을 더 크게 높인다 — 간혹 나타나는 암호화폐 급등 국면이다. 드물지만 사전에 배제해서는 안 된다.

양의 값 조건과 정상성

σt2\sigma_t^2가 여전히 가법적으로 구성되므로, 각 항이 음이 아닌 값을 유지해야 한다. 충분한 양의 값 조건은 다음과 같다.

ω>0,α0,α+γ0,β0.\omega > 0, \quad \alpha \geq 0, \quad \alpha + \gamma \geq 0, \quad \beta \geq 0.

α+γ0\alpha + \gamma \geq 0만 만족하면 γ\gamma 자체는 음수여도 무방하며, 그 결과 나쁜 뉴스 이후의 영향이 결코 음수가 되지 않는다.

공분산 정상성(covariance stationarity)을 위해서는, 혁신항 zt=εt/σtz_t = \varepsilon_t/\sigma_t가 0을 중심으로 대칭인 분포로 표준화되어 있다고 가정한다. 그러면 P(εt1<0)=1/2P(\varepsilon_{t-1} < 0) = 1/2이고 지시변수는 평균적으로 γ/2\gamma/2만큼 기여한다. 정상성 조건은 다음과 같이 된다.

α+β+12γ<1.\alpha + \beta + \tfrac{1}{2}\gamma < 1.

무조건(장기) 분산은 다음과 같다.

σˉ2=ω1αβ12γ.\bar{\sigma}^2 = \frac{\omega}{1 - \alpha - \beta - \tfrac{1}{2}\gamma}.

이는 1부의 결과 σˉ2=ω/(1αβ)\bar{\sigma}^2 = \omega/(1-\alpha-\beta)에 대응하는 GJR 버전으로, 추가된 12γ\tfrac{1}{2}\gamma 항이 레버리지 반감기의 평균적 기여를 반영한다. 혁신항 분포가 편향(skewed)되어 있다면(아래의 Hansen의 skew-tt), 1/21/2zt<0z_t < 0일 실제 확률로 대체되지만, 보고되는 지속성(persistence) 지표로는 1/21/2이 표준 기준값으로 사용된다.

EGARCH: 로그-분산을 모델링하며 양의 값 제약 없음

GJR는 양의 값 제약이라는 굴레에 갇혀 있다: 모든 파라미터 조합을 부등식 제약과 대조해 확인해야 하며, 이는 최적화 과정에서 성가시고, 롤링 재추정 과정에서 창(window)이 간혹 실행 불가능한 영역으로 벗어날 때는 더욱 문제가 된다. Nelson의 지수 GARCH(Exponential GARCH, 1991)는 조건부 분산의 로그를 모델링함으로써 이 문제를 완전히 우회한다. logσt2\log \sigma_t^2는 임의의 실수값을 가질 수 있으므로, σt2=exp(logσt2)\sigma_t^2 = \exp(\log \sigma_t^2)는 파라미터 값과 무관하게 자동으로 양수가 된다. 부과할 제약이 없다.

재귀식을 표준화된 혁신항 zt1=εt1/σt1z_{t-1} = \varepsilon_{t-1}/\sigma_{t-1}을 사용해 다음과 같이 쓴다.

logσt2=ω+βlogσt12+α(zt1Ezt1)+γzt1\log \sigma_t^2 = \omega + \beta \log \sigma_{t-1}^2 + \alpha\bigl(|z_{t-1}| - \mathbb{E}|z_{t-1}|\bigr) + \gamma\, z_{t-1}

두 항이 충격을 전달하며, 이 둘을 분리하는 것이 핵심 아이디어다.

  • 크기(magnitude)α(zt1Ezt1)\alpha(|z_{t-1}| - \mathbb{E}|z_{t-1}|)는 부호를 제거한 충격의 크기에 반응한다. Ezt1\mathbb{E}|z_{t-1}|을 빼서 중심화함으로써 평균 크기의 충격은 아무 기여도 하지 않게 된다. 표준정규분포의 경우 Ez=2/π0.7979\mathbb{E}|z| = \sqrt{2/\pi} \approx 0.7979이며, 표준화된 Student-tt의 경우 절댓값 기댓값은 더 작고 ν\nu에 따라 달라지지만 arch가 내부적으로 이를 처리한다.
  • 부호(sign)γzt1\gamma\, z_{t-1}이 비대칭성이다. 부호가 있는 혁신항에 선형이므로, 음의 zt1z_{t-1}은 양의 값과 반대 방향으로 logσt2\log\sigma_t^2를 밀어낸다.

부호 규약에 유의해야 하며 사람들이 자주 실수하는 부분이다. 이 파라미터화에서는 레버리지 효과(나쁜 뉴스가 변동성을 높인다)가 γ<0\gamma < 0에 대응한다: 음의 충격 zt1<0z_{t-1} < 0이면 γzt1>0\gamma z_{t-1} > 0이 되어 로그-분산이 증가한다. 이는 GJR의 γ>0\gamma > 0과 반대 부호다. 규약은 항상 기억에 의존하지 말고 해당 모델의 문서를 확인해야 한다. arch는 EGARCH를 자체 부호 규약으로 보고하며, 우리는 이를 기억에 의존하기보다 아래의 뉴스 임팩트 곡선으로 검증한다.

로그 상에서 모든 것이 가법적이므로, EGARCH(1,1)의 지속성은 logσt12\log\sigma_{t-1}^2에 대한 단일 자기회귀 계수 β\beta로 결정된다. 정상성은 β<1|\beta| < 1만 요구한다. 이는 GJR 부등식보다 훨씬 깔끔한 조건이며, 롤링 창에서 재적합할 때 실질적인 장점이 된다.

한 가지 짚어둘 세부사항: EGARCH의 충격에 대한 반응은 혁신항에 대해 지수적인 반면(마지막에 지수를 취한다), GJR는 이차식(quadratic)이다. 따라서 EGARCH는 큰 충격에 더 격렬하게 반응한다 — 꼬리 이벤트가 중요한 암호화폐에서는 장점이지만, 이상치가 발생한 날 이후 비현실적으로 큰 분산 예측을 만들어낼 수 있다는 이유이기도 하다. 어느 쪽도 보편적으로 더 낫지 않다. 표본 외 적합도와 리스크 백테스트로 선택해야 하며, 그것이 이 시리즈 전체의 요지다.

뉴스 임팩트 곡선

대칭 GARCH, GJR, EGARCH의 차이를 가장 명확하게 보는 방법은 뉴스 임팩트 곡선(news impact curve, Engle and Ng, 1993)이다: σt1\sigma_{t-1}을 장기 수준으로 고정하고, 다음 기간 조건부 분산 σt2\sigma_t^2을 마지막 충격 εt1\varepsilon_{t-1}의 함수로 그린다. 이는 "이 정도 크기와 부호의 충격이 주어졌을 때, 모델은 내일의 변동성을 얼마나 높이는가?"라는 질문에 답한다.

  • 대칭 GARCH는 0을 중심으로 하는 대칭 포물선을 만든다. 5%-5\%+5%+5\% 충격이 같은 높이에 위치한다. 이것이 바로 우리가 해결하려는 결함이다.
  • GJR는 0에서 꺾이는 포물선을 만든다 — γ>0\gamma > 0일 때 오른쪽(양의 충격)보다 왼쪽(음의 충격)이 더 가파르다. 두 절반은 각각 α+γ\alpha+\gammaα\alpha의 곡률을 갖는다.
  • EGARCH비대칭적인 지수 V자형을 만든다: γz\gamma z 항 때문에 두 팔의 기울기가 다르며, 마지막 지수화 때문에 전체가 포물선보다 더 빠르게 위로 휘어진다.

세 곡선 모두를 적합된 파라미터로부터 그리는 작업은 뒤의 구현 섹션에서 다룬다 — 비대칭성이 무엇을 제공하는지 전달하는 데 가장 유용한 단일 진단 도구다.

두꺼운 꼬리: Student-t와 skewed-t 혁신항

비대칭성은 충격의 부호에 대한 모델의 반응을 고친다. 충격 자체의 분포에 대해서는 아무것도 하지 않는다. 일반 GARCH는 ztN(0,1)z_t \sim \mathcal{N}(0,1)을 가정하는데, 이 가정은 암호화폐에서 거의 항상 틀린다. GARCH가 변동성 군집화를 제거한 후에도 표준화 잔차 zt=εt/σtz_t = \varepsilon_t / \sigma_t는 초과 첨도(excess kurtosis)를 유지한다 — 즉 두꺼운 꼬리를 갖는다. 분포의 어깨 부분을 적합시키는 정규분포 우도함수는 4, 5, 6 시그마 표준화 일자가 실제로 얼마나 자주 발생하는지를 과소평가한다.

리스크에 대한 결과는 직접적이다. 정규분포 99% VaR는 분위수 Φ1(0.01)2.326\Phi^{-1}(0.01) \approx -2.326을 사용하므로 VaR0.992.326σt\text{VaR}_{0.99} \approx 2.326\,\sigma_t를 예측한다. 실제 표준화 분포가 자유도 ν=5\nu = 5인 Student-tt라면, 실제 1% 분위수는 약 3.36-3.36에 가깝다 — 정규분포 VaR는 그 신뢰수준에서 약 44%44\%가량 낙관적이다. 실제로는 예상보다 훨씬 자주 이를 초과하게 되고, "불가능한" 날에 체계적으로 놀라게 될 것이다. 이것은 암호화폐만의 특이 현상이 아니다. Bollerslev(1987)는 주식과 외환 잔차가 동일한 두꺼운 꼬리를 보였기 때문에 정확히 이 이유로 tt-GARCH를 도입했다. 암호화폐는 같은 문제의 더 극단적인 버전일 뿐이다.

표준화 Student-t

Student-tt 밀도함수는 꼬리 두께를 조절하는 자유도 파라미터 ν>2\nu > 2를 갖는다: ν\nu가 작을수록 꼬리가 두꺼우며, ν\nu \to \infty가 되면 tt는 정규분포로 수렴한다. 문제는 원래의 tνt_\nu 분포가 분산 ν/(ν2)1\nu/(\nu-2) \neq 1을 가지므로, 혁신항으로 사용하기 전에 단위 분산으로 표준화해야 한다는 점이다 — 그렇지 않으면 GARCH 재귀식의 "σt\sigma_t"가 실제로는 조건부 표준편차가 아니게 된다.

단위 분산을 갖는 표준화 Student-tt 혁신항의 밀도함수는 다음과 같다.

f(z;ν)=Γ ⁣(ν+12)π(ν2)  Γ ⁣(ν2)(1+z2ν2)ν+12,ν>2.f(z;\nu) = \frac{\Gamma\!\left(\frac{\nu+1}{2}\right)}{\sqrt{\pi(\nu-2)}\;\Gamma\!\left(\frac{\nu}{2}\right)}\left(1 + \frac{z^2}{\nu-2}\right)^{-\frac{\nu+1}{2}}, \qquad \nu > 2.

내부의 (ν2)(\nu-2)에 주목하라 — 이것이 표준화로, Var(z)=1\mathrm{Var}(z)=1이 되도록 재조정한다. GARCH 조건부 분산 σt2\sigma_t^2zt=εt/σtz_t = \varepsilon_t/\sigma_t가 주어졌을 때, 한 관측치의 로그우도 기여분은 다음과 같다.

t=logΓ ⁣(ν+12)logΓ ⁣(ν2)12log(π(ν2))12logσt2ν+12log ⁣(1+zt2ν2).\ell_t = \log\Gamma\!\left(\tfrac{\nu+1}{2}\right) - \log\Gamma\!\left(\tfrac{\nu}{2}\right) - \tfrac{1}{2}\log\bigl(\pi(\nu-2)\bigr) - \tfrac{1}{2}\log\sigma_t^2 - \frac{\nu+1}{2}\log\!\left(1 + \frac{z_t^2}{\nu-2}\right).

12logσt2-\tfrac{1}{2}\log\sigma_t^2 항은 εt\varepsilon_t에서 ztz_t로의 변환에 대한 야코비안(Jacobian)으로, 1부의 정규분포 GARCH 우도함수에서 본 것과 같은 항이다. 형태만 바뀐다. GARCH 파라미터와 ν\nu에 대해 결합적으로 tt\sum_t \ell_t를 최대화하는 것이 바로 dist='t'를 넘길 때 arch가 수행하는 작업이다.

추정된 ν\nu 자체가 정보를 담고 있다. 일간 BTC/ETH 수익률의 경우 보통 ν36\nu \approx 3\text{–}6 범위에 위치한다 — 두꺼운 꼬리를 갖지만 유한한 분산(그러려면 ν>2\nu > 2가 필요)과 대체로 유한한 첨도(그러려면 ν>4\nu > 4가 필요)를 갖는다. 적합된 ν\nu가 4 미만으로 떨어지면, 모델상 표본 첨도가 기술적으로 무한대가 되며 일부 추정량이 불안정해질 수 있다는 점에 유의해야 한다 — 이상치와 데이터 품질을 면밀히 살펴봐야 한다는 신호다.

Hansen의 Skewed-t

Student-tt는 두꺼운 꼬리를 갖지만 여전히 대칭적이다 — 왼쪽 꼬리와 오른쪽 꼬리의 두께가 같다. 암호화폐 수익률 잔차는 종종 동시에 편향(skewed)되어 있다 — 왼쪽 꼬리(폭락)가 오른쪽보다 더 두껍다. Hansen의 skewed-tt(1994)는 ν\nu와 더불어 왜도 파라미터 λ(1,1)\lambda \in (-1, 1)을 갖는 표준화 tt를 일반화한다.

f(z;ν,λ)={bc(1+1ν2(bz+a1λ)2)ν+12z<a/bbc(1+1ν2(bz+a1+λ)2)ν+12za/bf(z;\nu,\lambda) = \begin{cases} b\,c\left(1 + \dfrac{1}{\nu-2}\left(\dfrac{bz+a}{1-\lambda}\right)^2\right)^{-\frac{\nu+1}{2}} & z < -a/b \\[2mm] b\,c\left(1 + \dfrac{1}{\nu-2}\left(\dfrac{bz+a}{1+\lambda}\right)^2\right)^{-\frac{\nu+1}{2}} & z \geq -a/b \end{cases}

여기서 상수 a=4λcν2ν1a = 4\lambda c\,\frac{\nu-2}{\nu-1}, b2=1+3λ2a2b^2 = 1 + 3\lambda^2 - a^2, c=Γ(ν+12)π(ν2)Γ(ν2)c = \frac{\Gamma(\frac{\nu+1}{2})}{\sqrt{\pi(\nu-2)}\,\Gamma(\frac{\nu}{2})}는 유효한 모든 (ν,λ)(\nu,\lambda)에 대해 zz가 평균 0, 분산 1을 갖도록 선택된다. 분포는 z=a/bz = -a/b에서 나뉘며, 한쪽 꼬리에 더 많은 질량을 밀어넣기 위해 각 구간마다 다른 스케일링을 사용한다.

해석: λ<0\lambda < 0은 왼쪽으로 편향된 분포(하방이 더 두꺼움)를 만들며, 이는 암호화폐에서 보통 발견되는 결과이고 레버리지 효과와 함께 나타날 것으로 예상할 수 있다. λ=0\lambda = 0은 대칭 Student-tt로 되돌아가므로, λ=0\lambda = 0 검정은 왜도 항이 실제로 무언가를 제공하는지 알려준다. arch에서 이는 dist='skewt'이며, ν\nuλ\lambda를 모두 추정한다. 이 결과는 왼쪽 꼬리 분위수가 오른쪽 꼬리 분위수보다 정직하게 더 두꺼운 VaR로 이어진다 — 생존해야 할 손실이 비대칭적일 때 정확히 원하는 결과다. 이는 포지션 결과에서의 손실 대 이익의 비대칭성과 직접 연결된다: x%x\%의 낙폭을 회복하려면 x%x\%보다 더 큰 상승이 필요하므로, 왼쪽 꼬리를 잘못 모델링하는 것이 오른쪽 꼬리를 잘못 모델링하는 것보다 비용이 더 크다.

Python 구현

이제 arch 라이브러리로 이 모든 것을 적합시킨다. 설정은 1부와 동일하다: 일간 수익률을 가져와 수치적 안정성을 위해 100배 스케일링하고(수익률이 O(0.01)O(0.01)일 때 GARCH 최적화기가 제대로 작동하지 않는다), 상수 평균으로 적합한다. 인트라데이나 다른 평균 모델을 원한다면 메커니즘은 동일하다.

설정과 데이터

import numpy as np
import pandas as pd
from arch import arch_model
from arch.univariate import GARCH, EGARCH, ConstantMean, StudentsT, SkewStudent
from scipy import stats

def fetch_returns(symbol="BTC-USD", start="2019-01-01", end="2025-12-31"):
    """Daily log returns, in percent (scaled x100 for the optimizer)."""
    import yfinance as yf
    px = yf.download(symbol, start=start, end=end)["Close"].dropna()
    ret = 100.0 * np.log(px / px.shift(1)).dropna()
    ret.name = symbol
    return ret

r = fetch_returns("BTC-USD")
print(f"{len(r)} daily observations, "
      f"annualized vol ~ {r.std() * np.sqrt(365):.0f}%")

암호화폐는 24시간 연중무휴 거래되므로 252가 아니라 365로 연율화한다 — 암호화폐 샤프비율이나 변동성을 주식 데스크의 수치와 비교할 때 흔히 혼동을 일으키는 작지만 반복적인 요소다.

네 가지 모델 적합

arch의 패턴: p=1, q=1vol='Garch'는 대칭 GARCH이며, o=1을 추가하면 GJR 임계값 항이 켜진다. vol='EGARCH'는 로그-분산 모델로 전환한다. 혁신항 분포는 dist로 설정한다: 'normal', 't', 'skewt'.

def fit(returns, vol="Garch", p=1, o=0, q=1, dist="normal"):
    am = arch_model(returns, mean="Constant",
                    vol=vol, p=p, o=o, q=q, dist=dist)
    res = am.fit(disp="off")
    return res

models = {
    "GARCH-N":    fit(r, vol="Garch",  o=0, dist="normal"),  # Part 1 baseline
    "GJR-t":      fit(r, vol="Garch",  o=1, dist="t"),        # asymmetry + fat tails
    "EGARCH-t":   fit(r, vol="EGARCH", o=1, dist="t"),        # log-variance asymmetry
    "GJR-skewt":  fit(r, vol="Garch",  o=1, dist="skewt"),    # + skew
}

for name, res in models.items():
    print(f"\n===== {name} =====")
    print(res.summary().tables[1])   # parameter table

vol='EGARCH'의 경우 o 인자가 비대칭(γz\gamma z) 항을 제어하고 p/q는 크기 항과 시차 항을 제어한다. o=1, p=1, q=1이 표준 EGARCH(1,1)이다. 한 가지 주의할 점: arch에서 EGARCH의 파라미터 이름은 동일한 문자를 쓰지만 비대칭 항의 부호 규약은 Nelson의 규약을 따르므로, 음의 추정값이 레버리지 효과다. 이를 기억에 의존하기보다 뉴스 임팩트 곡선으로 검증한다.

GJR 적합 결과 읽기

GJR-tt 파라미터 표는 대략 다음과 같이 보인다(예시 값이며 실제 실험 보고가 아니다 — 자신의 데이터로 재적합하라).

                  coef    std err       t      P>|t|
omega           0.0480     0.017     2.82     0.005
alpha[1]        0.0620     0.018     3.44     0.001
gamma[1]        0.0910     0.028     3.25     0.001
beta[1]         0.8850     0.021    42.1      0.000
nu              4.30       0.55      7.82     0.000

읽는 법:

  • gamma[1] = 0.091이고 tt-통계량이 3을 넘는다는 것은 통계적으로 유의한 레버리지 효과를 의미한다. 음의 충격 이후 제곱 충격의 영향은 α+γ=0.062+0.091=0.153\alpha + \gamma = 0.062 + 0.091 = 0.153이며, 양의 충격 이후에는 단지 α=0.062\alpha = 0.062다. 나쁜 뉴스는 이 모델의 변동성을 같은 크기의 좋은 뉴스보다 약 2.52.5배 더 크게 움직인다.
  • nu = 4.3은 두꺼운 꼬리를 확인해준다 — 정규분포(ν\nu \to \infty)와는 거리가 멀고, 4차 모멘트가 겨우 유한할 정도로 낮다. 이 시리즈에 정규분포 VaR를 적용하면 심하게 낙관적일 것이다.
  • 지속성은 α+β+12γ=0.062+0.885+0.04550.993\alpha + \beta + \tfrac{1}{2}\gamma = 0.062 + 0.885 + 0.0455 \approx 0.993으로 매우 높다. 일간 암호화폐에서 통상적인 값이다: 충격이 천천히 감쇠하고 변동성이 강하게 군집화된다.

가장 중요하게 확인해야 할 행은 γ\gamma 행이다. pp-값이 크다면 이 자산과 구간에서 비대칭 항이 제 몫을 하지 못하는 것이며, 더 단순한 대칭 모델을 선호해야 한다. 이는 장식이 아니라 모델 선택의 원칙이다 — 아래에서 더 다룬다.

정보 기준으로 모델 비교하기

로그우도는 파라미터를 추가할 때마다 항상 개선되므로, 로그우도만으로 모델을 선택해서는 안 된다. 파라미터 수에 페널티를 부과하는 AIC/BIC를 사용하라(BIC가 더 공격적이다).

def compare(models: dict) -> pd.DataFrame:
    rows = []
    for name, res in models.items():
        rows.append({
            "model": name,
            "n_params": len(res.params),
            "loglik": res.loglikelihood,
            "AIC": res.aic,
            "BIC": res.bic,
        })
    df = pd.DataFrame(rows).set_index("model")
    return df.sort_values("BIC")

print(compare(models))

경험 법칙: 기준선 대비 BIC 개선이 약 6을 넘으면 추가 구조가 실재한다는 강력한 증거다. 1–2 차이는 노이즈다. GJR-tGARCH-N보다 BIC 30점 이상 우수하지만 GJR-skewtGJR-t보다 겨우 1점 우수하다면, tt를 유지하고 왜도는 버려라 — 왜도 파라미터는 이 데이터에서 제 몫을 하지 못하고 있다. AIC/BIC를 표본 외 검증의 대체물로 읽어서는 안 된다. 이들은 복잡성으로 조정된 표본 내 적합도에 보상을 주는데, 이는 필요조건이지 충분조건이 아니다. 진짜 검증은 VaR 백테스트이며, 궁극적으로는 워크포워드 평가다.

뉴스 임팩트 곡선 그리기

이것이 성과를 보여주는 그래프다 — 비대칭성을 눈에 보이게 만들고 EGARCH 부호 규약을 검증한다.

import matplotlib.pyplot as plt

def news_impact_curve(res, shock_grid):
    """
    Next-period conditional variance as a function of the last shock,
    holding sigma_{t-1} at the model's unconditional level.
    Works for symmetric GARCH, GJR (o=1), and EGARCH.
    """
    p = res.params
    vol_name = res.model.volatility.__class__.__name__
    sigma2_bar = np.mean(res.conditional_volatility ** 2)

    omega = p["omega"]
    alpha = p.get("alpha[1]", 0.0)
    gamma = p.get("gamma[1]", 0.0)
    beta  = p.get("beta[1]", 0.0)

    if vol_name == "EGARCH":
        sig_prev = np.sqrt(sigma2_bar)
        z = shock_grid / sig_prev
        E_abs = np.sqrt(2 / np.pi)   # approx; arch uses the fitted dist's E|z|
        log_s2 = (omega + beta * np.log(sigma2_bar)
                  + alpha * (np.abs(z) - E_abs) + gamma * z)
        return np.exp(log_s2)
    else:
        ind = (shock_grid < 0).astype(float)
        return omega + (alpha + gamma * ind) * shock_grid**2 + beta * sigma2_bar

shocks = np.linspace(-8, 8, 401)   # daily % shocks
plt.figure(figsize=(8, 5))
for name in ["GARCH-N", "GJR-t", "EGARCH-t"]:
    nic = news_impact_curve(models[name], shocks)
    plt.plot(shocks, nic, label=name, lw=2)
plt.axvline(0, color="gray", lw=0.8, ls="--")
plt.xlabel("Last shock  $\\varepsilon_{t-1}$  (daily %)")
plt.ylabel("Next-period conditional variance  $\\sigma_t^2$")
plt.title("News impact curve: symmetric vs GJR vs EGARCH (BTC)")
plt.legend()
plt.tight_layout()

이를 실행하면, 대칭 GARCH-N 곡선은 0을 중심으로 하는 깔끔한 포물선이 된다 — 6%-6\%+6%+6\% 충격이 동일한 분산을 갖는다. GJR-t는 원점에서 꺾이는 포물선으로, 왼쪽 팔이 더 높다. EGARCH-t는 지수 V자형이며, 왼쪽 팔이 오른쪽 팔보다 위에 있다면 한눈에 레버리지 효과와 부호 규약을 확인한 것이다. EGARCH의 왼쪽 팔이 오른쪽보다 아래에 있다면, γ\gamma가 양수로 추정된 것(상승-변동성 국면)이거나 부호가 뒤바뀐 것이다 — 그래프가 추측 없이 어느 쪽인지 알려준다.

네 가지 모델의 나란한 비교

리스크로 넘어가기 전에 네 모델을 나란히 놓고 보는 것이 도움이 된다. 각 행은 설계 결정이며, 열은 그 결정이 무엇을 비용으로 치르고 무엇을 얻는지 보여준다.

속성 GARCH-N GJR-t EGARCH-t GJR-skewt
비대칭성(충격의 부호) 없음 임계값 γIε2\gamma I\varepsilon^2 부호 있는 γz\gamma z 임계값 γIε2\gamma I\varepsilon^2
혁신항의 꼬리 형태 정규분포 Student-tt Student-tt skewed-tt
혁신항의 왜도 없음 없음 없음 있음(λ\lambda)
양의 값 제약 있음 있음(α+γ0\alpha+\gamma\ge0) 없음(로그 형태) 있음
정상성 조건 α+β<1\alpha+\beta<1 α+β+12γ<1\alpha+\beta+\tfrac12\gamma<1 β<1\lvert\beta\rvert<1 α+β+P(z<0)γ<1\alpha+\beta+P(z<0)\gamma<1
기준선 대비 추가 파라미터 0개 γ,ν\gamma,\nu γ,ν\gamma,\nu γ,ν,λ\gamma,\nu,\lambda
암호화폐에서의 통상적 결론 VaR 백테스트 실패 강력하고 견고함 강력하고 견고함 GJR-t 대비 한계적

내면화해야 할 패턴: 1열에서 2열로의 도약 — 비대칭성과 두꺼운 꼬리를 동시에 추가하는 것 — 이 리스크 보정 개선의 거의 대부분을 차지하는 지점이다. 이후의 정교화(EGARCH의 함수 형태, 왜도 항)는 실재하지만 부차적이며, 많은 암호화폐 시계열에서는 노이즈 범위 내에 있다. 모델링 예산은 첫 번째 도약에 쓰고 나머지에는 회의적인 태도를 유지하라.

리스크 응용: VaR와 기대손실

더 정교한 변동성 모델을 적합시키는 것은 어떤 의사결정을 개선할 때만 가치가 있다. 개선하기에 가장 명확한 의사결정은 1스텝 꼬리 리스크 예측이다: 내일은 얼마나 나쁠 수 있는가? 우리는 적합된 GARCH-tt/skew-tt 예측으로부터 직접 하루 앞선 Value-at-Risk기대손실(Expected Shortfall, 조건부 VaR라고도 하며 HRP/CVaR 포트폴리오 파이프라인이 목적함수로 사용하는 지표)을 산출한다.

조건부 분포에서 VaR로

GARCH 메커니즘은 조건부 평균 μt+1\mu_{t+1}과 조건부 표준편차 σt+1\sigma_{t+1}의 1스텝 예측을 제공한다. 수익률은 rt+1=μt+1+σt+1zt+1r_{t+1} = \mu_{t+1} + \sigma_{t+1} z_{t+1}로 모델링되며 zt+1z_{t+1}은 적합된 표준화 분포(정규, tt, 또는 skew-tt)에서 추출된다. 따라서 수익률α\alpha-분위수는 표준화 분포α\alpha-분위수를 단순 아핀 변환한 값이다.

VaRα(t+1)=(μt+1+σt+1Fz1(1α))\text{VaR}_{\alpha}(t+1) = -\Bigl(\mu_{t+1} + \sigma_{t+1}\, F_z^{-1}(1-\alpha)\Bigr)

여기서 Fz1F_z^{-1}은 표준화 혁신항의 분위수(역누적분포함수)이며, 선행하는 음의 부호는 VaR를 양의 손실 값으로 표기하는 관례를 따른 것이다. 99% VaR의 경우 α=0.99\alpha = 0.99이고 Fz1(0.01)F_z^{-1}(0.01)을 대입한다. tt/skew-tt의 전체 이점이 여기서 드러난다: Fz1(0.01)F_z^{-1}(0.01)은 정규분포의 2.326-2.326보다 더 음수이므로 VaR는 정직하게 더 커진다.

기대손실

VaR는 임계값을 알려줄 뿐, 위반이 발생했을 때 얼마나 나쁜지는 알려주지 않는다. 기대손실 — VaR를 초과했을 조건부에서의 평균 손실 — 은 이를 알려주며, 정합적(coherent, 부분가법적)이기 때문에 CVaR 최적화의 근간이 되는 리스크 척도이자 바젤(Basel)이 이 지표로 전환한 이유이기도 하다. 위치-척도(location-scale) 모델에서는 다음과 같다.

ESα(t+1)=(μt+1+σt+1E ⁣[zzFz1(1α)]).\text{ES}_{\alpha}(t+1) = -\Bigl(\mu_{t+1} + \sigma_{t+1}\, \mathbb{E}\!\left[z \mid z \leq F_z^{-1}(1-\alpha)\right]\Bigr).

조건부 꼬리 기댓값 항 E[zzq]\mathbb{E}[z \mid z \le q]은 표준 분포에 대해 닫힌 형태(closed form)를 갖는다. 정규분포의 경우 q=Φ1(1α)q = \Phi^{-1}(1-\alpha)일 때 다음과 같다.

E[zzq]=ϕ(q)1α,\mathbb{E}[z \mid z \le q] = -\frac{\phi(q)}{1-\alpha},

여기서 ϕ\phi는 표준정규 확률밀도함수다. 자유도 ν\nu를 갖는 **표준화 Student-tt**의 경우 q=tν1(1α)q = t_\nu^{-1}(1-\alpha)(표준화 척도상)일 때, 꼬리 기댓값은 다음과 같다.

E[zzq]=ν+q2ν1gν(q)1α,\mathbb{E}[z \mid z \le q] = -\frac{\nu + q^2}{\nu - 1}\cdot\frac{g_\nu(q)}{1-\alpha},

여기서 gνg_\nu는 표준화 tt 확률밀도함수다. tt 기대손실은 VaR보다 더 큰 폭으로 정규분포 기대손실을 초과하는데, tt의 꼬리가 단순히 더 멀리 뻗어 있을 뿐 아니라 더 두껍기 때문에, 임계값을 넘어선 평균 손실이 불균형적으로 크기 때문이다. 그 추가적인 격차가 바로 정규분포 모델이 숨기고 있는 수치다.

적합된 arch 모델에서 VaR와 ES 계산하기

arch의 분포 객체는 ppf(분위수) 메서드를 제공하므로, 다시 유도할 필요 없이 표준화 분위수를 직접 얻을 수 있다. ES는 수치적으로 적분하는데, 이는 견고하며 normal/t/skewt 전반에 걸쳐 균일하게 작동한다.

from scipy import integrate

def var_es_forecast(res, alpha=0.99):
    """
    One-step-ahead VaR and ES at level alpha, on the same (x100) scale
    as the returns fed to the model. Divide by 100 for fractional units.
    """
    fc = res.forecast(horizon=1, reindex=False)
    mu = fc.mean.iloc[-1, 0]
    sigma = np.sqrt(fc.variance.iloc[-1, 0])

    dist = res.model.distribution          # StudentsT / SkewStudent / Normal
    dp = [res.params[k] for k in res.params.index
          if k in ("nu", "eta", "lambda", "lam")]

    z_q = dist.ppf(1 - alpha, dp) if dp else dist.ppf(1 - alpha)
    z_q = float(np.atleast_1d(z_q)[0])

    def pdf(z):
        arr = np.atleast_1d(z).astype(float)
        lp = dist.loglikelihood(dp, arr, np.ones_like(arr), individual=True) \
             if dp else dist.loglikelihood([], arr, np.ones_like(arr),
                                           individual=True)
        return np.exp(lp)

    num, _ = integrate.quad(lambda z: z * pdf(z), -30, z_q, limit=200)
    es_z = num / (1 - alpha)               # E[z | z <= z_q]

    var = -(mu + sigma * z_q)
    es  = -(mu + sigma * es_z)
    return {"mu": mu, "sigma": sigma, "z_q": z_q,
            "VaR": var, "ES": es}

for name in ["GARCH-N", "GJR-t", "GJR-skewt"]:
    out = var_es_forecast(models[name], alpha=0.99)
    print(f"{name:11s}  sigma={out['sigma']:.2f}%  "
          f"z_q={out['z_q']:+.2f}  "
          f"VaR99={out['VaR']:.2f}%  ES99={out['ES']:.2f}%")

z_q 열이 이야기 전체를 담은 하나의 숫자다. 정규분포 모델은 zq2.33z_q \approx -2.33을 사용하고, ν4.3\nu \approx 4.3tt3.3-3.3에 가까운 값을 사용하며, skew-tt왼쪽 분위수를 더 멀리 밀어내는 동시에 오른쪽 분위수는 안쪽으로 당긴다. 동일한 σt+1\sigma_{t+1}이지만 VaR는 실질적으로 더 커진다. 암호화폐에 정규분포 VaR를 적용해 왔다면, 이것이 조용히 감수해 온 격차다.

1스텝 대 다단계: 유의사항

위의 모든 내용은 하루 앞선 예측이며, 이는 GARCH VaR가 가장 깔끔한 영역이다. 더 긴 지평선(horizon)에서는 두 가지가 복잡해지므로, 외삽하기 전에 알아둬야 한다.

첫째, 분산 예측은 평균회귀(mean-revert)한다. 정상적인 GARCH의 hh스텝 앞선 조건부 분산은 hh가 커짐에 따라 무조건 수준 σˉ2\bar\sigma^2로 수렴하며, 누적 hh일 분산은 각 스텝별 예측의 합이다 — 변동성이 장기 평균에 있지 않은 한 h×σt+12h\times\sigma_{t+1}^2아니다. 순진한 "시간의 제곱근" 스케일링 VaR(h)=hVaR(1)\text{VaR}(h) = \sqrt{h}\,\text{VaR}(1)은 이 평균회귀를 무시하며, 하필 충격 직후 — 그 수치가 가장 필요한 시점 — 에 부정확해진다. 모델 고유의 다단계 분산 경로를 사용하라.

둘째, 다일(multi-day) 수익률의 분포는 1일 혁신항과 같은 형태가 아니다. 여러 개의 tt분포 일간 충격을 합산해도(비선형 GARCH 재귀식을 거치므로) hh일 지평선에서 tt 분포가 되지 않는다. 깔끔한 닫힌 형태는 존재하지 않는다. 다일 VaR에 대한 정직한 방법은 시뮬레이션이다: 적합된 표준화 분포에서 혁신항 경로를 추출하고, GARCH 재귀식을 통과시켜 시뮬레이션된 수익률 경로를 얻은 뒤, hh일 수익률로 집계하고 경험적 분위수를 읽는다. 이는 해석적인 다지평선 분위수가 전혀 존재하지 않는 skew-tt의 경우도 자연스럽게 처리한다. 이 글의 1스텝 해석적 공식은 정확하다. 어떤 다단계 지름길도 검증이 필요한 근사치로 취급하라.

VaR 백테스트: Kupiec과 Christoffersen

VaR 예측은 확률적 주장이다: "손실은 (1α)(1-\alpha) 비율의 날에만 이 임계값을 초과할 것이다." 워크포워드 평가에서 위반(violations, 실현 손실이 예측 VaR를 초과한 날)을 세고 두 가지를 확인하여 이를 검증한다. 첫째, 위반 비율이 맞는가? 둘째, 위반이 독립적인가, 아니면 군집화되는가(모델이 정확히 중요한 순간 — 변동성 급등기 — 에 실패한다는 의미)?

It=1{losst>VaRt}I_t = \mathbf{1}\{\text{loss}_t > \text{VaR}_t\}를 위반 시퀀스, N=ItN = \sum I_tTT일 동안의 위반 횟수, π^=N/T\hat{\pi} = N/T를 관찰된 비율이라 하자. 목표 비율은 p=1αp = 1-\alpha다.

Kupiec의 무조건부 커버리지 검정(1995)은 우도비를 통해 π^p\hat\pi \approx p를 확인한다.

LRuc=2log ⁣[pN(1p)TNπ^N(1π^)TN]    χ12.LR_{uc} = -2\log\!\left[\frac{p^{N}(1-p)^{T-N}}{\hat\pi^{N}(1-\hat\pi)^{T-N}}\right] \;\sim\; \chi^2_1.

Christoffersen의 독립성 검정(1998)은 오늘의 위반이 어제의 위반으로 예측되지 않는지를 확인한다. nijn_{ij}를 위반 시퀀스에서 상태 ii에서 상태 jj로의 전이 횟수, π01=n01/(n00+n01)\pi_{01} = n_{01}/(n_{00}+n_{01}), π11=n11/(n10+n11)\pi_{11} = n_{11}/(n_{10}+n_{11}), π=(n01+n11)/T\pi = (n_{01}+n_{11})/T라 하자. 그러면 다음과 같다.

LRind=2log ⁣[(1π)n00+n10πn01+n11(1π01)n00π01n01(1π11)n10π11n11]    χ12.LR_{ind} = -2\log\!\left[\frac{(1-\pi)^{n_{00}+n_{10}}\,\pi^{\,n_{01}+n_{11}}}{(1-\pi_{01})^{n_{00}}\pi_{01}^{n_{01}}(1-\pi_{11})^{n_{10}}\pi_{11}^{n_{11}}}\right] \;\sim\; \chi^2_1.

두 검정은 조건부 커버리지(conditional coverage) 검정 LRcc=LRuc+LRindχ22LR_{cc} = LR_{uc} + LR_{ind} \sim \chi^2_2로 결합되어, 올바른 비율과 독립성을 동시에 확인한다. 모델이 Kupiec은 통과(올바른 위반 횟수)하면서도 Christoffersen은 실패(모두 한 번의 폭락 주간에 몰림)할 수 있다 — 이것이 가장 잡아내야 할 실패 유형인데, 군집화된 위반이야말로 계좌를 날려버리는 위반이기 때문이다.

from scipy.stats import chi2

def var_backtest(losses, var, p):
    """
    losses, var: 1D arrays, same length; loss>0 is a loss, var>0 threshold.
    p = 1 - alpha (target violation rate, e.g. 0.01 for 99% VaR).
    Returns Kupiec, Christoffersen-independence, and conditional-coverage LR.
    """
    losses = np.asarray(losses)
    var = np.asarray(var)
    I = (losses > var).astype(int)          # violation indicators
    T = len(I)
    N = int(I.sum())
    pi_hat = N / T

    eps = 1e-12
    ll_null = N * np.log(p + eps) + (T - N) * np.log(1 - p + eps)
    ll_alt  = N * np.log(pi_hat + eps) + (T - N) * np.log(1 - pi_hat + eps)
    LR_uc = -2 * (ll_null - ll_alt)
    p_uc = 1 - chi2.cdf(LR_uc, df=1)

    n00 = np.sum((I[:-1] == 0) & (I[1:] == 0))
    n01 = np.sum((I[:-1] == 0) & (I[1:] == 1))
    n10 = np.sum((I[:-1] == 1) & (I[1:] == 0))
    n11 = np.sum((I[:-1] == 1) & (I[1:] == 1))
    pi01 = n01 / (n00 + n01) if (n00 + n01) else 0.0
    pi11 = n11 / (n10 + n11) if (n10 + n11) else 0.0
    pi   = (n01 + n11) / (n00 + n01 + n10 + n11)

    def _ll(pi01, pi11, pi_pooled, use_pooled):
        if use_pooled:
            a = (n00 + n10) * np.log(1 - pi_pooled + eps)
            b = (n01 + n11) * np.log(pi_pooled + eps)
            return a + b
        return (n00 * np.log(1 - pi01 + eps) + n01 * np.log(pi01 + eps)
                + n10 * np.log(1 - pi11 + eps) + n11 * np.log(pi11 + eps))

    LR_ind = -2 * (_ll(pi01, pi11, pi, True) - _ll(pi01, pi11, pi, False))
    p_ind = 1 - chi2.cdf(LR_ind, df=1)

    LR_cc = LR_uc + LR_ind
    p_cc = 1 - chi2.cdf(LR_cc, df=2)

    return {
        "T": T, "violations": N,
        "obs_rate": pi_hat, "target_rate": p,
        "LR_uc": LR_uc, "p_uc": p_uc,
        "LR_ind": LR_ind, "p_ind": p_ind,
        "LR_cc": LR_cc, "p_cc": p_cc,
    }

losses/var 입력을 정직하게 생성하려면, 확장(expanding) 또는 롤링 창에서 재적합(또는 최소한 재예측)하고, 표본 외 각 일자에 대한 1스텝 앞선 VaR를 기록한 뒤, 그날의 실현 손실과 비교해야 한다. VaR를 표본 내(in-sample)에서 백테스트하지 마라 — 예측하도록 요구받은 동일한 폭락 구간에 적합된 모델은 실제보다 훨씬 우수해 보인다. 이는 백테스트-라이브 정합성과 같은 원칙이다: 평가는 의사결정 시점에 사용 가능했던 정보만 사용해야 한다.

def walk_forward_var(returns, alpha=0.99, start=750, refit_every=25,
                     vol="Garch", o=1, dist="t"):
    """
    Expanding-window one-step VaR. Refit every `refit_every` days
    (refitting daily is correct but slow; every ~25 days is a common
    compromise -- validate the shortcut on your data).
    """
    losses, vars_ = [], []
    res = None
    for t in range(start, len(returns)):
        if res is None or (t - start) % refit_every == 0:
            am = arch_model(returns.iloc[:t], mean="Constant",
                            vol=vol, p=1, o=o, q=1, dist=dist)
            res = am.fit(disp="off")
        fc = res.forecast(horizon=1, reindex=False)
        mu = fc.mean.iloc[-1, 0]
        sig = np.sqrt(fc.variance.iloc[-1, 0])
        dp = [res.params[k] for k in res.params.index
              if k in ("nu", "eta", "lambda", "lam")]
        z_q = float(np.atleast_1d(
            res.model.distribution.ppf(1 - alpha, dp) if dp
            else res.model.distribution.ppf(1 - alpha))[0])
        var_t = -(mu + sig * z_q)
        vars_.append(var_t)
        losses.append(-returns.iloc[t])     # realized loss for that day
    return np.array(losses), np.array(vars_)

losses, vars_ = walk_forward_var(r, alpha=0.99, dist="t")
print(var_backtest(losses, vars_, p=0.01))

읽는 법: 잘 보정된 99% VaR는 1%에 가까운 관찰 비율, 유의하지 않은 Kupiec(큰 p_uc), 유의하지 않은 Christoffersen(큰 p_ind, 군집화 없음)을 보인다. 실제로 암호화폐에서 정직한 결과는 GARCH-정규분포가 Kupiec에 실패(위반이 너무 많고 p_uc가 매우 작음)하는 반면 GJR-tt 또는 EGARCH-tt는 통과하거나 근접한다는 것이다. 그 대비가 이 글 전체의 논지를 가설검정으로 구현한 것이다. tt 모델조차 군집화된 위반을 보인다면(작은 p_ind), 변동성 동학이 여전히 잘못 명세된 것이다 — 종종 더 긴 기억(컴포넌트/FIGARCH) 또는 국면(regime) 계층이 필요하다는 신호이며, 이는 HMM을 이용한 국면 탐지와 연결된다.

통과/실패가 아닌 꼬리 손실로 모델 순위 매기기

Kupiec과 Christoffersen은 이진 판정을 제공한다 — 모델이 기각되거나 기각되지 않거나다. 이는 필요하지만 거칠다: 두 모델 모두 "통과"하면서도 하나가 의미 있게 더 예리할 수 있다. 경쟁하는 VaR 예측을 순위 매기려면, 분위수에 대해 엄격하게 정합적인 손실함수인 핀볼(분위수) 손실로 점수를 매긴다.

Lτ(r,q)=(τ1{r<q})(rq),τ=1α,L_\tau(r, q) = \bigl(\tau - \mathbf{1}\{r < q\}\bigr)\,(r - q), \qquad \tau = 1-\alpha,

여기서 qq는 (부호가 있는) VaR 분위수이고 rr은 실현 수익률이다. 표본 외 일자 전체에 걸쳐 평균을 낼 때, 평균 핀볼 손실이 낮을수록 더 잘 보정되고 더 예리한 분위수임을 의미한다. 이 손실함수가 τ\tau-분위수에 대해 정합적이기 때문에, 이를 최소화하는 것이 모델을 게으르게 넓게 잡는 데 보상을 주지 않는다. 두 모델을 공식적으로 비교하려면 일별 손실 차이를 Diebold-Mariano 검정에 입력하라.

def pinball_loss(returns, var, alpha=0.99):
    tau = 1 - alpha
    q = -np.asarray(var)               # VaR is a positive loss; quantile is negative
    r = np.asarray(returns)
    hit = (r < q).astype(float)
    return np.mean((tau - hit) * (r - q))

기대손실에 대해 구체적으로 언급하면, ES는 그 자체로는 도출 가능(elicitable)하지 않다는 점에 유의해야 한다(ES만을 최소화하는 손실함수가 존재하지 않는다). 이는 진정한 이론적 난점으로, VaR와 함께 Fissler-Ziggel 채점 규칙을 사용해 ES를 평가하거나, 위반 규모의 평균이 모델이 예측한 ES와 일치하는지 확인하는 더 단순한 실무 방식으로 대체할 수 있다. 조잡하지만 유용한 ES 점검법: VaR 위반이 발생한 날들 중에서 실현 손실의 평균을 그 날들의 평균 예측 ES와 비교하는 것이다 — 두 값이 가까워야 한다.

규제상의 틀은 바젤 신호등(Basel traffic-light) 방식이다: 250거래일 동안 99% VaR 위반이 04회면 "녹색"(양호), 59회면 "황색"(정밀 조사), 10회 이상이면 "적색"(모델이 기각되고 자본 승수가 상승)이다. Kupiec의 더 거친 사촌격이지만, 리스크 위원회가 실제로 사용하는 언어이며 LR 통계량과 함께 보고할 가치가 있다.

실무적 고려사항

추가 파라미터가 보상받지 못하는 경우

정직한 기본 태도는 복잡성에 대한 회의주의다. 추가하는 모든 파라미터는 최적화기가 과적합할 수 있는 손잡이이며, 비대칭 두꺼운 꼬리 GARCH에는 여러 개가 있다. 구체적인 지침:

  • 유동성이 낮거나 짧은 표본. 일간 관측치가 수백 개뿐이면 γ\gammaλ\lambda의 표준오차가 커지고, 표본 노이즈에 불과한 비대칭성을 "탐지"하게 된다. 새로 나온 얇은 알트코인의 경우 데이터가 뒷받침할 수 있는 가장 복잡한 모델은 흔히 대칭 GARCH-tt다. 200일치 데이터에 skew-tt EGARCH를 적합시키는 것은 자기기만이다.
  • 왜도 항은 종종 비용을 넘지 못한다. 실무에서 정규분포 → tt로의 전환은 크고 신뢰할 만한 개선이다(두꺼운 꼬리는 실재하며 강력하다). tt → skew-tt로의 전환은 종종 한계적이다 — BIC 개선이 1~2점, 때로는 음수다. 데이터가 명확히 요구할 때만 왜도를 추가하라.
  • 일간 데이터에서는 EGARCH와 GJR가 대체로 비슷하다. 둘은 서로 다른 함수 형태로 동일한 정성적 이야기를 담고 있다. 표본 내 로그우도가 더 좋다는 이유가 아니라 표본 외 VaR 백테스트로 선택하라.
  • 더 높은 빈도는 답을 바꾼다. 시간봉이나 분봉에서는 인트라데이 계절성과 미시구조가 지배적이며, 비대칭성과 무관하게 일반적인 일간형 GARCH는 잘못 명세된 것이다. 다른 문제에는 다른 도구가 필요하다.

이는 견고한 우위가 없다는 정직한 평가와 같은 교훈이다: 표본 외 검증에서 살아남지 못하는 더 복잡한 모델은 그것이 대체한 단순한 모델보다 못하다. 정밀함이라는 환상을 안고 있기 때문이다. "ETH에서는 왜도가 도움이 되지 않았다"는 부정적 결과를 실제 발견으로 보고하고, 표본 내 AIC가 아니라 워크포워드 최적화를 심판으로 삼아라.

이것들은 다른 모두가 기반으로 삼는 한계분포다

여기서 다룬 모델들은 종착점이 아니다. 이들은 결합 리스크 메커니즘을 위한 단변량 구성 요소다. 암호화폐 결합 리스크를 위한 코퓰라 모델 글은 비네 코퓰라(vine copula)를 적합시키기 전의 GARCH-EVT 한계분포로 정확히 EGARCH/GJR-tt를 사용한다 — 자산별로 비대칭 두꺼운 꼬리 GARCH를 적합시키고, 표준화 잔차를 추출한 다음에야 자산 간 의존성을 모델링한다. 한계분포가 대칭 정규분포 GARCH라면, 의존성 모델이 아무리 좋아도 코퓰라는 그 꼬리 오류를 그대로 물려받는다. 쓰레기 한계분포는 쓰레기 결합 VaR를 낳는다.

다변량 변동성 문제 — 자산별 분산이 아니라 시간에 따라 변하는 상관관계 — 에 대해서는 이 단변량 적합 위에 동적 상관관계 모델을 얹는 3부, DCC-GARCH를 참조하라. 그리고 변동성 예측을 포지션 사이징과 트레이딩 백테스트로 전환하는 것에 대해서는, 4부의 변동성 타겟팅이 바로 이 모델들의 σt+1\sigma_{t+1} 예측을 사용해 예측된 리스크에 반비례하도록 노출을 조정한다.

분포에 의존하지 않는 대안

리스크 섹션의 모든 내용은 하나의 모수적 가정에 기반한다: 표준화 잔차가 tt 또는 skew-tt를 따른다는 것이다. 이 가정은 검정 가능하고 대체로 합리적이지만 실패할 수 있다. 꼬리 형태를 전혀 확정하고 싶지 않다면, conformal prediction이 유한표본 커버리지 보장을 갖는 분포에 무관한 예측 구간을 제공한다 — 혁신항 분포에 대해 아무런 주장도 하지 않는, 진정으로 다른 철학이다. 두 접근법은 상호보완적이다: 모수적 GARCH-tt는 완전한 조건부 밀도(따라서 conformal 구간이 직접 제공하지 못하는 ES)를 제공하는 반면, conformal은 밀도가 틀렸을 때도 유지되는 커버리지를 제공한다. 프로덕션 환경에서는 둘 다 상호 검증용으로 사용하는 것이 저렴한 보험이다.

수치적·워크플로 관련 유의사항

  • 수익률을 100배 스케일링하라. GARCH 최적화기는 원시 소수 수익률보다 퍼센트 수익률에서 훨씬 안정적으로 수렴한다. 소수 단위로 보고할 때는 VaR/ES를 다시 스케일 조정하는 것을 잊지 마라.
  • 지속성을 주시하라. α+β+12γ\alpha + \beta + \tfrac{1}{2}\gamma 추정치가 약 0.999를 넘으면 모델이 거의 적분(near-integrated, IGARCH형)된 상태다. 예측이 극도로 느리게 평균회귀하며 장기 지평선 분산 예측이 신뢰할 수 없게 된다. 반드시 잘못된 것은 아니지만 표시해 두어야 한다.
  • 롤링 창에서의 수렴 실패. EGARCH의 로그 형태는 양의 값 제약을 피하지만, 병적인(pathological) 창에서는 여전히 수렴에 실패할 수 있다. fit()을 try/except로 감싸고, 라이브 백테스트를 중단시키기보다 이전 창의 파라미터로 폴백하라.
  • 평균 모델. 이 글 전체에서 상수 평균을 사용했다. 대부분의 일간 암호화폐에서는 조건부 평균이 0에 가깝고 변동성에 압도되므로, 정말 타당한 이유가 없다면 이를 예측하는 데 모델 복잡성을 쓰지 마라.

요약

  • 일반 GARCH(1,1)에는 두 가지 구조적 결함이 있다: 대칭적(충격이 ε2\varepsilon^2로 들어가기 때문에 +x%+x\%x%-x\%에 동일하게 반응)이고 정규분포 혁신항을 가정한다(암호화폐의 두꺼운 꼬리를 과소평가). 둘 다 낙관적인 VaR를 통해 실제 손실로 이어진다.
  • GJR-GARCH는 임계값 항 γI(εt1<0)εt12\gamma\,I(\varepsilon_{t-1}<0)\,\varepsilon_{t-1}^2를 추가한다. 유의한 γ>0\gamma > 0은 레버리지 효과다: 나쁜 뉴스가 변동성을 더 크게 높인다. 양의 값 조건은 α+γ0\alpha+\gamma\ge0이 필요하며, 지속성은 α+β+12γ\alpha+\beta+\tfrac{1}{2}\gamma다.
  • EGARCHlogσt2\log\sigma_t^2를 모델링하므로 양의 값 제약이 없고 정상성은 단지 β<1|\beta|<1이다. 비대칭성은 크기 항 zt1|z_{t-1}|과 분리된 부호 있는 항 γzt1\gamma z_{t-1}을 통해 들어온다(이 규약에서는 레버리지가 γ<0\gamma<0).
  • 뉴스 임팩트 곡선 — 다음 기간 분산 대 마지막 충격 — 은 비대칭성을 한눈에 보여주고 EGARCH 부호 규약을 검증한다.
  • Student-tt 혁신항(dist='t')은 자유도 ν\nu(암호화폐의 경우 보통 3~6)로 꼬리를 고치며, Hansen의 skew-tt(dist='skewt')는 더 두꺼운 왼쪽 꼬리를 위한 왜도 λ\lambda를 추가한다. 정규분포 → tt로의 전환은 크고 신뢰할 만한 이득이며, tt → skew-tt는 종종 한계적이다.
  • VaR와 ES는 적합된 조건부 분포로부터 도출된다: VaRα=(μt+1+σt+1Fz1(1α))\text{VaR}_\alpha = -(\mu_{t+1} + \sigma_{t+1}F_z^{-1}(1-\alpha))이며, 두꺼운 꼬리 분위수는 리스크를 정규분포보다 정직하게 더 크게 만든다. ES(정합적, \approx CVaR)는 VaR를 넘어서는 평균 손실을 포착한다.
  • Kupiec과 Christoffersen으로 백테스트하라. Kupiec은 위반 비율을 확인하고, Christoffersen은 위반이 군집화되지 않았는지 확인한다. 모델이 하나는 통과하고 다른 하나는 실패할 수 있다 — 군집화된 위반이 위험한 실패 유형이다. 반드시 표본 외에서 엄격하게 백테스트하라.
  • 복잡성보다 원칙. BIC 그리고 표본 외 VaR 백테스트를 모두 통과할 때만 비대칭성/왜도를 추가하라. 짧거나 유동성이 낮은 시계열에서는 대체로 더 단순한 모델이 승리한다.

References:

  • Nelson, D. B. (1991). Conditional heteroskedasticity in asset returns: A new approach. Econometrica, 59(2), 347-370. DOI
  • Glosten, L. R., Jagannathan, R., & Runkle, D. E. (1993). On the relation between the expected value and the volatility of the nominal excess return on stocks. Journal of Finance, 48(5), 1779-1801. DOI
  • Bollerslev, T. (1987). A conditionally heteroskedastic time series model for speculative prices and rates of return. Review of Economics and Statistics, 69(3), 542-547. DOI
  • Hansen, B. E. (1994). Autoregressive conditional density estimation. International Economic Review, 35(3), 705-730. DOI
  • Engle, R. F., & Ng, V. K. (1993). Measuring and testing the impact of news on volatility. Journal of Finance, 48(5), 1749-1778. DOI
  • Christoffersen, P. F. (1998). Evaluating interval forecasts. International Economic Review, 39(4), 841-862. DOI
  • Kupiec, P. H. (1995). Techniques for verifying the accuracy of risk measurement models. Journal of Derivatives, 3(2), 73-84. DOI
  • Black, F. (1976). Studies of stock price volatility changes. Proceedings of the American Statistical Association, Business and Economic Statistics Section, 177-181.
  • McNeil, A. J., Frey, R., & Embrechts, P. (2015). Quantitative Risk Management: Concepts, Techniques and Tools (2nd ed.). Princeton University Press.
  • Sheppard, K. (2023). arch: Autoregressive conditional heteroskedasticity models in Python. GitHub.
blog.disclaimer

MarketMaker.cc Team

퀀트 리서치 및 전략

Telegram에서 토론하기
Newsletter

시장에서 앞서 나가세요

뉴스레터를 구독하여 독점적인 AI 트레이딩 통찰력, 시장 분석 및 플랫폼 업데이트를 받아보세요.

귀하의 개인정보를 존중합니다. 언제든지 구독을 취소할 수 있습니다.