GARCH(1,1):預測加密貨幣波動率
開啟一張BTC日收益率圖表,你會注意到關於隨機遊走的教科書從未讓你準備好面對的現象:平靜與混亂是成簇出現的。下跌6%的一天很少是孤立的。它往往處於一整週4-8%的劇烈波動之中,然後市場喘口氣,度過沉悶的1%行情的一個月,直到下一場風暴來臨。收益率本身看起來近乎不可預測——你無法可靠地判斷明天是漲是跌——但它們的幅度卻具有高度可預測性。今天的動盪能告訴你很多關於明天的資訊。
交易者手邊幾乎所有的風險工具都在默默地假設這一點不成立。Black-Scholes用單一常數給期權定價。靜態的風險價值(Value-at-Risk)指標用一個波動率估計值乘以正態分位數。固定3%的止損把一個死氣沉沉的週二和FOMC公告或某交易所脫錨事件前後的幾個小時一視同仁。這些工具都以同樣的方式失效:它們把一個隨時間變化的量塌縮成一個常數,然後在這個常數偏偏動起來的時候大吃一驚。
本文是加密貨幣波動率建模四部曲系列的第一部分。它搭建基礎:GARCH(1,1)模型、為什麼它能很好地擬合加密貨幣收益率、如何用arch庫通過最大似然法誠實地估計它,以及如何將條件方差預測轉化為兩個立即有用的東西——一個倉位規模和一個都能隨市場"呼吸"的止損寬度。第二部分加入非對稱性和厚尾特徵,第三部分轉向多元建模,第四部分組裝完整的波動率目標回測。這裡我們刻意讓應用部分保持簡單;誠實的、經過前向驗證的策略是第四部分的主題。
加密貨幣收益率的典型化事實

在建模任何東西之前,先精確弄清楚我們要復現的是什麼才划算。經驗金融收益率——股票、外匯,尤其是加密貨幣——共享一小組已被記錄了幾十年的穩健統計規律。它們通常被稱為典型化事實(stylized facts),其中三個驅動了後面的一切。
1. 波動率聚集。 大幅波動之後往往跟著大幅波動(不論方向),小幅波動之後往往跟著小幅波動。曼德爾布羅特(Mandelbrot)在1963年研究棉花價格時注意到了這一點。形式上,雖然收益率幾乎不存在序列相關性,但平方收益率(已實現方差的一個代理指標)表現出強烈的、緩慢衰減的正自相關性。
2. 厚尾(尖峰峭度)。 收益率的無條件分佈在極端值處的質量遠多於高斯分佈。正態分佈的峰度為3,而BTC的日對數收益率通常在8-10以上,更高頻的加密貨幣收益率可能更糟。按正態模型的說法,六西格瑪的日子應該大約百萬年才出現一次,但實際上每十年就會出現好幾次。
3. 收益率無線性自相關,平方收益率有強自相關。 這正是區分真正的波動率過程與平凡趨勢的標誌。如果你把對其自身滯後項迴歸,得不到任何可利用的東西。如果你把對其滯後項迴歸,會發現清晰、持久的訊號。這正是一個方差模型應該捕捉的結構——也正是常數模型所丟棄的東西。
我們可以用幾行程式碼目測這三點。這裡不需要特殊的資料來源;生產環境用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,原始收益率的Ljung-Box p值未能拒絕"無自相關"的假設,而平方收益率的p值實際上接近於零。最後這個對比就是全部關鍵所在。在日線級別上,收益率的符號沒有什麼可交易的,但它們的方差中存在大量結構,而且這種結構是可預測的。
關於加密貨幣24/7執行特性的說明:與股票不同,加密貨幣沒有隔夜跳空也沒有周末休市,所以"一天"是一根乾淨的24小時K線,年化係數是,而不是。波動率聚集在日內尺度上也同樣存在,如果你在小時線上執行GARCH,這一點很重要——資金費率翻轉和清算連鎖反應會注入尖銳的、聚集性的方差爆發,而日線模型會把這些抹平。
從ARCH到GARCH

現在問題已經被清晰地提出:對一個不是常數而是依賴於近期歷史的方差建模。第一個正確做到這一點的模型是恩格爾(Engle)的ARCH(自迴歸條件異方差,1982年),這為他贏得了2003年諾貝爾獎。
把收益率寫成條件均值加一個衝擊:
這裡是條件方差——即在已知截至時刻的所有資訊條件下的方差——而是一個標準化的新息(在最簡單的情形下服從標準正態分佈)。"條件"這個詞承載了全部的關鍵:無條件而言方差可能是常數,但以昨天為條件時它會變動。
恩格爾的ARCH()將今天的方差表示為最近個平方衝擊的加權和:
其中、以保證方差為正。這直接捕捉了聚集現象:一個大的衝擊會推高,從而提高再次出現大沖擊的機率,使方差持續保持高位。問題在於經驗上的衰減方式。真實市場中的波動率持續性會跨越很多個滯後期,因此要擬合它,ARCH模型需要很大的——通常是8、10甚至更多——這意味著要估計一個很長、不穩定、容易過擬合的向量。
Bollerslev在1986年的洞見是加入一個用單一參數吸收所有這種持續性的項。GARCH(1,1)——廣義ARCH——的遞迴式為:
三個參數,三種清晰的解釋:
- —— 基線或底線。錨定方差長期水平的常數。方差永遠不會衰減到所支撐的水平以下。
- —— 對新資訊的反應。方差對昨天的意外反應有多劇烈。較大的意味著條件方差跳躍且對沖擊敏感。
- —— 持續性或記憶。昨天的方差有多少會延續到今天。較大的意味著波動率平滑且消退緩慢——平靜保持平靜,風暴保持風暴。
其精妙之處在於這個遞迴本身。因為本身就包含一個項,向後展開可以看出GARCH(1,1)其實是一個ARCH(),對過去平方衝擊的權重呈幾何衰減:
所以單單一個就買到了對過去衝擊的無限、指數加權記憶。這正是為什麼區區一個GARCH(1,1)——三個參數——經常勝過擁有十個參數的ARCH模型,也是它成為應用波動率建模主力工具的原因。事實上,它是RiskMetrics EWMA方差估計器的近親,後者正是、、固定為0.94的特例。GARCH的推廣之處在於讓資料自己選擇、以及一個真正的均值迴歸水平。
性質:平穩性、長期方差與半衰期
GARCH(1,1)遞迴有幾個值得推導的性質,因為正是它們讓你能夠推理這個模型,而不僅僅是盲目地擬合它。
無條件(長期)方差。 假設該過程是協方差平穩的,因此無條件方差存在且隨時間保持不變。對遞迴式兩邊取期望。由於:
這就是波動率均值迴歸所趨向的水平。它只有在時才存在——且才為正。
平穩性條件。 同一個不等式,
正是GARCH(1,1)的協方差平穩性條件。量是方差過程的持續性:它是支配方差衝擊如何衰減回的AR(1)係數。如果,無條件方差為無窮大(或未定義),衝擊永遠不會完全消失。
我們可以顯式地看到均值迴歸。定義方差偏差。對遞迴式做一點代數變換(代入),在期望意義下得到:
當前方差與其長期水平之間的差距,每一步都以的比例收縮。這正是我們後面用到的多步預測。
波動率半衰期。 一個方差衝擊需要多長時間才能衰減到正常水平的一半?令並求解:
對於,半衰期約為13.5天;對於,約為34天;對於,約為69天。這個單一數字通常比原始參數更直觀——它以你所用K線的單位告訴你波動率有多"粘"。
加密貨幣中的近IGARCH問題。 這裡是加密貨幣特有的一個曲折之處。當你把GARCH(1,1)擬合到BTC或ETH的收益率上時,幾乎總會發現非常接近1——0.98、0.99,有時甚至0.995這樣的值都很常見。這就是近IGARCH(整合GARCH)狀態。它帶來實際後果:
- 半衰期變得極長(數週到數月),因此模型會把波動率視為高度持續、幾乎不做均值迴歸。
- 的估計變得極其敏感:從0.99變到0.995這樣一個微小變化,就會使隱含的長期方差翻倍。在這種狀態下,永遠不要在沒有置信區間的情況下相信長期波動率的點估計。
- 多步預測的均值迴歸速度極慢,以至於在幾周以內的實用視野中,GARCH的行為幾乎和方差隨機遊走(這正是EWMA所假設的)一樣。
近整合現象究竟是真實存在的,還是結構性斷點的假象(波動率水平的永久性轉變被模型誤讀為一段長期持續的插曲),這是一個真正存在爭議的問題。這也是為什麼應該在滾動視窗上重新擬合,而不是一次性用全部歷史資料擬合的又一個理由,我們在後面討論陷阱時會再談到這一點。狀態結構問題最好由顯式的切換模型來處理——參見用隱馬爾可夫模型進行狀態檢測,它與GARCH互補而非替代關係。
最大似然估計
GARCH參數通過最大似然法估計。邏輯很直接:給定,該遞迴會產生一整條條件方差路徑,在假設新息服從某分佈的前提下,我們可以寫出觀測到的收益率序列的似然。然後我們選擇使該似然最大化。
假設新息服從高斯分佈,則。單個觀測值的條件密度為
因為模型是以條件形式寫出的,聯合似然可以分解為一系列一步預測密度的乘積,對數似然則是一個簡單的求和:
有兩個結構性事實值得注意。第一,既作為懲罰項出現(——模型因聲稱高方差而受到懲罰),又出現在標準化殘差中(——模型因被"意外"而受到懲罰)。最優解在兩者之間取得平衡,這正是使方差得以追蹤的原因。第二,該遞迴需要一個初始種子;通常的選擇是收益率的樣本方差,在有幾千個觀測值的情況下,這個種子幾乎無關緊要。
極大化沒有解析解,所以我們進行數值最佳化(arch使用帶解析或數值梯度的擬牛頓法)。對於GARCH(1,1)而言,似然曲面通常表現良好,但實踐中有兩點會帶來麻煩:正性約束(),以及當時接近邊界處的行為,此時最佳化器可能爬行得很慢。這兩者都由一個好的庫替你處理好了——你也應該用現成的庫。手寫一個GARCH最大似然估計是個不錯的學習練習,但不是好的生產選擇。
arch庫
Kevin Sheppard開發的arch包是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是滯後方差項的數量(項,即GARCH階數),q是滯後平方殘差項的數量(項,即ARCH階數)。所以p=1, q=1就是我們推導的GARCH(1,1)。(Bollerslev原始的記號將其寫作GARCH(),其中代表ARCH階數——兩種約定的順序是顛倒的。相信庫自己的文件,而不是你的記憶。)
閱讀摘要輸出時,係數表大致如下(這是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狀態。半衰期天。omega= 0.4821,所以長期方差為(百分比平方單位),即長期日波動率,或大約年化。這是一個合理的BTC數字。alpha和beta都高度顯著。alpha相對於beta較小是典型現象:加密貨幣的方差主要來自持續性(記憶),對新衝擊有適度但真實的反應。
×100縮放的坑
這是從arch得到無意義結果的最常見方式,值得單獨開一小節討論。最佳化器在處理數量級為到的數字時表現最好。日對數收益率的數量級是,所以它們的平方是,而則要落在約的數量級——在這個範圍內,數值梯度會失去精度,擬合可能悄悄地無法收斂,或返回垃圾般的標準誤。
解決方法是在放大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能在任意時間跨度上給出清晰的解析預測。
一步預測。 在時刻(樣本末尾)我們已知和,所以下一個方差是確定性的:
不需要求期望——右邊的一切都是已觀測到的。
多步預測。 對於,我們還不知道中間的衝擊,所以要取條件期望。利用(因為),該遞迴塌縮為預測方差上一個簡單的AR(1)形式:
從一步預測開始迭代,可以得到閉式解,這正是我們前面推導出的均值迴歸結果的顯式寫法:
請仔細讀這個式子,因為它是每一次GARCH預測的幾何結構。方差的期限結構從今天的條件方差出發,幾何式地衰減向長期水平。如果今天比平均水平更平靜,預測曲線會向上升;如果今天是危機時刻,它會向下衰減到。這個衰減速度完全由決定——在加密貨幣的近IGARCH狀態下,,衰減速度極慢,以至於在兩週以內的預測視野中,預測值幾乎不會偏離今天的水平。這一點值得牢記:對於短持倉週期,加密貨幣GARCH預測本質上就是"明天看起來和今天差不多,只是非常緩慢地迴歸均值"。
聚合到持倉視野。 交易者很少關心未來某一天的方差。如果你持有一個倉位天,並且收益率在條件上不相關(這是開篇提到的典型化事實),那麼累積天收益率的方差就是逐日預測方差之和:
這才是你真正應該據以確定倉位規模的數字——即你持倉週期內盈虧的波動率。請注意,這絕不是樸素的縮放,後者只有在方差恆定時才成立。當今天的方差高於時,均值迴歸的預測使真實的天波動率低於平方根法則的結果;當今天很平靜時,則高於該結果。搞對這一點,就是一個尊重期限結構的止損和一個不尊重的止損之間的差別。
程式碼實現:
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和偏態分佈,情況就會是這樣)這非常有用。對於上面這些方差線性相關的量,解析路徑是精確且免費的。
診斷:模型真的起作用了嗎?
擬合一個模型不等於驗證它。GARCH的整個意義在於吸收條件異方差——即波動率聚集——使得剩下的部分(接近)獨立同分布。因此正確的檢驗是檢視標準化殘差
並追問:聚集現象消失了嗎?如果模型捕捉到了方差動態,應具有單位方差,而且關鍵是,它們的平方應不再表現出自相關性。我們執行三項檢驗。
1. 標準化殘差上的Ljung-Box檢驗。 檢查水平上是否還殘留線性自相關(這實際上是在檢驗均值模型,而非方差模型)。應不拒絕原假設。
2. 平方標準化殘差上的Ljung-Box檢驗。 這是重要的一項。如果仍存在顯著自相關,說明方差模型未能去除聚集現象——存在GARCH(1,1)未能捕捉的結構,你可能需要更高階模型、非對稱變體,或不同的新息分佈。應不拒絕原假設。
3. ARCH-LM檢驗(恩格爾的拉格朗日乘子檢驗)。 將對其自身滯後項迴歸,檢驗聯合顯著性。它本質上是檢驗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}")
良好的輸出應該是什麼樣子:上的Ljung-Box p值從(原始平方收益率上的)接近零跳升到舒適地高於0.05,並且ARCH-LM檢驗未能拒絕原假設。這就是模型在二階矩上完成了任務的證據。
不完美的輸出——也是你在加密貨幣上使用普通高斯GARCH(1,1)時應該預期看到的情況——是聚集性檢驗通過了,但標準化殘差的峰度仍然偏高(比如4-6而不是0)。GARCH去除了聚集現象,但單一厚尾無條件分佈依然存在,因為高斯新息無法復現尾部特徵。這種殘留的厚尾性不是這裡要修復的缺陷;它正是第二部分的動機所在,參見加密貨幣中的非對稱GARCH與槓桿效應,其中Student-t和偏態t分佈新息以及GJR/EGARCH非對稱項正是用來解決這個問題的。
應用:波動率縮放的倉位規模與止損

現在我們有了明天(以及未來天)波動率的預測。我們該拿它做什麼?兩個最簡單、最有價值的用途是倉位規模和止損設定。這裡我們刻意讓兩者都保持基礎水平——包含全部實際操作細節的完整波動率目標策略是第四部分的內容。
波動率目標倉位規模
其思路是持有一個風險貢獻隨時間大致恆定的倉位,而不是名義規模恆定的倉位。如果你總是投入相同的美元規模,你的風險會在高波動狀態下膨脹,在平靜狀態下萎縮——這恰恰與你想要的相反。波動率目標法則反其道而行之:以固定的目標盈虧波動率為目標,讓預測來決定規模。
對於目標年化波動率(比如20%)和預測年化波動率,倉位權重為
當預測波動率高時,你縮小倉位;當預測波動率低時,你放大倉位。這就是全部機制。因為是預測值——在時刻的收益實現之前,在時刻就已知——所以不存在前視偏差,前提是你在時機把握上足夠嚴謹(關於這一點,後面陷阱部分會詳談)。
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")
這是與真正的資金分配規則一脈相承的近親。波動率目標法回答的是"風險應該隨波動率如何縮放",而凱利準則回答的是"風險應該隨優勢如何縮放"——在一個完整的倉位規模體系中兩者相乘:規模 優勢 / 方差。請注意凱利公式中的方差項正是你剛剛計算出的GARCH預測值,這也是為什麼一個即時波動率模型能夠比靜態歷史估計顯著改善凱利倉位規模。如果你的優勢估計本身帶有已量化的不確定性,保形預測提供了一種不依賴分佈假設的方式來相應地放大或縮小倉位,並且它與波動率目標法能夠乾淨地組合使用。
上限w_max不是可選項。在近IGARCH狀態下,一段平靜期可能會把預測波動率壓得很低,此時會要求一個理論上很好、但一旦平靜破裂就會很致命的槓桿水平——而根據波動率聚集現象,平靜遲早會破裂,往往還很突然。給槓桿設上限是一種粗糙但有效的做法,承認你的預測只是一個條件均值,而不是保證,而且犯錯的代價是不對稱的。這種不對稱性——賬戶爆倉無法靠一次對稱的盈利來挽回——正是虧損與盈利的不對稱性,它應當讓你係統性地比一個只考慮方差的規則更保守。
波動率縮放止損
固定百分比止損和固定倉位規模患有同一種病:3%的止損在平靜市場中是一觸即發的敏感開關,在劇烈波動市場中卻是舍入誤差。它會在高波動狀態下讓你被普通噪音震出好倉位,而在狀態轉換期又回吐太多利潤。解決方法是以預測波動率為單位設定止損距離。
其中是你預期持倉視野上的預測波動率(即預測一節中得到的聚合量),是一個倍數——通常在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}")
因為使用的是均值迴歸的期限結構預測而不是一個扁平的歷史數字,止損會在進入動盪狀態時自動放寬,在波動率消退時自動收緊——期限結構替你完成了這種自適應。這裡驅動倉位規模和止損的是同一個預測,這是一個特性而非巧合:在高波動狀態下,你同時持有更小的倉位,並給這個倉位更多的空間,兩種效應疊加在一起,大幅降低了尾部風險。倉位規模和止損是同一個波動率視角的兩種投影,而不是兩個獨立的旋鈕。
第一部分的應用探討到此為止。一個真正的策略還必須處理頻繁再平衡帶來的交易成本、預測計算時刻與交易執行時刻之間的時機問題、換手率控制,以及最重要的——誠實的樣本外評估。所有這些都在第四部分:波動率目標GARCH策略中,我們會在那裡構建並進行前向測試完整流程。
陷阱
GARCH容易擬合,也容易讓人自我欺騙。失敗模式相當一致。
收益率縮放。 前面已經講過,但它是頭號bug,值得再強調一次:在放大100倍的收益率上擬合arch,並把每一個輸出都反縮放(方差除以,波動率除以)。這裡一個悄無聲息的100倍錯誤,會汙染後續每一個倉位規模和止損計算。
擬閤中的前視偏差。 這是最隱蔽的殺手。如果你在全部歷史資料上擬合模型,然後在同一段歷史上計算"預測",那麼每一次預測都偷偷看到了未來——參數是用預測日之後的資料估計出來的。樣本內擬合看起來會很漂亮,但實盤表現會完全不像它。每一次回測預測都必須來自一個僅用該時刻可獲得資料擬合的模型:在一個擴充或滾動視窗上重新擬合,預測一步,向前滾動。這一點不容商量,也正是前向最佳化這篇文章的全部主題。樣本內GARCH和真正前向驗證的GARCH之間的差距,就是演示樣品和一個能在實盤市場中存活下來的系統之間的差距——另見回測-實盤一致性。
預測的時機問題。 與前一點相關但不同。第天的預測必須從第天收盤(或者你的K線收盤時刻)可獲得的資訊中計算出來,而且倉位必須能以你實際能拿到的價格執行。用第天的收盤價計算預測,然後在第天的開盤價"交易",這是一種前視偏差,會悄悄地虛增每一個結果。
高階模型的過擬合。 GARCH(1,1)幾乎總是夠用的。因為GARCH(2,2)或GARCH(3,1)能把樣本內對數似然略微推高一點就去擬合它,這種誘惑通常是在擬合噪音;額外的參數很少能改善樣本外預測,反而經常讓最佳化器在邊界附近變得不穩定。優先選擇簡約模型,如果必須比較不同階數,應通過前向切分上的樣本外預測損失來比較,而不是用樣本內AIC。當殘差診斷仍顯示問題時,通常應該改進的是新息分佈或加入非對稱項(第二部分內容),而不是提高階數。
結構性斷點被誤讀為持續性。 如前所述,波動率水平的永久性轉變(新的市場狀態、市場微觀結構的變化)可能被GARCH吸收為虛假的高持續性,把推向1。如果你的長期波動率估計在不同視窗間顯得不穩定,應懷疑存在斷點,而不是相信近IGARCH的點估計。滾動重新擬合,以及在適當情況下使用顯式的狀態模型,可以防範這一點。
把波動率預測當作收益率預測。 GARCH預測的是波動的幅度,而不是方向。它告訴你明天的波動可能有多大,而不是往哪個方向。這正是為什麼它的天然用武之地是風險管理——倉位規模、止損、VaR——而不是訊號生成。不要把一個良好的方差預測誤認為是優勢(edge)。
後續走向
GARCH(1,1)是基礎,而且它刻意保持不完整。本系列在三個方向上對它加以擴充:
- 非對稱性與厚尾 —— 真實的加密貨幣波動率對下跌行情的反應比對上漲行情更強烈(槓桿效應),而高斯新息無法復現尾部特徵。GJR-GARCH、EGARCH以及Student-t/偏態t新息在第二部分中討論。
- 多元波動率 —— 加密貨幣資產之間的相關性本身也是隨時間變化的,並且在崩盤中會飆升。對整個協方差矩陣進行動態建模是第三部分:DCC-GARCH的內容,它與Markowitz均值方差理論以及一旦協方差變為動態後的基於CVaR的資產配置直接相連。
- 完整策略 —— 倉位規模、止損、成本、換手率,以及誠實的前向評估,都匯聚在第四部分中。
以及GARCH邊際分佈如何匯入聯合風險:這裡的單變數條件方差模型正是GARCH-EVT-copula組合投資組合VaR/CVaR流程的第一階段。一旦你從逐資產GARCH擬閤中得到標準化殘差,你就對它們做變換,再用copula把它們粘合在一起——邊際分佈是GARCH給出的,依賴結構是copula給出的。這一構造,包括尾部依賴和EVT尾部處理,在加密貨幣聯合風險的copula模型一文中有深入介紹;本文正是支撐它的單變數引擎。
總結
- 加密貨幣收益率表現出波動率聚集、厚尾,以及收益率無自相關但平方收益率有強自相關的特徵。任何假設波動率恆定的工具——單一的Black-Scholes、靜態VaR、固定百分比止損——都與這些事實不相符。
- GARCH(1,1),,用三個參數對隨時間變化的條件方差建模:基線、衝擊反應、持續性。它是一個具有幾何衰減記憶的ARCH(),這正是它優於高階ARCH的原因。
- 平穩性要求;長期方差為,持續性為,波動率半衰期為。加密貨幣處於近IGARCH狀態():高度持續、均值迴歸緩慢,且長期方差估計脆弱。
- 用最大似然法估計。 高斯對數似然是一系列一步密度之和;用
arch_model(r*100, vol="Garch", p=1, q=1)擬合它。記住**×100縮放**,並一致地反縮放每一個輸出。 - 預測以的速率幾何式地均值迴歸到長期方差。將逐日方差預測聚合起來得到持倉視野波動率——而不是用樸素的法則。
- 用平方標準化殘差上的Ljung-Box檢驗和ARCH-LM檢驗來驗證。 通過這些檢驗證實聚集現象已被建模消除;殘留的厚尾特徵則是第二部分的動機所在。
- 將其應用於波動率目標倉位規模(,帶上限)和波動率縮放止損()。同一個預測同時驅動兩者,所以高波動狀態下倉位會同時變小且止損同時放寬。
- 重要的陷阱:收益率縮放、擬閤中的前視偏差(只在過去資料上擬合,始終前向驗證)、預測時機、階數過高,以及永遠不要把方差預測誤認為方向預測。
References:
- 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
量化研究與策略