GARCH(1,1): Cryptovolatiliteit voorspellen
Open een grafiek van de dagelijkse BTC-rendementen en je zult iets opmerken waar de leerboeken over random walks je nooit op hebben voorbereid: de rust en de chaos komen in clusters. Een daling van 6% op een dag staat zelden alleen. Ze zit ingebed in een week met uitslagen van 4-8%, waarna de markt uitademt en een maand lang wegdrijft in slaperige sessies van 1% voordat de volgende storm losbarst. De rendementen zelf lijken bijna onvoorspelbaar - je kunt niet betrouwbaar zeggen of het morgen omhoog of omlaag gaat - maar hun omvang is zeer voorspelbaar. De turbulentie van vandaag vertelt je veel over die van morgen.
Vrijwel elk risicohulpmiddel waar een trader naar grijpt, gaat er stilzwijgend van uit dat dit niet waar is. Black-Scholes prijst een optie met een enkele constante . Een statisch Value-at-Risk-getal vermenigvuldigt een enkele volatiliteitsschatting met een normaalkwantiel. Een vaste stop-loss van 3% behandelt een doodstille zijwaartse dinsdag en de uren rond een FOMC-publicatie of een grote de-peg op een exchange alsof ze hetzelfde risico dragen. Elk van deze faalt op exact dezelfde manier: het comprimeert een in de tijd veranderende grootheid tot een constante, en wordt vervolgens verrast wanneer die constante toch blijkt te bewegen.
Dit artikel is deel 1 van een serie in vier delen over volatiliteitsmodellering voor crypto. Het legt het fundament: het GARCH(1,1)-model, waarom het zo goed past bij cryptorendementen, hoe je het eerlijk schat met maximum likelihood via de arch-bibliotheek, en hoe je een voorspelling van de conditionele variantie omzet in twee direct bruikbare dingen - een positiegrootte en een stopbreedte die beide meeademen met de markt. Deel 2 voegt asymmetrie en zware staarten toe, deel 3 gaat multivariaat, en deel 4 stelt de volledige, op volatiliteit gerichte backtest samen. We houden de toepassing hier bewust eenvoudig; de eerlijke, walk-forward-gevalideerde strategie is het onderwerp van deel 4.
De gestileerde feiten van cryptorendementen
Voordat we iets modelleren, loont het om precies te zijn over wat we proberen te reproduceren. Empirische financiële rendementen - aandelen, valuta en crypto in het bijzonder - delen een kleine set robuuste statistische regelmatigheden die al decennia zijn gedocumenteerd. Ze worden meestal gestileerde feiten genoemd, en drie ervan sturen alles wat volgt.
1. Volatiliteitsclustering. Grote bewegingen worden doorgaans gevolgd door grote bewegingen (in beide richtingen), en kleine bewegingen door kleine bewegingen. Mandelbrot merkte dit in 1963 op in katoenprijzen. Formeel gezien zijn de rendementen vrijwel serieel ongecorreleerd, terwijl de gekwadrateerde rendementen (een proxy voor de gerealiseerde variantie) een sterke, langzaam afnemende positieve autocorrelatie vertonen.
2. Dikke staarten (leptokurtosis). De onconditionele verdeling van rendementen heeft veel meer massa in de extremen dan een Gaussische verdeling. Waar een normale verdeling een kurtosis van 3 heeft, zitten de dagelijkse logaritmische BTC-rendementen routinematig boven 8-10, en crypto-rendementen op hogere frequentie kunnen erger zijn. Zes-sigma-dagen, die volgens een normaal model ongeveer eens per miljoen jaar zouden voorkomen, verschijnen meerdere keren per decennium.
3. Geen lineaire autocorrelatie in rendementen, sterke autocorrelatie in gekwadrateerde rendementen. Dit is de vingerafdruk die een echt volatiliteitsproces onderscheidt van een triviale trend. Als je regresseert op zijn eigen vertragingen, krijg je niets bruikbaars. Als je regresseert op zijn vertragingen, vind je een duidelijk, aanhoudend signaal. Dit is precies de structuur die een variantiemodel zou moeten vastleggen - en precies wat een model met constante weggooit.
We kunnen alle drie in een paar regels bekijken. Niets hiervan vereist een speciale databron; gebruik ccxt in productie, maar voor een reproduceerbaar fragment volstaat 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]))
De typische uitkomst (illustratief - jouw venster zal verschillen): een excess kurtosis ruim boven 3, een Ljung-Box-p-waarde op de ruwe rendementen die er niet in slaagt "geen autocorrelatie" te verwerpen, en een p-waarde op de gekwadrateerde rendementen die effectief nul is. Dat laatste contrast is het hele spel. Er valt niets te verhandelen in het teken van de rendementen op dagelijkse horizon, maar er zit heel veel structuur in hun variantie, en die structuur is voorspelbaar.
Een opmerking over de 24/7-aard van crypto. Anders dan bij aandelen is er geen overnight-gap en geen weekendsluiting, dus de "dag" is een schone bar van 24 uur en de annualiseringsfactor is , niet . Volatiliteitsclustering blijft ook op intraday-schalen bestaan, wat van belang is als je GARCH op uurlijkse bars draait - omslagen in de funding rate en liquidatiecascades injecteren scherpe, geclusterde variantie-uitbarstingen die een dagelijks model gladstrijkt.
Van ARCH naar GARCH
Het probleem is nu scherp gesteld: modelleer een variantie die niet constant is maar afhangt van het recente verleden. Het eerste model dat dit correct deed, was Engle's ARCH (Autoregressive Conditional Heteroskedasticity, 1982), waarmee hij in 2003 de Nobelprijs won.
Schrijf het rendement als een conditioneel gemiddelde plus een schok:
Hier is de conditionele variantie - de variantie van gegeven alles wat bekend is tot en met tijdstip - en is een gestandaardiseerde innovatie (standaardnormaal in het eenvoudigste geval). Het woord "conditioneel" doet al het werk: onconditioneel kan de variantie constant zijn, maar geconditioneerd op gisteren beweegt ze.
Engle's ARCH() maakt de variantie van vandaag een gewogen som van de laatste gekwadrateerde schokken:
met en om de variantie positief te houden. Dit legt clustering direct vast: een grote schok duwt omhoog, wat de kans op nog een grote schok vergroot, wat de variantie verhoogd houdt. Het probleem is het empirische verval. Volatiliteitspersistentie in echte markten strekt zich uit over veel vertragingen, dus om het te passen heeft een ARCH-model een grote nodig - vaak 8, 10 of meer - en dat betekent het schatten van een lange, instabiele vector van die de neiging heeft te overfitten.
Bollerslevs inzicht in 1986 was om een term toe te voegen die al die persistentie opvangt met een enkele parameter. De GARCH(1,1) - Generalized ARCH - recursie is:
Drie parameters, drie heldere interpretaties:
- - de basislijn of ondergrens. Een constante die het langetermijnniveau van de variantie verankert. De variantie daalt nooit onder wat ondersteunt.
- - de reactie op nieuws. Hoe heftig de variantie reageert op de verrassing van gisteren. Een grote betekent dat de conditionele variantie schokkerig en schokgevoelig is.
- - de persistentie of het geheugen. Hoeveel van de variantie van gisteren doorwerkt in vandaag. Een grote betekent dat de volatiliteit vloeiend is en langzaam vervaagt - rust blijft rust, stormen blijven stormen.
De elegantie zit in de recursie. Omdat zelf een term bevatte, laat uitwerken naar achteren zien dat GARCH(1,1) een ARCH() is met geometrisch afnemende gewichten op vroegere gekwadrateerde schokken:
Zo koopt de enkele je een oneindig, exponentieel gewogen geheugen van vroegere schokken. Dit is de reden waarom een simpele GARCH(1,1) - drie parameters - routinematig ARCH-modellen met tien parameters verslaat, en waarom het het werkpaard van de toegepaste volatiliteitsmodellering werd. Het is in feite een nauwe verwant van de RiskMetrics-EWMA-variantieschatter, die het speciale geval , is met vastgezet op 0,94. GARCH generaliseert het door de data , en een echt mean-reversion-niveau te laten kiezen.
Eigenschappen: stationariteit, langetermijnvariantie en halfwaardetijd
De GARCH(1,1)-recursie heeft een paar eigenschappen die het waard zijn om af te leiden, want ze zijn wat je in staat stelt over het model te redeneren in plaats van het blindelings te passen.
Onconditionele (langetermijn)variantie. Neem aan dat het proces covariantiestationair is, zodat de onconditionele variantie bestaat en constant is in de tijd. Neem de verwachtingswaarde van beide kanten van de recursie. Omdat :
Dit is het niveau waar de volatiliteit naar terugkeert. Het bestaat alleen - en is alleen positief - wanneer .
Stationariteitsvoorwaarde. Dezelfde ongelijkheid,
is de covariantiestationariteitsvoorwaarde voor GARCH(1,1). De grootheid is de persistentie van het variantieproces: het is de AR(1)-coëfficiënt die bepaalt hoe een variantieschok terugvalt naar . Als , is de onconditionele variantie oneindig (of ongedefinieerd) en sterven schokken nooit volledig uit.
We kunnen de mean-reversion expliciet zien. Definieer de variantieafwijking . Een beetje algebra op de recursie (met substitutie van ) geeft, in verwachting:
De kloof tussen de huidige variantie en het langetermijnniveau krimpt bij elke stap met een factor . Dit is precies de meerstapsvoorspelling die we later gebruiken.
Volatiliteits-halfwaardetijd. Hoe lang duurt het voordat een variantieschok halverwege terug is naar normaal? Stel en los op:
Voor is de halfwaardetijd ongeveer 13,5 dagen; voor is het ongeveer 34 dagen; voor is het ongeveer 69 dagen. Dit enkele getal is vaak intuïtiever dan de ruwe parameters - het vertelt je, in de eenheden van je bars, hoe kleverig de volatiliteit is.
Het bijna-IGARCH-probleem in crypto. Hier is de crypto-specifieke kronkel. Wanneer je GARCH(1,1) op BTC- of ETH-rendementen past, vind je bijna altijd heel dicht bij 1 - waarden van 0,98, 0,99, soms 0,995 zijn routine. Dit is het bijna-IGARCH-regime (Integrated GARCH). Het heeft echte gevolgen:
- De halfwaardetijd wordt enorm (weken tot maanden), dus het model behandelt de volatiliteit als zeer persistent en nauwelijks mean-reverting.
- De schatting van wordt extreem gevoelig: een kleine verandering in van 0,99 naar 0,995 verdubbelt de geïmpliceerde langetermijnvariantie. Vertrouw in dit regime nooit op de puntschatting van de langetermijnvolatiliteit zonder een betrouwbaarheidsinterval.
- Meerstapsvoorspellingen keren zo langzaam terug naar het gemiddelde dat, voor praktische horizonten van minder dan een paar weken, GARCH zich bijna gedraagt als een random-walk-in-variantie (wat EWMA aanneemt).
Of bijna-integratie echt is of een artefact van structurele breuken (een permanente verschuiving in het volatiliteitsniveau die door het model als één lange persistente episode wordt gelezen) is een echt debat. Het is nog een reden om te herschatten op rollende vensters in plaats van eenmalig op alle historie te passen, een punt waar we op terugkomen bij de valkuilen. Regimestructuur specifiek wordt beter behandeld door een expliciet switching-model - zie regimedetectie met verborgen Markov-modellen, dat complementair is aan GARCH in plaats van een vervanging.
Schatting met maximum likelihood
GARCH-parameters worden geschat met maximum likelihood. De logica is direct: gegeven produceert de recursie een volledig pad van conditionele varianties , en onder een veronderstelde verdeling voor de innovaties kunnen we opschrijven hoe waarschijnlijk de waargenomen rendementen zijn. We kiezen dan om die likelihood te maximaliseren.
Neem Gaussische innovaties aan, zodat . De conditionele dichtheid van één waarneming is
Omdat het model conditioneel is geschreven, ontbindt de gezamenlijke likelihood in een product van eenstaps-vooruitdichtheden, en is de log-likelihood een gewone som:
Twee structurele feiten om op te merken. Ten eerste verschijnt zowel als een straf ( - het model wordt bestraft voor het claimen van een hoge variantie) als in het gestandaardiseerde residu ( - het model wordt bestraft voor verrast worden). Het optimum balanceert de twee, en dat is wat de variantie doet meebewegen. Ten tweede heeft de recursie een startwaarde nodig; de gebruikelijke keuze is de steekproefvariantie van de rendementen, en met een paar duizend waarnemingen maakt de startwaarde nauwelijks uit.
Er is geen gesloten vorm voor de maximaliseerder, dus we optimaliseren numeriek (arch gebruikt een quasi-Newton-methode met analytische of numerieke gradiënten). Het likelihood-oppervlak is voor GARCH(1,1) doorgaans goed hanteerbaar, maar twee dingen bijten in de praktijk: de positiviteitsbeperkingen () en het gedrag nabij de rand wanneer , waar de optimizer traag kan voortkruipen. Beide worden voor je afgehandeld door een goede bibliotheek - en je zou er een moeten gebruiken. Een GARCH-MLE zelf schrijven is een prima leeroefening maar een slechte productiekeuze.
De arch-bibliotheek
Het arch-pakket van Kevin Sheppard is het standaardhulpmiddel in Python. De hele fit is vier regels.
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())
Een woord over de argumentnamen, want ze zijn een veelvoorkomende bron van verwarring. In arch is p het aantal vertraagde varianties (-termen, de GARCH-orde) en q het aantal vertraagde gekwadrateerde residuen (-termen, de ARCH-orde). Dus p=1, q=1 is de GARCH(1,1) die we hebben afgeleid. (Bollerslevs oorspronkelijke notatie schrijft het als GARCH() met voor de ARCH-orde - de twee conventies zijn omgewisseld. Vertrouw op de eigen documentatie van de bibliotheek, niet op je geheugen.)
Als je de samenvatting leest, ziet de coëfficiëntentabel er ongeveer zo uit (illustratieve waarden voor dagelijkse BTC-rendementen, geen echt 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
==========================================================
Hoe je het leest:
alpha[1] + beta[1]= 0,0912 + 0,8994 = 0,9906. Persistentie net onder 1 - het bijna-IGARCH-regime, precies zoals gewaarschuwd. Halfwaardetijd dagen.omega= 0,4821, dus de langetermijnvariantie is in procent-kwadraateenheden, oftewel een langetermijn-dagvolatiliteit van , of ruwweg op jaarbasis. Dat is een plausibel BTC-getal.- Zowel
alphaalsbetazijn sterk significant. Datalphaklein is ten opzichte vanbetais typisch: cryptovariantie is voornamelijk persistentie (geheugen), met een bescheiden maar reële reactie op verse schokken.
De ×100-schalingsvalstrik
Dit is de meest voorkomende manier om onzin uit arch te krijgen, en verdient daarom een eigen paragraaf. De optimizer werkt het beste wanneer de getallen die hij ziet tot zijn. Dagelijkse logaritmische rendementen zijn , dus hun kwadraten zijn en moet rond liggen - laag in een bereik waar numerieke gradiënten precisie verliezen en de fit stilzwijgend kan falen te convergeren of onzinnige standaardfouten kan teruggeven.
De oplossing is om te passen op rendementen geschaald met 100 (dus in procenten), zoals hierboven. arch geeft zelfs een DataScaleWarning als je het vergeet. Alles wat je uit het model afleest, is dan in procent- of procent-kwadraateenheden, en je moet consistent terugschalen:
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%}")
Het mengen van geschaalde en niet-geschaalde grootheden - bijvoorbeeld een procentvolatiliteit invoeren in een positiegrootteformule die decimalen verwacht - levert fouten op van precies 100x, die gemakkelijk over het hoofd te zien zijn omdat de code gewoon draait. Kies een conventie (ik houd alles decimaal buiten de fit en schaal alleen op de grens met arch) en overschrijd die nooit.
De conditionele variantie voorspellen
Een gepast model is alleen nuttig als het voorspelt. GARCH geeft schone, analytische voorspellingen op elke horizon.
Eén stap vooruit. Op tijdstip (het einde van de steekproef) kennen we en , dus de volgende variantie is deterministisch:
Geen verwachting nodig - alles aan de rechterkant is waargenomen.
Meerdere stappen vooruit. Voor kennen we de tussenliggende schokken nog niet, dus nemen we conditionele verwachtingen. Met (omdat ) reduceert de recursie tot een simpele AR(1) in de voorspelde variantie:
Dit itereren vanaf de eenstapsvoorspelling geeft de gesloten vorm, die het mean-reversion-resultaat is dat we eerder afleidden, nu expliciet uitgeschreven:
Lees dit zorgvuldig, want het is de geometrie van elke GARCH-voorspelling. De termijnstructuur van de variantie begint bij de conditionele variantie van vandaag en vervalt geometrisch naar het langetermijnniveau . Als vandaag rustiger is dan gemiddeld, stijgt de voorspellingscurve naar ; als vandaag een crisis is, daalt ze ernaartoe. De snelheid van dat verval wordt volledig bepaald door - en in het bijna-IGARCH-cryptoregime, waar , is het verval zo langzaam dat voor horizonten van minder dan een paar weken de voorspelling nauwelijks van het niveau van vandaag afwijkt. Dat is de moeite waard om te internaliseren: voor korte holdingperiodes is de crypto-GARCH-voorspelling in wezen "morgen ziet eruit als vandaag, alleen heel langzaam terugkerend."
Aggregeren naar een holdinghorizon. Traders geven zelden om de variantie van een enkele toekomstige dag. Als je een positie dagen aanhoudt en de rendementen conditioneel ongecorreleerd zijn (het gestileerde feit van het begin), is de variantie van het cumulatieve -daagse rendement de som van de eendaagse voorspelde varianties:
Dit is het getal waar je daadwerkelijk je positie tegen dimensioneert - de volatiliteit van de P&L over je holdingperiode. Merk op dat het nadrukkelijk niet de naïeve -schaling is, die alleen correct is als de variantie constant is. Wanneer de variantie van vandaag boven ligt, maakt de mean-reverting-voorspelling de werkelijke -daagse volatiliteit lager dan de wortel-regel; wanneer vandaag rustig is, is ze hoger. Dit goed doen is het verschil tussen een stop die de termijnstructuur respecteert en een die dat niet doet.
In 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%}")
Voor langere horizonten ondersteunt GARCH ook simulatievoorspellingen (method="simulation"), die de innovatieverdeling voortstuwen en je de volledige voorspellingsdichtheid geven, niet alleen de variantie ervan - nuttig wanneer de innovaties niet-Gaussisch zijn, wat ze zullen zijn zodra we in deel 2 overstappen op Student-t en scheve verdelingen. Voor de lineair-in-variantie-grootheden hierboven is het analytische pad exact en gratis.
Diagnostiek: heeft het model daadwerkelijk gewerkt?
Een model passen is niet hetzelfde als het valideren. Het hele punt van GARCH is om de conditionele heteroskedasticiteit - de volatiliteitsclustering - te absorberen, zodat wat overblijft (bij benadering) i.i.d. is. De juiste controle is daarom om te kijken naar de gestandaardiseerde residuen
en te vragen: is de clustering verdwenen? Als het model de variantiedynamiek heeft vastgelegd, zouden de een eenheidsvariantie moeten hebben en, cruciaal, zouden hun kwadraten geen resterende autocorrelatie meer moeten vertonen. We voeren drie tests uit.
1. Ljung-Box op gestandaardiseerde residuen. Controleert of er geen lineaire autocorrelatie overblijft in het niveau van (dit test eigenlijk het gemiddeldemodel, niet het variantiemodel). Zou niet moeten verwerpen.
2. Ljung-Box op gekwadrateerde gestandaardiseerde residuen. Dit is de belangrijke. Als nog steeds significante autocorrelatie heeft, is het variantiemodel er niet in geslaagd de clustering te verwijderen - er is structuur die GARCH(1,1) niet heeft vastgelegd, en je hebt mogelijk een hogere orde, een asymmetrische variant of een andere innovatieverdeling nodig. Zou niet moeten verwerpen.
3. ARCH-LM-test (Engle's Lagrange-multiplier-test). Regresseer op zijn eigen vertragingen en test op gezamenlijke significantie. Het is in wezen een formele versie van test 2 en vraagt direct "is er ARCH-effect overgebleven?" Een niet-significant resultaat bevestigt dat de conditionele heteroskedasticiteit is weggemodelleerd.
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}")
Hoe goede output eruitziet: de Ljung-Box-p-waarden op springen van bijna nul (op de ruwe gekwadrateerde rendementen) naar comfortabel boven 0,05, en de ARCH-LM-test slaagt er niet in te verwerpen. Dat is je bewijs dat het model zijn werk deed op het tweede moment.
Hoe imperfecte output eruitziet - en wat je zou moeten verwachten bij een simpele Gaussische GARCH(1,1) op crypto - is dat de clusteringtests slagen maar de kurtosis van het gestandaardiseerde residu nog steeds verhoogd is (zeg 4-6 in plaats van 0). GARCH verwijdert de clustering maar een enkele dikke-staart-onconditionele verdeling blijft, omdat Gaussische innovaties de staarten niet kunnen reproduceren. Die resterende dikke-staartigheid is hier geen bug om te repareren; het is de motivatie voor deel 2, asymmetrische GARCH en het leverage-effect in crypto, waar Student-t- en scheve-t-innovaties en de GJR/EGARCH-asymmetrieterm precies dit aanpakken.
Toepassing: op volatiliteit geschaalde positiegrootte en stops
We hebben nu een voorspelling van de volatiliteit van morgen (en van de volgende dagen). Wat doen we ermee? De twee eenvoudigste, meest waardevolle toepassingen zijn positiegrootte en stopplaatsing. We houden beide hier bewust basaal - de volledige vol-targeting-strategie met al zijn praktische machinerie is deel 4.
Op volatiliteit gerichte positiegrootte
Het idee is om een positie aan te houden waarvan de risicobijdrage ruwweg constant is door de tijd, in plaats van een positie waarvan de notionele waarde constant is. Als je altijd dezelfde dollargrootte inzet, zwelt je risico op in hoge-volatiliteitsregimes en krimpt het in rustige - het tegenovergestelde van wat je wilt. Volatiliteits-targeting keert dit om: streef naar een vaste doelvolatiliteit van de P&L, en laat de voorspelling de grootte bepalen.
Voor een op jaarbasis beoogde volatiliteit (zeg 20%) en een op jaarbasis voorspelde volatiliteit is het positiegewicht
Wanneer de voorspelde volatiliteit hoog is, schaal je omlaag; wanneer ze laag is, schaal je omhoog. Dat is het hele mechanisme. Omdat voorspeld is - bekend op voordat het rendement op is gerealiseerd - is er geen look-ahead, mits je gedisciplineerd bent over de timing (meer hierover bij de valkuilen).
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")
Dit is een naaste verwant van goede kapitaalallocatieregels. Volatiliteits-targeting beantwoordt "hoeveel moet het risico schalen met volatiliteit," terwijl het Kelly-criterium beantwoordt "hoeveel moet het risico schalen met edge" - en de twee vermenigvuldigen zich in een volledige sizing-stack: grootte edge / variantie. Merk op dat de variantieterm van Kelly precies de GARCH-voorspelling is die je zojuist hebt berekend, en dat is waarom een live volatiliteitsmodel de Kelly-sizing wezenlijk scherper maakt dan een statische historische schatting. Als je edge-schatting zelf gekwantificeerde onzekerheid draagt, geeft conforme voorspelling een verdelingsvrije manier om de grootte te verbreden of te verkleinen om daarbij te passen, en het combineert schoon met vol-targeting.
De begrenzing w_max is niet optioneel. In het bijna-IGARCH-regime kan een stille periode de voorspelde volatiliteit behoorlijk laag drukken, en zal een leverage eisen die op papier prima is en ruïneus wanneer de rust breekt - wat, conform volatiliteitsclustering, uiteindelijk gebeurt, vaak abrupt. Het begrenzen van leverage is de grove-maar-effectieve erkenning dat je voorspelling een conditioneel gemiddelde is, geen garantie, en dat de uitbetaling bij ongelijk hebben asymmetrisch is. Die asymmetrie - een opgeblazen account is niet herstelbaar door een symmetrische winst - is precies de verlies-versus-winst-asymmetrie die je systematisch voorzichtiger zou moeten maken dan een variantie-alleen-regel suggereert.
Op volatiliteit geschaalde stops
Een stop met een vast percentage heeft dezelfde kwaal als een vaste positiegrootte: een stop van 3% is een haartrekker in een rustige markt en een afrondingsfout in een gewelddadige. Het schopt je uit goede posities door gewone ruis tijdens hoge-volatiliteitsregimes en geeft veel te veel terug tijdens overgangen. De oplossing is om de stopafstand in te stellen in eenheden van voorspelde volatiliteit.
waarbij de voorspelde volatiliteit over je verwachte holdinghorizon is (de geaggregeerde grootheid uit de voorspellingssectie) en een veelvoud is - typisch 1,5 tot 3 - gekozen zodat de stop buiten de normale fluctuatie zit maar binnen een echte ongunstige beweging.
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}")
Omdat de mean-reverting-termijnstructuurvoorspelling gebruikt in plaats van een vlak historisch getal, verbreedt de stop zich automatisch bij het ingaan van turbulente regimes en versmalt hij naarmate de volatiliteit afneemt - de termijnstructuur doet het aanpassen voor je. Dit is dezelfde voorspelling die zowel de grootte als de stop voedt, wat een kenmerk is: in een hoge-volatiliteitsregime houd je tegelijkertijd minder aan en geef je de positie meer ruimte, en de twee effecten versterken elkaar tot een wezenlijk lager staartrisico. Positiegrootte en stops zijn twee projecties van één volatiliteitsvisie, geen twee onafhankelijke knoppen.
Zover voeren we de toepassing in deel 1. Een echte strategie moet omgaan met transactiekosten door constante herbalancering, de timing van wanneer de voorspelling wordt berekend versus wanneer de trade wordt geplaatst, turnover-controle en - bovenal - eerlijke out-of-sample-evaluatie. Dat alles is deel 4: de op volatiliteit gerichte GARCH-strategie, waar we het geheel opbouwen en walk-forward-testen.
Valkuilen
GARCH is gemakkelijk te passen en gemakkelijk om jezelf mee voor de gek te houden. De faalmodi zijn consistent.
Rendementsschaling. Hierboven behandeld, maar het is de bug nummer één, dus het is de herhaling waard: pas arch op rendementen × 100, en schaal elke output terug (variantie door , volatiliteit door ). Een stille 100x-fout hier vergiftigt elke stroomafwaartse sizing- en stopberekening.
Look-ahead in het fitten. De subtiele killer. Als je het model op de hele historie past en vervolgens "voorspellingen" over diezelfde historie berekent, heeft elke voorspelling stiekem de toekomst gezien - de parameters werden geschat met data van na de voorspellingsdatum. De in-sample-fit ziet er prachtig uit en de live prestatie zal er totaal niet op lijken. Elke gebacktestte voorspelling moet komen van een model dat alleen is gepast op data die op dat moment beschikbaar was: herschat op een uitdijend of rollend venster, voorspel één stap, rol vooruit. Dit is niet onderhandelbaar en het is het hele onderwerp van walk-forward-optimalisatie. De kloof tussen een in-sample-GARCH en een correct walk-forward-GARCH is de kloof tussen een demo en een systeem dat het contact met live markten overleeft - zie ook backtest-live-pariteit.
Timing van de voorspelling. Verwant maar onderscheiden. De voorspelling voor dag moet worden berekend uit informatie die beschikbaar is bij de sluiting van dag (of wanneer je bar ook sluit), en de positie moet uitvoerbaar zijn tegen een prijs die je daadwerkelijk zou kunnen krijgen. De voorspelling berekenen met de slotkoers van dag en vervolgens "traden" tegen de opening van dag is een look-ahead die elk resultaat stilzwijgend opblaast.
Overfitten van hoge ordes. GARCH(1,1) is bijna altijd voldoende. De verleiding om GARCH(2,2) of GARCH(3,1) te passen omdat het de in-sample-log-likelihood een tikje omhoog duwt, is meestal ruis-fitten; de extra parameters verbeteren zelden de out-of-sample-voorspellingen en maken de optimizer vaak instabiel nabij de rand. Verkies het spaarzame model, en als je ordes moet vergelijken, vergelijk ze dan op basis van out-of-sample-voorspellingsverlies op een walk-forward-splitsing, niet op basis van in-sample-AIC. Wanneer de residudiagnostiek nog steeds een probleem laat zien, is de oplossing meestal een betere innovatieverdeling of een asymmetrieterm (deel 2), geen hogere orde.
Structurele breuken gelezen als persistentie. Zoals opgemerkt kan een permanente verschuiving in het volatiliteitsniveau (een nieuw marktregime, een verandering in de marktmicrostructuur) door GARCH worden geabsorbeerd als vals-hoge persistentie, waardoor naar 1 wordt geduwd. Als je langetermijnvolatiliteitsschatting instabiel lijkt over vensters, vermoed dan een breuk in plaats van de bijna-IGARCH-puntschatting te vertrouwen. Rollende herschattingen en, waar gepast, een expliciet regimemodel beschermen hiertegen.
Volatiliteitsvoorspellingen behandelen als rendementsvoorspellingen. GARCH voorspelt de omvang van bewegingen, niet hun richting. Het vertelt je hoe groot de uitslag van morgen waarschijnlijk is, niet welke kant op. Dit is precies waarom zijn natuurlijke thuis risicomanagement is - positiegrootte, stops, VaR - in plaats van signaalgeneratie. Verwar een goede variantievoorspelling niet met een edge.
Waar dit naartoe gaat
GARCH(1,1) is het fundament, en het is bewust onvolledig. De serie bouwt er in drie richtingen op voort:
- Asymmetrie en zware staarten - echte cryptovolatiliteit reageert sterker op neerwaartse dan op opwaartse bewegingen (het leverage-effect), en Gaussische innovaties kunnen de staarten niet reproduceren. GJR-GARCH, EGARCH en Student-t / scheve-t-innovaties zijn deel 2.
- Multivariate volatiliteit - correlaties tussen crypto-activa zijn zelf in de tijd variërend en pieken tijdens crashes. Het dynamisch modelleren van de hele covariantiematrix is deel 3: DCC-GARCH, dat direct aansluit op Markowitz mean-variance en CVaR-gebaseerde allocatie zodra de covariantie dynamisch is.
- De volledige strategie - positiegrootte, stops, kosten, turnover en eerlijke walk-forward-evaluatie komen samen in deel 4.
En waar GARCH-marginalen gezamenlijk risico voeden: het univariate conditionele-variantiemodel hier is precies de eerste fase van de GARCH-EVT-copula-pijplijn voor portefeuille-VaR/CVaR. Zodra je gestandaardiseerde residuen hebt uit een GARCH-fit per activum, transformeer je ze en lijm je ze samen met een copula - de marginalen zijn GARCH, de afhankelijkheid is de copula. Die constructie, inclusief staartafhankelijkheid en de EVT-staartbehandeling, wordt diepgaand behandeld in copula-modellen voor gezamenlijk cryptorisico; dit artikel is de univariate motor die eronder zit.
Samenvatting
- Cryptorendementen vertonen volatiliteitsclustering, dikke staarten en geen rendementsautocorrelatie maar sterke autocorrelatie in gekwadrateerde rendementen. Elk hulpmiddel dat constante volatiliteit aanneemt - Black-Scholes met een enkele , statische VaR, stops met vast percentage - is verkeerd gespecificeerd ten opzichte van deze feiten.
- GARCH(1,1), , modelleert de in de tijd variërende conditionele variantie met drie parameters: een basislijn , een schokreactie en een persistentie . Het is een ARCH() met geometrisch afnemend geheugen, en daarom verslaat het hoge-orde-ARCH.
- Stationariteit vereist ; de langetermijnvariantie is , de persistentie is , en de volatiliteits-halfwaardetijd is . Crypto zit in het bijna-IGARCH-regime (): zeer persistent, langzaam terugkerend naar het gemiddelde, en met een fragiele langetermijnvariantieschatting.
- Schat met maximum likelihood. De Gaussische log-likelihood is een som van eenstapsdichtheden; pas hem met
arch_model(r*100, vol="Garch", p=1, q=1). Onthoud de ×100-schaling en schaal elke output consistent terug. - Voorspellingen keren geometrisch terug naar de langetermijnvariantie met snelheid . Aggregeer dagelijkse variantievoorspellingen om de holdinghorizon-volatiliteit te krijgen - niet de naïeve -regel.
- Valideer met Ljung-Box op gekwadrateerde gestandaardiseerde residuen en de ARCH-LM-test. Slagen hiervoor bevestigt dat de clustering is weggemodelleerd; resterende dikke staarten motiveren deel 2.
- Pas het toe op op volatiliteit gerichte positiegrootte (, begrensd) en op volatiliteit geschaalde stops (). Eén voorspelling drijft beide, dus hoge-volatiliteitsregimes krijgen tegelijkertijd een kleinere grootte en bredere stops.
- De valkuilen die ertoe doen: rendementsschaling, look-ahead in het fitten (pas alleen op data uit het verleden, altijd walk-forward), voorspellingstiming, over-ordening, en nooit een variantievoorspelling verwarren met een richtingsvoorspelling.
Referenties:
- 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
Kwantitatief onderzoek en strategie