GARCH(1,1): Prognose der Krypto-Volatilität
Öffnet man ein Chart der täglichen BTC-Renditen, fällt etwas auf, worauf einen die Lehrbücher zum Random Walk nie vorbereitet haben: Ruhe und Chaos treten in Clustern auf. Ein Tag mit 6% Verlust steht selten allein. Er sitzt inmitten einer Woche mit Schwankungen von 4-8%, dann atmet der Markt aus und driftet einen Monat lang durch schläfrige 1%-Sitzungen, bevor der nächste Sturm kommt. Die Renditen selbst wirken nahezu unvorhersagbar — man kann kaum verlässlich sagen, ob es morgen aufwärts oder abwärts geht — aber ihre Größenordnung ist zutiefst vorhersagbar. Die heutige Turbulenz sagt viel über die morgige aus.
Fast jedes Risikowerkzeug, das ein Trader zur Hand nimmt, geht stillschweigend davon aus, dass dies nicht zutrifft. Black-Scholes bepreist eine Option mit einem einzigen konstanten . Eine statische Value-at-Risk-Zahl multipliziert eine Volatilitätsschätzung mit einem Normalverteilungsquantil. Ein fester 3%-Stop-Loss behandelt einen toten Seitwärts-Dienstag und die Stunden rund um eine FOMC-Veröffentlichung oder ein größeres Börsen-De-Peg, als trügen sie das gleiche Risiko. Jedes dieser Werkzeuge scheitert auf dieselbe Weise: Es kollabiert eine zeitveränderliche Größe zu einer Konstanten und wird dann überrascht, wenn sich die Konstante doch bewegt.
Dieser Artikel ist Teil 1 einer vierteiligen Serie zur Volatilitätsmodellierung im Kryptobereich. Er legt das Fundament: das GARCH(1,1)-Modell, warum es so gut zu Krypto-Renditen passt, wie man es ehrlich per Maximum-Likelihood mit der Bibliothek arch schätzt, und wie man eine Prognose der bedingten Varianz in zwei sofort nützliche Dinge verwandelt — eine Positionsgröße und eine Stop-Breite, die beide mit dem Markt atmen. Teil 2 fügt Asymmetrie und fette Tails hinzu, Teil 3 wird multivariat, und Teil 4 setzt das vollständige Volatility-Targeting-Backtest zusammen. Die Anwendung hier halten wir bewusst einfach; die ehrlich per Walk-Forward validierte Strategie ist Gegenstand von Teil 4.
Die stilisierten Fakten der Krypto-Renditen
Bevor man irgendetwas modelliert, lohnt es sich, präzise zu sein, was man eigentlich reproduzieren will. Empirische Finanzrenditen — Aktien, Devisen und besonders Krypto — teilen eine kleine Menge robuster statistischer Regelmäßigkeiten, die seit Jahrzehnten dokumentiert sind. Man nennt sie üblicherweise stilisierte Fakten, und drei davon bestimmen alles Folgende.
1. Volatilitätsclustering. Große Bewegungen folgen tendenziell auf große Bewegungen (beiderlei Vorzeichens), kleine auf kleine. Mandelbrot bemerkte dies 1963 bei Baumwollpreisen. Formal gilt: Während die Renditen nahezu seriell unkorreliert sind, zeigen die quadrierten Renditen (ein Proxy für die realisierte Varianz) eine starke, langsam abklingende positive Autokorrelation.
2. Fette Tails (Leptokurtosis). Die unbedingte Verteilung der Renditen hat weit mehr Masse in den Extremen als eine Gaußverteilung. Während eine Normalverteilung eine Kurtosis von 3 hat, liegen die täglichen Log-Renditen von BTC routinemäßig über 8-10, und höherfrequente Krypto-Renditen können noch schlechter sein. Sechs-Sigma-Tage, die laut einem Normalverteilungsmodell etwa einmal pro Million Jahre auftreten sollten, kommen mehrmals pro Jahrzehnt vor.
3. Keine lineare Autokorrelation in den Renditen, starke Autokorrelation in den quadrierten Renditen. Das ist der Fingerabdruck, der einen echten Volatilitätsprozess von einem trivialen Trend unterscheidet. Regressiert man auf seine eigenen Lags, erhält man nichts Verwertbares. Regressiert man auf seine Lags, findet man ein klares, anhaltendes Signal. Genau diese Struktur soll ein Varianzmodell erfassen — und genau das wirft ein Modell mit konstantem weg.
Alle drei lassen sich mit ein paar Zeilen Code überprüfen. Dafür braucht man keine spezielle Datenquelle; in der Produktion nutzt man ccxt, für ein reproduzierbares Snippet reicht aber 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]))
Das typische Ergebnis (illustrativ — euer Zeitfenster wird abweichen): eine Exzess-Kurtosis deutlich über 3, ein Ljung-Box-p-Wert für die Rohrenditen, der "keine Autokorrelation" nicht verwirft, und ein p-Wert für die quadrierten Renditen, der praktisch null ist. Dieser letzte Kontrast ist das ganze Spiel. Es gibt beim täglichen Horizont nichts zu handeln im Vorzeichen der Renditen, aber es gibt sehr viel Struktur in ihrer Varianz, und diese Struktur ist prognostizierbar.
Eine Anmerkung zur 24/7-Natur von Krypto. Anders als bei Aktien gibt es keine Overnight-Lücke und keinen Wochenendschluss, sodass der "Tag" ein sauberer 24-Stunden-Balken ist und der Annualisierungsfaktor ist, nicht . Volatilitätsclustering überlebt auch auf Intraday-Skalen, was relevant ist, wenn man GARCH auf Stundenkerzen anwendet — Funding-Rate-Wechsel und Liquidationskaskaden erzeugen scharfe, geclusterte Varianzausbrüche, die ein Tagesmodell glättet.
Von ARCH zu GARCH
Das Problem ist nun scharf formuliert: eine Varianz modellieren, die nicht konstant ist, sondern von der jüngeren Vergangenheit abhängt. Das erste Modell, das dies sauber leistete, war Engles ARCH (Autoregressive Conditional Heteroskedasticity, 1982), wofür er 2003 den Nobelpreis erhielt.
Man schreibt die Rendite als bedingten Mittelwert plus Schock:
Hier ist die bedingte Varianz — die Varianz von gegeben allem, was bis zum Zeitpunkt bekannt ist — und ist eine standardisierte Innovation (im einfachsten Fall standardnormalverteilt). Das Wort "bedingt" leistet die ganze Arbeit: unbedingt mag die Varianz konstant sein, aber bedingt auf gestern bewegt sie sich.
Engles ARCH() macht die heutige Varianz zu einer gewichteten Summe der letzten quadrierten Schocks:
mit und , um die Varianz positiv zu halten. Das erfasst Clustering direkt: Ein großer Schock treibt nach oben, was die Wahrscheinlichkeit eines weiteren großen Schocks erhöht, was die Varianz erhöht hält. Das Problem ist der empirische Abklingprozess. Die Volatilitätspersistenz in realen Märkten erstreckt sich über viele Lags, sodass ein ARCH-Modell zur Anpassung ein großes braucht — oft 8, 10 oder mehr — und das bedeutet, einen langen, instabilen Vektor von zu schätzen, der zum Overfitting neigt.
Bollerslevs Einsicht von 1986 war, einen Term hinzuzufügen, der die gesamte Persistenz mit einem einzigen Parameter aufsaugt. Die GARCH(1,1)-Rekursion — Generalized ARCH — lautet:
Drei Parameter, drei klare Interpretationen:
- — die Basislinie oder der Boden. Eine Konstante, die das langfristige Niveau der Varianz verankert. Die Varianz sinkt nie unter das, was trägt.
- — die Reaktion auf Nachrichten. Wie heftig die Varianz auf die gestrige Überraschung reagiert. Ein großes bedeutet, dass die bedingte Varianz sprunghaft und schockempfindlich ist.
- — die Persistenz oder das Gedächtnis. Wie viel von der gestrigen Varianz sich in den heutigen Tag überträgt. Ein großes bedeutet, dass die Volatilität glatt und langsam abklingt — Ruhe bleibt ruhig, Stürme bleiben stürmisch.
Die Eleganz liegt in der Rekursion. Da selbst einen -Term enthielt, zeigt das rückwärtige Ausrollen, dass GARCH(1,1) ein ARCH() mit geometrisch abklingenden Gewichten auf vergangene quadrierte Schocks ist:
Also erkauft das einzelne ein unendliches, exponentiell gewichtetes Gedächtnis vergangener Schocks. Deshalb schlägt ein bloßes GARCH(1,1) — drei Parameter — routinemäßig ARCH-Modelle mit zehn, und deshalb wurde es zum Arbeitspferd der angewandten Volatilitätsmodellierung. Es ist tatsächlich ein naher Verwandter des RiskMetrics-EWMA-Varianzschätzers, der den Spezialfall , mit fest auf 0,94 gesetztem darstellt. GARCH verallgemeinert dies, indem es die Daten , und ein echtes Mean-Reversion-Niveau wählen lässt.
Eigenschaften: Stationarität, langfristige Varianz und Halbwertszeit
Die GARCH(1,1)-Rekursion hat einige Eigenschaften, die es sich herzuleiten lohnt, denn sie erlauben es, über das Modell nachzudenken, statt es nur blind anzupassen.
Unbedingte (langfristige) Varianz. Angenommen, der Prozess ist kovarianzstationär, sodass die unbedingte Varianz existiert und über die Zeit konstant ist. Man bildet den Erwartungswert beider Seiten der Rekursion. Da :
Das ist das Niveau, zu dem die Volatilität mean-revertiert. Es existiert — und ist nur positiv — wenn .
Stationaritätsbedingung. Dieselbe Ungleichung,
ist die Kovarianzstationaritätsbedingung für GARCH(1,1). Die Größe ist die Persistenz des Varianzprozesses: Sie ist der AR(1)-Koeffizient, der bestimmt, wie ein Varianzschock zurück zu abklingt. Ist , ist die unbedingte Varianz unendlich (oder undefiniert), und Schocks sterben nie vollständig aus.
Man kann die Mean-Reversion explizit sehen. Man definiert die Varianzabweichung . Etwas Algebra an der Rekursion (mit Einsetzen von ) ergibt im Erwartungswert:
Die Lücke zwischen der aktuellen Varianz und ihrem langfristigen Niveau schrumpft bei jedem Schritt um den Faktor . Das ist genau die Mehrschritt-Prognose, die wir später verwenden.
Volatilitäts-Halbwertszeit. Wie lange dauert es, bis ein Varianzschock zur Hälfte auf den Normalzustand zurückgeklungen ist? Man setzt und löst:
Für beträgt die Halbwertszeit etwa 13,5 Tage; für etwa 34 Tage; für etwa 69 Tage. Diese einzelne Zahl ist oft intuitiver als die rohen Parameter — sie sagt euch, in den Einheiten eurer Kerzen, wie klebrig die Volatilität ist.
Das Near-IGARCH-Problem bei Krypto. Hier ist die krypto-spezifische Besonderheit. Passt man GARCH(1,1) an BTC- oder ETH-Renditen an, findet man fast immer sehr nahe an 1 — Werte von 0,98, 0,99, manchmal 0,995 sind üblich. Das ist das Near-IGARCH-Regime (Integrated GARCH). Es hat reale Konsequenzen:
- Die Halbwertszeit wird enorm (Wochen bis Monate), sodass das Modell die Volatilität als sehr persistent und kaum mean-revertierend behandelt.
- Die Schätzung von wird extrem empfindlich: Eine kleine Änderung von von 0,99 auf 0,995 verdoppelt die implizite langfristige Varianz. In diesem Regime sollte man niemals der Punktschätzung der langfristigen Volatilität ohne Konfidenzintervall trauen.
- Mehrschritt-Prognosen mean-revertieren so langsam, dass GARCH für praktische Horizonte unter ein paar Wochen sich fast wie ein Random Walk in der Varianz verhält (was EWMA annimmt).
Ob die Near-Integration echt ist oder ein Artefakt struktureller Brüche (eine dauerhafte Verschiebung des Volatilitätsniveaus, die das Modell als eine lange, persistente Episode liest), ist eine reale Debatte. Das ist ein weiterer Grund, auf rollierenden Fenstern neu zu schätzen statt einmal auf der gesamten Historie, ein Punkt, auf den wir bei den Fallstricken zurückkommen. Regimestruktur speziell wird besser durch ein explizites Switching-Modell behandelt — siehe Regimeerkennung mit Hidden-Markov-Modellen, das GARCH ergänzt, statt es zu ersetzen.
Schätzung per Maximum Likelihood
GARCH-Parameter werden per Maximum Likelihood geschätzt. Die Logik ist direkt: Gegeben , erzeugt die Rekursion einen vollständigen Pfad bedingter Varianzen , und unter einer angenommenen Verteilung der Innovationen können wir aufschreiben, wie wahrscheinlich die beobachteten Renditen sind. Dann wählen wir so, dass diese Likelihood maximiert wird.
Bei angenommenen Gauß'schen Innovationen gilt . Die bedingte Dichte einer Beobachtung ist
Weil das Modell bedingt formuliert ist, faktorisiert die gemeinsame Likelihood in ein Produkt von Ein-Schritt-Dichten, und die Log-Likelihood ist eine schlichte Summe:
Zwei strukturelle Tatsachen sind zu beachten. Erstens erscheint sowohl als Strafterm ( — das Modell wird bestraft, wenn es hohe Varianz behauptet) als auch im standardisierten Residuum ( — das Modell wird bestraft, wenn es überrascht wird). Das Optimum balanciert beide aus, und genau das lässt die Varianz mitverfolgen. Zweitens braucht die Rekursion einen Startwert ; die übliche Wahl ist die Stichprobenvarianz der Renditen, und bei ein paar tausend Beobachtungen spielt der Startwert kaum eine Rolle.
Es gibt keine geschlossene Form für das Maximum, daher wird numerisch optimiert (arch nutzt ein Quasi-Newton-Verfahren mit analytischen oder numerischen Gradienten). Die Likelihood-Fläche verhält sich für GARCH(1,1) im Allgemeinen gutartig, aber zwei Dinge machen in der Praxis Probleme: die Positivitätsbeschränkungen () und das Verhalten nahe der Grenze, wenn , wo der Optimierer nur langsam vorankommt. Beides wird von einer guten Bibliothek für euch gehandhabt — und ihr solltet eine verwenden. Eine GARCH-MLE von Hand zu bauen ist eine gute Lernübung, aber eine schlechte Wahl für die Produktion.
Die Bibliothek arch
Das Paket arch von Kevin Sheppard ist das Standardwerkzeug in Python. Die gesamte Anpassung besteht aus vier Zeilen.
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())
Ein Wort zu den Argumentnamen, da sie eine häufige Verwirrungsquelle sind. In arch ist p die Anzahl der gelaggten Varianzen (-Terme, die GARCH-Ordnung) und q die Anzahl der gelaggten quadrierten Residuen (-Terme, die ARCH-Ordnung). Also ist p=1, q=1 das GARCH(1,1), das wir hergeleitet haben. (Bollerslevs ursprüngliche Notation schreibt es als GARCH() mit für die ARCH-Ordnung — die beiden Konventionen sind vertauscht. Vertraut der Dokumentation der Bibliothek, nicht eurem Gedächtnis.)
Liest man die Zusammenfassung, sieht die Koeffiziententabelle ungefähr so aus (illustrative Werte für tägliche BTC-Renditen, kein echtes Experiment):
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
==========================================================
So liest man es:
alpha[1] + beta[1]= 0,0912 + 0,8994 = 0,9906. Persistenz knapp unter 1 — das Near-IGARCH-Regime, genau wie gewarnt. Halbwertszeit Tage.omega= 0,4821, sodass die langfristige Varianz in Prozent-Quadrat-Einheiten ist, d.h. eine langfristige tägliche Volatilität von , oder ungefähr annualisiert. Das ist ein plausibler BTC-Wert.- Sowohl
alphaals auchbetasind stark signifikant. Dassalphaim Vergleich zubetaklein ist, ist typisch: Krypto-Varianz besteht überwiegend aus Persistenz (Gedächtnis), mit einer moderaten, aber echten Reaktion auf frische Schocks.
Die ×100-Skalierungsfalle
Das ist der mit Abstand häufigste Weg, aus arch Unsinn herauszubekommen, daher verdient es einen eigenen Abschnitt. Der Optimierer funktioniert am besten, wenn die Zahlen, die er sieht, bis groß sind. Tägliche Log-Renditen sind , ihre Quadrate also , und liegt bei etwa — in einem Bereich, in dem numerische Gradienten an Präzision verlieren und die Anpassung stillschweigend nicht konvergieren oder Standardfehler von Müllqualität liefern kann.
Die Lösung ist, auf mit 100 skalierten Renditen zu fitten (d.h. in Prozent), wie oben gezeigt. arch gibt sogar eine DataScaleWarning aus, wenn man das vergisst. Alles, was man aus dem Modell ausliest, ist dann in Prozent- oder Prozent-Quadrat-Einheiten, und man muss konsistent zurückskalieren:
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%}")
Skalierte und unskalierte Größen zu mischen — etwa eine Prozentvolatilität in eine Positionsgrößenformel einzuspeisen, die Dezimalwerte erwartet — erzeugt Fehler von genau 100x, die leicht zu übersehen sind, weil der Code anstandslos läuft. Man wählt eine Konvention (ich halte außerhalb der Anpassung alles dezimal und skaliere nur an der arch-Grenze) und überschreitet sie nie.
Prognose der bedingten Varianz
Ein angepasstes Modell ist nur nützlich, wenn es prognostiziert. GARCH liefert saubere, analytische Prognosen für jeden Horizont.
Ein Schritt voraus. Zum Zeitpunkt (dem Ende der Stichprobe) kennen wir und , sodass die nächste Varianz deterministisch ist:
Kein Erwartungswert nötig — alles auf der rechten Seite ist beobachtet.
Mehrere Schritte voraus. Für kennen wir die dazwischenliegenden Schocks noch nicht, also bilden wir bedingte Erwartungswerte. Mit (weil ) kollabiert die Rekursion zu einem einfachen AR(1) in der prognostizierten Varianz:
Iteriert man dies von der Ein-Schritt-Prognose aus, ergibt sich die geschlossene Form, die genau das Mean-Reversion-Resultat ist, das wir zuvor hergeleitet haben, nun explizit ausgeschrieben:
Das sollte man sorgfältig lesen, denn es ist die Geometrie jeder GARCH-Prognose. Die Laufzeitstruktur der Varianz beginnt bei der heutigen bedingten Varianz und klingt geometrisch zum langfristigen Niveau ab. Ist heute ruhiger als der Durchschnitt, steigt die Prognosekurve zu an; ist heute eine Krise, fällt sie dorthin ab. Die Geschwindigkeit dieses Abklingens wird vollständig durch bestimmt — und im Near-IGARCH-Krypto-Regime, wo , ist das Abklingen so langsam, dass sich die Prognose für Horizonte unter etwa zwei Wochen kaum vom heutigen Niveau wegbewegt. Das sollte man verinnerlichen: Für kurze Haltedauern besagt die Krypto-GARCH-Prognose im Wesentlichen "morgen sieht aus wie heute, nur sehr langsam zurückkehrend".
Aggregation auf einen Haltehorizont. Trader interessieren sich selten für die Varianz eines einzelnen zukünftigen Tages. Hält man eine Position für Tage und sind die Renditen bedingt unkorreliert (die stilisierte Tatsache vom Anfang), ist die Varianz der kumulativen -Tage-Rendite die Summe der Ein-Tages-Prognosevarianzen:
Das ist die Zahl, auf die man tatsächlich seine Position bemisst — die Volatilität des P&L über die Haltedauer. Beachtet, dass dies ausdrücklich nicht die naive -Skalierung ist, die nur bei konstanter Varianz korrekt ist. Liegt die heutige Varianz über , macht die mean-revertierende Prognose die wahre -Tage-Vol niedriger als die Wurzel-Regel; ist heute ruhig, ist sie höher. Das richtig hinzubekommen, ist der Unterschied zwischen einem Stop, der die Laufzeitstruktur respektiert, und einem, der es nicht tut.
Im Code:
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%}")
Für längere Horizonte unterstützt GARCH auch Simulations-Prognosen (method="simulation"), die die Innovationsverteilung nach vorne propagieren und die vollständige Prognosedichte liefern, nicht nur ihre Varianz — nützlich, wenn die Innovationen nicht-gaußisch sind, wie es der Fall sein wird, sobald wir in Teil 2 zu Student-t- und schiefen Verteilungen übergehen. Für die oben genannten linear-in-der-Varianz-Größen ist der analytische Pfad exakt und kostenlos.
Diagnostik: Hat das Modell tatsächlich funktioniert?
Ein Modell anzupassen ist nicht dasselbe wie es zu validieren. Der ganze Sinn von GARCH ist es, die bedingte Heteroskedastizität — das Volatilitätsclustering — zu absorbieren, sodass übrig bleibt, was (nahezu) i.i.d. ist. Die richtige Prüfung besteht daher darin, die standardisierten Residuen
zu betrachten und zu fragen: Ist das Clustering verschwunden? Hat das Modell die Varianzdynamik erfasst, sollten die Einheitsvarianz haben, und, entscheidend, ihre Quadrate sollten keine verbleibende Autokorrelation zeigen. Wir führen drei Tests durch.
1. Ljung-Box auf standardisierte Residuen. Prüft, dass keine lineare Autokorrelation im Niveau von verbleibt (dies testet eigentlich das Mittelwertmodell, nicht das Varianzmodell). Sollte nicht verworfen werden.
2. Ljung-Box auf quadrierte standardisierte Residuen. Das ist der wichtige Test. Wenn noch signifikante Autokorrelation aufweist, hat das Varianzmodell das Clustering nicht vollständig entfernt — es gibt Struktur, die GARCH(1,1) nicht erfasst hat, und man braucht möglicherweise eine höhere Ordnung, eine asymmetrische Variante oder eine andere Innovationsverteilung. Sollte nicht verworfen werden.
3. ARCH-LM-Test (Engles Lagrange-Multiplikator-Test). Regressiert auf seine eigenen Lags und testet auf gemeinsame Signifikanz. Das ist im Wesentlichen eine formale Version von Test 2 und fragt direkt "gibt es noch einen ARCH-Effekt übrig?". Ein nicht signifikantes Ergebnis bestätigt, dass die bedingte Heteroskedastizität weggemodelliert wurde.
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}")
So sieht ein gutes Ergebnis aus: Die Ljung-Box-p-Werte für springen von nahe null (bei den rohen quadrierten Renditen) auf komfortabel über 0,05, und der ARCH-LM-Test verwirft nicht. Das ist der Beleg, dass das Modell seine Aufgabe beim zweiten Moment erfüllt hat.
So sieht ein unvollkommenes Ergebnis aus — und das sollte man bei einem einfachen Gauß'schen GARCH(1,1) auf Krypto-Daten erwarten —: Die Clustering-Tests bestehen, aber die Kurtosis der standardisierten Residuen ist immer noch erhöht (sagen wir 4-6 statt 0). GARCH entfernt das Clustering, aber eine einzelne fettschwänzige unbedingte Verteilung bleibt bestehen, weil Gauß'sche Innovationen die Tails nicht reproduzieren können. Diese verbleibende Fettschwänzigkeit ist kein hier zu behebender Fehler; sie ist die Motivation für Teil 2, asymmetrisches GARCH und der Leverage-Effekt bei Krypto, wo Student-t- und schiefe-t-Innovationen sowie der GJR/EGARCH-Asymmetrieterm genau dies adressieren.
Anwendung: Volatilitätsskaliertes Sizing und Stops
Wir haben nun eine Prognose der morgigen (und der nächsten Tage) Volatilität. Was macht man damit? Die zwei einfachsten, wertvollsten Anwendungen sind Positionsgröße und Stop-Platzierung. Wir halten beide hier bewusst einfach — die vollständige Vol-Targeting-Strategie mit ihrer gesamten praktischen Maschinerie ist Teil 4.
Volatilitätsgezieltes Positions-Sizing
Die Idee ist, eine Position zu halten, deren Risikobeitrag über die Zeit ungefähr konstant bleibt, statt einer Position mit konstantem Nominalwert. Setzt man immer die gleiche Dollargröße ein, bläht sich das Risiko in Hochvolatilitätsregimen auf und schrumpft in ruhigen — das Gegenteil dessen, was man will. Volatility Targeting kehrt dies um: Man zielt auf eine feste Zielvolatilität des P&L und lässt die Prognose die Größe bestimmen.
Für eine annualisierte Zielvolatilität (z.B. 20%) und eine prognostizierte annualisierte Volatilität ist das Positionsgewicht
Ist die prognostizierte Volatilität hoch, skaliert man herunter; ist sie niedrig, skaliert man hinauf. Das ist der gesamte Mechanismus. Da prognostiziert ist — bekannt zum Zeitpunkt , bevor die Rendite zum Zeitpunkt realisiert wird —, gibt es keinen Blick in die Zukunft, sofern man beim Timing diszipliniert vorgeht (mehr dazu bei den Fallstricken).
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")
Das ist ein enger Verwandter echter Kapitalallokationsregeln. Volatility Targeting beantwortet "wie stark sollte das Risiko mit der Volatilität skalieren", während das Kelly-Kriterium beantwortet "wie stark sollte das Risiko mit dem Edge skalieren" — und die beiden multiplizieren sich in einem vollständigen Sizing-Stack: Größe Edge / Varianz. Beachtet, dass Kellys Varianzterm genau die gerade berechnete GARCH-Prognose ist, weshalb ein live laufendes Volatilitätsmodell das Kelly-Sizing gegenüber einer statischen historischen Schätzung deutlich schärft. Trägt die eigene Edge-Schätzung selbst quantifizierte Unsicherheit, bietet konforme Prädiktion einen verteilungsfreien Weg, die Größe entsprechend zu vergrößern oder zu verkleinern, und lässt sich sauber mit Vol Targeting kombinieren.
Die Obergrenze w_max ist nicht optional. Im Near-IGARCH-Regime kann eine ruhige Phase die prognostizierte Vol recht niedrig drücken, und verlangt dann einen Hebel, der auf dem Papier gut aussieht und ruinös ist, sobald die Ruhe bricht — was, gemäß Volatilitätsclustering, irgendwann geschieht, oft abrupt. Die Hebelbegrenzung ist die grobe, aber wirksame Anerkennung, dass die eigene Prognose ein bedingter Mittelwert ist, keine Garantie, und dass die Auszahlung bei einem Fehler asymmetrisch ist. Diese Asymmetrie — ein gesprengtes Konto lässt sich nicht durch einen symmetrischen Gewinn wiederherstellen — ist genau die Asymmetrie zwischen Verlust und Gewinn, die einen systematisch konservativer machen sollte, als es eine reine Varianzregel nahelegt.
Volatilitätsskalierte Stops
Ein fester prozentualer Stop leidet an derselben Krankheit wie eine feste Positionsgröße: Ein 3%-Stop ist in einem ruhigen Markt ein Haarauslöser und in einem heftigen ein Rundungsfehler. Er wirft einen bei normalem Rauschen während Hochvolatilitätsregimen aus guten Positionen und gibt bei Übergängen viel zu viel zurück. Die Lösung besteht darin, die Stop-Distanz in Einheiten der prognostizierten Volatilität festzulegen.
wobei die prognostizierte Volatilität über den erwarteten Haltehorizont ist (die aggregierte Größe aus dem Prognoseabschnitt) und ein Multiplikator — typischerweise 1,5 bis 3 —, gewählt so, dass der Stop außerhalb normaler Schwankungen, aber innerhalb einer echten Gegenbewegung liegt.
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}")
Weil die mean-revertierende Laufzeitstruktur-Prognose statt einer flachen historischen Zahl verwendet, weitet sich der Stop automatisch, wenn turbulente Regimes bevorstehen, und zieht sich zusammen, wenn die Volatilität nachlässt — die Laufzeitstruktur übernimmt die Anpassung für einen. Das ist dieselbe Prognose, die sowohl die Größe als auch den Stop speist, und das ist ein Feature: In einem Hochvolatilitätsregime hält man gleichzeitig weniger und gibt der Position mehr Raum, und die beiden Effekte summieren sich zu einem deutlich niedrigeren Tail-Risiko. Sizing und Stops sind zwei Projektionen einer einzigen Volatilitätssicht, nicht zwei unabhängige Regler.
So weit treiben wir die Anwendung in Teil 1. Eine echte Strategie muss Transaktionskosten durch ständiges Rebalancing, das Timing zwischen der Berechnung der Prognose und der Ausführung des Trades, Turnover-Kontrolle und — vor allem — ehrliche Out-of-Sample-Evaluierung handhaben. All das ist Teil 4: die Volatility-Targeting-GARCH-Strategie, wo wir das Ganze bauen und per Walk-Forward testen.
Fallstricke
GARCH ist leicht anzupassen und leicht, sich damit selbst zu täuschen. Die Fehlermodi sind konsistent.
Renditenskalierung. Oben behandelt, aber es ist Bug Nummer eins, daher wiederholen wir es: arch an Renditen × 100 anpassen und jede Ausgabe zurückskalieren (Varianz durch , Volatilität durch ). Ein stiller 100x-Fehler hier vergiftet jede nachgelagerte Sizing- und Stop-Berechnung.
Blick in die Zukunft bei der Anpassung. Der subtile Killer. Passt man das Modell an die gesamte Historie an und berechnet dann "Prognosen" über dieselbe Historie, hat jede Prognose heimlich die Zukunft gesehen — die Parameter wurden mit Daten von nach dem Prognosedatum geschätzt. Die In-Sample-Anpassung sieht wunderbar aus, und die Live-Performance ähnelt ihr überhaupt nicht. Jede zurückgetestete Prognose muss von einem Modell stammen, das nur auf zu diesem Zeitpunkt verfügbaren Daten angepasst wurde: auf einem expandierenden oder rollierenden Fenster neu anpassen, einen Schritt prognostizieren, vorwärts rollen. Das ist nicht verhandelbar und ist das gesamte Thema von Walk-Forward-Optimierung. Die Lücke zwischen einem In-Sample-GARCH und einem sauber walk-forward getesteten ist die Lücke zwischen einer Demo und einem System, das den Kontakt mit Live-Märkten übersteht — siehe auch Backtest-Live-Parität.
Timing der Prognose. Verwandt, aber eigenständig. Die Prognose für Tag muss aus Informationen berechnet werden, die zum Schluss von Tag verfügbar sind (oder wann immer die eigene Kerze schließt), und die Position muss zu einem tatsächlich erreichbaren Preis ausführbar sein. Die Prognose mit dem Schlusskurs von Tag zu berechnen und dann zum Eröffnungskurs von Tag zu "handeln", ist ein Blick in die Zukunft, der jedes Ergebnis still aufbläht.
Overfitting hoher Ordnungen. GARCH(1,1) reicht fast immer aus. Die Versuchung, GARCH(2,2) oder GARCH(3,1) anzupassen, weil es die In-Sample-Log-Likelihood nach oben schiebt, ist meist Rauschen-Fitting; die zusätzlichen Parameter verbessern selten Out-of-Sample-Prognosen und machen den Optimierer nahe der Grenze oft instabil. Bevorzugt das sparsame Modell, und wenn man Ordnungen vergleichen muss, vergleicht sie anhand des Out-of-Sample-Prognoseverlusts auf einem Walk-Forward-Split, nicht anhand des In-Sample-AIC. Zeigt die Residuendiagnostik noch immer ein Problem, liegt die Lösung meist in einer besseren Innovationsverteilung oder einem Asymmetrieterm (Teil 2), nicht in einer höheren Ordnung.
Strukturbrüche, die als Persistenz gelesen werden. Wie angemerkt, kann eine dauerhafte Verschiebung des Volatilitätsniveaus (ein neues Marktregime, eine Veränderung der Marktmikrostruktur) von GARCH als scheinbar hohe Persistenz absorbiert werden, was Richtung 1 treibt. Wirkt die Schätzung der langfristigen Volatilität über verschiedene Fenster hinweg instabil, vermutet einen Bruch, statt der Near-IGARCH-Punktschätzung zu vertrauen. Rollierende Neuanpassungen und, wo passend, ein explizites Regimemodell schützen davor.
Volatilitätsprognosen mit Renditeprognosen verwechseln. GARCH prognostiziert die Größenordnung von Bewegungen, nicht ihre Richtung. Es sagt einem, wie groß der morgige Ausschlag voraussichtlich sein wird, nicht in welche Richtung. Genau deshalb liegt sein natürlicher Platz im Risikomanagement — Sizing, Stops, VaR — statt in der Signalgenerierung. Verwechselt keine gute Varianzprognose mit einem Edge.
Wie es weitergeht
GARCH(1,1) ist das Fundament, und es ist absichtlich unvollständig. Die Serie baut darauf in drei Richtungen auf:
- Asymmetrie und fette Tails — reale Krypto-Volatilität reagiert stärker auf Abwärtsbewegungen als auf Aufwärtsbewegungen (der Leverage-Effekt), und Gauß'sche Innovationen können die Tails nicht reproduzieren. GJR-GARCH, EGARCH und Student-t-/schiefe-t-Innovationen sind Teil 2.
- Multivariate Volatilität — Korrelationen zwischen Krypto-Assets sind selbst zeitveränderlich und schnellen bei Crashs nach oben. Die gesamte Kovarianzmatrix dynamisch zu modellieren ist Teil 3: DCC-GARCH, das sich direkt mit Markowitz-Mean-Variance und CVaR-basierter Allokation verbindet, sobald die Kovarianz dynamisch ist.
- Die vollständige Strategie — Sizing, Stops, Kosten, Turnover und ehrliche Walk-Forward-Evaluierung kommen in Teil 4 zusammen.
Und wo GARCH-Randverteilungen in das gemeinsame Risiko einfließen: Das univariate Modell der bedingten Varianz hier ist genau die erste Stufe der GARCH-EVT-Copula-Pipeline für Portfolio-VaR/CVaR. Hat man die standardisierten Residuen aus einer Per-Asset-GARCH-Anpassung, transformiert man sie und fügt sie mit einer Copula zusammen — die Randverteilungen sind GARCH, die Abhängigkeit ist die Copula. Diese Konstruktion, einschließlich Tail-Abhängigkeit und der EVT-Tail-Behandlung, wird ausführlich in Copula-Modellen für gemeinsames Krypto-Risiko behandelt; dieser Artikel ist der univariate Motor, der darunter sitzt.
Zusammenfassung
- Krypto-Renditen zeigen Volatilitätsclustering, fette Tails und keine Renditen-Autokorrelation, aber starke Autokorrelation der quadrierten Renditen. Jedes Werkzeug, das konstante Volatilität annimmt — Black-Scholes mit einem einzigen , statisches VaR, feste prozentuale Stops — ist gegenüber diesen Fakten falsch spezifiziert.
- GARCH(1,1), , modelliert zeitveränderliche bedingte Varianz mit drei Parametern: eine Basislinie , eine Schockreaktion und eine Persistenz . Es ist ein ARCH() mit geometrisch abklingendem Gedächtnis, weshalb es hochgradige ARCH-Modelle schlägt.
- Stationarität erfordert ; die langfristige Varianz ist , die Persistenz ist , und die Volatilitäts-Halbwertszeit ist . Krypto befindet sich im Near-IGARCH-Regime (): sehr persistent, langsam mean-revertierend, mit einer fragilen Schätzung der langfristigen Varianz.
- Per Maximum Likelihood schätzen. Die Gauß'sche Log-Likelihood ist eine Summe von Ein-Schritt-Dichten; man passt sie mit
arch_model(r*100, vol="Garch", p=1, q=1)an. Die ×100-Skalierung nicht vergessen und jede Ausgabe konsistent zurückskalieren. - Prognosen mean-revertieren geometrisch zur langfristigen Varianz mit Rate . Aggregiert die täglichen Varianzprognosen, um die Haltehorizont-Volatilität zu erhalten — nicht die naive -Regel.
- Validiert mit Ljung-Box auf quadrierte standardisierte Residuen und dem ARCH-LM-Test. Bestehen diese, ist bestätigt, dass das Clustering weggemodelliert wurde; verbleibende fette Tails motivieren Teil 2.
- Wendet es an auf volatilitätsgezieltes Sizing (, gedeckelt) und volatilitätsskalierte Stops (). Eine Prognose treibt beides an, sodass Hochvolatilitätsregime gleichzeitig kleinere Größe und weitere Stops bekommen.
- Die relevanten Fallstricke: Renditenskalierung, Blick in die Zukunft bei der Anpassung (nur auf vergangenen Daten anpassen, immer walk-forward), Prognosetiming, zu hohe Ordnungen und niemals eine Varianzprognose mit einer Richtungsprognose verwechseln.
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
Quantitative Research & Strategy