असममित और हैवी-टेल्ड GARCH: EGARCH, GJR, और Student-t
इस सीरीज़ के भाग 1 में हमने GARCH(1,1) को शुरू से बनाया था: वोलैटिलिटी-क्लस्टरिंग की सहज समझ, कंडीशनल-वेरिएंस रिकर्शन, मैक्सिमम लाइकलीहुड एस्टिमेशन, फोरकास्टिंग, और arch लाइब्रेरी के साथ मानक रेजिड्युअल डायग्नोस्टिक्स। अगर आपने वह नहीं पढ़ा है, तो वहाँ से शुरू करें — यह पोस्ट यह मानकर चलती है कि आप पहले से एक सामान्य GARCH(1,1) को फिट और इंटरप्रेट कर सकते हैं, और बुनियादी बातें दोबारा नहीं बताएगी।
सामान्य GARCH(1,1) एक अच्छा बेसलाइन है लेकिन एक खराब अंतिम उत्तर। इसमें दो संरचनात्मक खामियाँ हैं जिन्हें बैकटेस्ट में नज़रअंदाज़ करना सस्ता है और असली पूंजी के साथ नज़रअंदाज़ करना महंगा। पहला, यह सममित (symmetric) है: मॉडल के दिन पर वैसे ही प्रतिक्रिया करता है जैसे के दिन पर, क्योंकि शॉक वेरिएंस रिकर्शन में केवल अपने स्क्वायर, , के ज़रिए प्रवेश करता है। स्क्वायर करने से चिह्न (sign) खो जाता है। दूसरा, यह गॉसियन इनोवेशन्स मानता है: GARCH के वोलैटिलिटी क्लस्टरिंग को सोख लेने के बाद भी, BTC और ETH के स्टैंडर्डाइज़्ड रेजिड्युअल्स स्पष्ट रूप से फैट-टेल्ड होते हैं, और एक गॉसियन लाइकलीहुड व्यवस्थित रूप से टेल को कम आंकता है। एक GARCH(1,1)-Normal 99% VaR समय के 1% से कहीं ज़्यादा बार टूटेगा।
यह पोस्ट दोनों खामियों को ठीक करती है। हम GJR-GARCH और EGARCH के साथ असममितता (asymmetry) जोड़ते हैं, और Student- और Hansen की skewed- इनोवेशन्स के साथ हैवी टेल्स। फिर हम वह काम करते हैं जो असल में फायदा देता है: फिट किए गए कंडीशनल डिस्ट्रीब्यूशन को एक-स्टेप Value-at-Risk और Expected Shortfall फोरकास्ट में बदलना, और उस फोरकास्ट को Kupiec और Christoffersen टेस्ट्स से ईमानदारी से बैकटेस्ट करना। एक वोलैटिलिटी मॉडल जिसे आप कभी रिस्क-टेस्ट नहीं करते, वह केवल सजावट है।
लीवरेज इफेक्ट, और क्रिप्टो ज़्यादा गड़बड़ क्यों है
इक्विटीज़ में इस असममितता का एक नाम और एक कहानी है। लीवरेज इफेक्ट (Black, 1976): जब किसी कंपनी का स्टॉक गिरता है, तो उसका debt-to-equity अनुपात बढ़ता है, इक्विटी यांत्रिक रूप से ज़्यादा जोखिमपूर्ण हो जाती है, और वोलैटिलिटी बढ़ जाती है। बुरी खबर भविष्य की वोलैटिलिटी को समान आकार की अच्छी खबर से ज़्यादा बढ़ाती है। अनुभवजन्य रूप से यह इक्विटी वोलैटिलिटी साहित्य के सबसे मज़बूत स्टाइलाइज़्ड फैक्ट्स में से एक है।
क्रिप्टो में कॉर्पोरेट अर्थ में कोई इक्विटी या बैलेंस-शीट लीवरेज नहीं है, फिर भी लीवरेज-इफेक्ट जैसी असममितता अक्सर दिखाई देती है — जो अकाउंटिंग के बजाय जबरन डीलीवरेजिंग से चलती है। जब BTC तेज़ी से गिरता है, तो ओवर-कोलैटरलाइज़्ड लोन लिक्विडेट हो जाते हैं, परपेचुअल-फ्यूचर्स की लॉन्ग पोज़िशन्स ज़बरदस्ती बंद हो जाती हैं, फंडिंग पलट जाती है, और यह कैस्केड वोलैटिलिटी को और बढ़ाता है। तो मैकेनिज़्म अलग है लेकिन चिह्न अक्सर इक्विटीज़ से मेल खाता है: डाउन-मूव्स वोलैटिलिटी को ज़्यादा स्पाइक करते हैं।
महत्वपूर्ण चेतावनी: क्रिप्टो ज़्यादा गड़बड़ है, और आपको असममितता को एक नियम के बजाय एक अनुभवजन्य सवाल की तरह लेना चाहिए। हिंसक अप-मूव्स — शॉर्ट स्क्वीज़, लीवरेज से भरा मेल्ट-अप, या ETF-अप्रूवल गैप — भी वास्तविक वोलैटिलिटी को स्पाइक कर सकते हैं। एसेट और सैंपल विंडो के आधार पर, अनुमानित असममितता मज़बूत, कमज़ोर, या कभी-कभी "गलत" चिह्न वाली हो सकती है। यह पोस्ट जिस अनुशासन पर ज़ोर देती है: असममित मॉडल फिट करें, देखें कि असममितता पैरामीटर सांख्यिकीय रूप से महत्वपूर्ण है या नहीं और अपेक्षित दिशा में है या नहीं, और अतिरिक्त पैरामीटर तभी रखें जब वह अपनी जगह कमाए। इक्विटी की कहानी को बिना जांचे मान न लें; उसे टेस्ट करें।
मॉडल करने से पहले असममितता की जांच
ऊपर दिए गए संक्षेप में कहा गया है "असममितता को अनुभवजन्य मानें" — इसलिए असममित मॉडल फिट करने से पहले, यह जांचने के लिए एक सस्ता औपचारिक टेस्ट चलाएं कि असममितता है भी या नहीं। Engle-Ng साइन-बायस टेस्ट्स (1993) ठीक यही करते हैं। पहले एक सममित GARCH(1,1) फिट करें, इसके स्क्वायर्ड स्टैंडर्डाइज़्ड रेजिड्युअल्स लें, और उन्हें पिछले शॉक के चिह्न और आकार के इंडिकेटर्स पर रिग्रेस करें:
जहां और । तर्क यह है: अगर सममित मॉडल ने पहले ही सब कुछ पकड़ लिया है, तो कल के शॉक का चिह्न और आकार आज के स्क्वायर्ड रेजिड्युअल की भविष्यवाणी नहीं करना चाहिए, इसलिए । अलग-अलग -टेस्ट्स साइन-बायस (), नेगेटिव-साइज़-बायस (), और पॉज़िटिव-साइज़-बायस () टेस्ट्स हैं; तीनों पर संयुक्त -टेस्ट ऑम्निबस टेस्ट है। एक महत्वपूर्ण या बताता है कि नेगेटिव शॉक्स को सममित मॉडल व्यवस्थित रूप से गलत आंक रहा है — यह आपके लिए संकेत है कि 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"])
अगर संयुक्त -टेस्ट अमहत्वपूर्ण है, तो आपके पास सममित बने रहने और दो पैरामीटर बचाने का अनुभवजन्य लाइसेंस है। अगर यह महत्वपूर्ण है — BTC/ETH के लिए सामान्य परिणाम — तो साफ ज़मीर के साथ GJR/EGARCH की ओर बढ़ें, यह जानते हुए कि आप एक असली फीचर को मॉडल कर रहे हैं, शोर का पीछा नहीं कर रहे। यही वह अनुभवजन्य अनुशासन है जिसकी मांग शुरुआत में की गई थी: इक्विटी लीवरेज कहानी को मान न लें, उसे टेस्ट करें।
GJR-GARCH: थ्रेशोल्ड टर्म के ज़रिए असममितता
Glosten-Jagannathan-Runkle मॉडल (1993) — जिसे कभी-कभी TGARCH या थ्रेशोल्ड GARCH कहा जाता है — GARCH(1,1) में सबसे छोटा संभव संशोधन है जो बुरी और अच्छी खबर को अलग-अलग प्रभाव देने देता है। भाग 1 से सममित कंडीशनल-वेरिएंस रिकर्शन याद करें:
GJR एक थ्रेशोल्ड टर्म जोड़ता है: वेरिएंस की एक अतिरिक्त मात्रा जो केवल नेगेटिव शॉक के बाद सक्रिय होती है।
जहां इंडिकेटर है
रिकर्शन को केस के हिसाब से पढ़ें। एक पॉज़िटिव शॉक () के बाद, इंडिकेटर शून्य होता है और अगली-अवधि वेरिएंस पर स्क्वायर्ड शॉक का प्रभाव केवल होता है। एक नेगेटिव शॉक के बाद, इंडिकेटर एक होता है और प्रभाव होता है। पैरामीटर एक ही संख्या में पूरी असममितता कहानी है:
- : नेगेटिव शॉक्स समान आकार के पॉज़िटिव शॉक्स से ज़्यादा वोलैटिलिटी बढ़ाते हैं। यह लीवरेज इफेक्ट है, और यह वही है जो आप ज़्यादातर समय BTC/ETH में पाने की उम्मीद करते हैं।
- : मॉडल वापस सममित GARCH(1,1) में गिर जाता है। इसलिए पर एक likelihood-ratio या -टेस्ट असममितता के अस्तित्व का प्रत्यक्ष टेस्ट है।
- : पॉज़िटिव शॉक्स ज़्यादा वोलैटिलिटी बढ़ाते हैं — कभी-कभार का क्रिप्टो मेल्ट-अप रेजीम। दुर्लभ, लेकिन इसे पहले से खारिज न करें।
पॉज़िटिविटी और स्टेशनैरिटी
क्योंकि अब भी योगात्मक रूप से बनाया गया है, हमें प्रत्येक टर्म को नॉन-नेगेटिव रखने की ज़रूरत है। पर्याप्त पॉज़िटिविटी शर्तें हैं
ध्यान दें कि खुद नेगेटिव हो सकता है जब तक है, ताकि बुरी-खबर-के-बाद का प्रभाव कभी नेगेटिव न हो।
कोवेरियंस स्टेशनैरिटी के लिए, मान लें कि इनोवेशन्स शून्य के आसपास सममित रूप से स्टैंडर्डाइज़्ड हैं, ताकि हो और इंडिकेटर औसतन का योगदान दे। स्टेशनैरिटी शर्त बन जाती है
अनकंडीशनल (long-run) वेरिएंस फिर है
यह भाग 1 के परिणाम का GJR एनालॉग है, जिसमें अतिरिक्त टर्म लीवरेज हाफ-लाइफ के औसत योगदान का हिसाब रखता है। अगर आपका इनोवेशन डिस्ट्रीब्यूशन स्क्यूड है (नीचे Hansen का skew-), तो की जगह की वास्तविक प्रायिकता आती है, लेकिन रिपोर्ट किए गए पर्सिस्टेंस के लिए मानक संदर्भ है।
EGARCH: लॉग-वेरिएंस मॉडल करना, बिना पॉज़िटिविटी की बाध्यता के
GJR आपको वेरिएंस-पॉज़िटिविटी की सीमाओं में बांधे रखता है: हर पैरामीटर संयोजन को असमानता की शर्तों के विरुद्ध जांचना पड़ता है, जो ऑप्टिमाइज़ेशन के दौरान परेशान करने वाला है और रोलिंग री-एस्टिमेशन के दौरान और भी बुरा जब कोई विंडो कभी-कभार एक अव्यवहार्य क्षेत्र में भटक जाती है। Nelson का Exponential GARCH (1991) कंडीशनल वेरिएंस का लघुगणक (logarithm) मॉडल करके इसे पूरी तरह टाल देता है। क्योंकि कोई भी वास्तविक संख्या हो सकता है, पैरामीटर चाहे जो भी हों, स्वतः पॉज़िटिव होता है। कोई बाध्यता लगाने की ज़रूरत नहीं।
स्टैंडर्डाइज़्ड इनोवेशन के संदर्भ में रिकर्शन लिखें:
दो टर्म शॉक को वहन करते हैं, और उन्हें अलग करना ही पूरा विचार है:
- मैग्निट्यूड टर्म शॉक के आकार पर प्रतिक्रिया करता है, चिह्न हटाकर। घटाने से यह सेंटर हो जाता है ताकि औसत-आकार का शॉक कोई योगदान न दे। एक स्टैंडर्ड नॉर्मल के लिए, ; एक स्टैंडर्डाइज़्ड Student- के लिए एक्सपेक्टेड एब्सोल्यूट वैल्यू छोटा होता है और पर निर्भर करता है, लेकिन
archइसे आंतरिक रूप से संभालता है। - साइन टर्म असममितता है। यह साइन्ड इनोवेशन में लीनियर है, इसलिए एक नेगेटिव , को पॉज़िटिव के विपरीत दिशा में धकेलता है।
साइन कन्वेंशन मायने रखता है और लोगों को उलझा देता है। इस पैरामीटराइज़ेशन में लीवरेज इफेक्ट (बुरी खबर वोलैटिलिटी बढ़ाती है) के अनुरूप है: एक नेगेटिव शॉक तब बनाता है, जिससे log-वेरिएंस बढ़ता है। यह GJR के से विपरीत चिह्न है। कन्वेंशन के लिए हमेशा मॉडल के अपने दस्तावेज़ीकरण को पढ़ें, अपनी याददाश्त पर भरोसा न करें; arch EGARCH को अपने चिह्न के साथ रिपोर्ट करता है, और हम इसे नीचे न्यूज़ इम्पैक्ट कर्व के विरुद्ध जांचते हैं।
क्योंकि सब कुछ लॉग में योगात्मक है, EGARCH(1,1) का पर्सिस्टेंस पर एकल ऑटोरिग्रेसिव गुणांक द्वारा नियंत्रित होता है; स्टेशनैरिटी के लिए केवल चाहिए। यह GJR की असमानता से कहीं ज़्यादा साफ-सुथरी शर्त है, और जब आप रोलिंग विंडोज़ पर दोबारा फिट करते हैं तो यह एक असली व्यावहारिक फायदा है।
एक सूक्ष्म बात कहने लायक है: EGARCH की शॉक्स पर प्रतिक्रिया इनोवेशन में एक्सपोनेंशियल है (आप अंत में एक्सपोनेंशिएट करते हैं), जबकि GJR क्वाड्रेटिक है। इसलिए EGARCH बड़े शॉक्स पर ज़्यादा हिंसक प्रतिक्रिया करता है — क्रिप्टो में यह एक फीचर है, जहां टेल इवेंट्स ही मायने रखते हैं, लेकिन यह एक कारण भी है कि EGARCH किसी आउटलायर दिन के बाद अनुचित रूप से बड़ा वेरिएंस फोरकास्ट दे सकता है। कोई भी सार्वभौमिक रूप से बेहतर नहीं है; आप out-of-sample फिट और रिस्क बैकटेस्ट्स से चुनते हैं, जो इस पूरी सीरीज़ का मकसद है।
न्यूज़ इम्पैक्ट कर्व
सममित GARCH, GJR, और EGARCH के बीच का अंतर देखने का सबसे साफ तरीका न्यूज़ इम्पैक्ट कर्व (Engle and Ng, 1993) है: को उसके long-run स्तर पर स्थिर रखें और अगली-अवधि कंडीशनल वेरिएंस को अंतिम शॉक के फलन के रूप में प्लॉट करें। यह जवाब देता है "इस आकार और चिह्न के शॉक को देखते हुए, मॉडल कल की वोलैटिलिटी को कितना बढ़ाता है?"
- सममित GARCH शून्य पर केंद्रित एक सममित परबोला बनाता है। एक और एक शॉक एक ही ऊंचाई पर आते हैं। यही वह खामी है जिसे हम ठीक कर रहे हैं।
- GJR शून्य पर एक किंक वाला परबोला बनाता है — जब हो तो बाईं ओर (नेगेटिव शॉक्स) दाईं ओर से ज़्यादा तीखा। दोनों हिस्सों की वक्रता क्रमशः और होती है।
- EGARCH एक असममित, एक्सपोनेंशियल V-आकार बनाता है: टर्म के कारण दोनों भुजाओं का ढलान अलग होता है, और अंतिम एक्सपोनेंशिएशन के कारण पूरी चीज़ परबोला से तेज़ ऊपर की ओर मुड़ती है।
हम बाद में, इम्प्लीमेंटेशन सेक्शन में, फिट किए गए पैरामीटर्स से तीनों को प्लॉट करते हैं — यह असममितता के फायदे को बताने के लिए सबसे उपयोगी डायग्नोस्टिक है।
हैवी टेल्स: Student-t और Skewed-t इनोवेशन्स
असममितता शॉक्स के चिह्न पर मॉडल की प्रतिक्रिया को ठीक करती है। यह खुद शॉक्स के डिस्ट्रीब्यूशन के बारे में कुछ नहीं करती। सामान्य GARCH मानता है, और यह धारणा क्रिप्टो के लिए लगभग हमेशा गलत होती है। GARCH के वोलैटिलिटी क्लस्टरिंग को हटाने के बाद भी, स्टैंडर्डाइज़्ड रेजिड्युअल्स अतिरिक्त कर्टोसिस बनाए रखते हैं — वे फैट-टेल्ड हैं। एक गॉसियन लाइकलीहुड, डिस्ट्रीब्यूशन के कंधों को फिट करते हुए, यह कम आंकता है कि एक -, -, या -सिग्मा स्टैंडर्डाइज़्ड दिन असल में कितनी बार होता है।
रिस्क के लिए परिणाम प्रत्यक्ष है। एक गॉसियन 99% VaR क्वांटाइल का उपयोग करता है, इसलिए यह की भविष्यवाणी करता है। अगर सही स्टैंडर्डाइज़्ड डिस्ट्रीब्यूशन Student- है, मान लें डिग्री ऑफ फ्रीडम के साथ, तो सही 1% क्वांटाइल लगभग है — गॉसियन VaR उस कॉन्फिडेंस स्तर पर लगभग आशावादी है। आप इसे 1% समय से कहीं ज़्यादा बार तोड़ेंगे और "असंभव" दिनों से व्यवस्थित रूप से हैरान होंगे। यह कोई क्रिप्टो की विचित्रता नहीं है; Bollerslev (1987) ने ठीक इसीलिए -GARCH पेश किया क्योंकि इक्विटी और FX रेजिड्युअल्स में भी वही फैट टेल्स दिखे थे। क्रिप्टो उसी समस्या का एक ज़्यादा चरम संस्करण भर है।
स्टैंडर्डाइज़्ड Student-t
Student- डेंसिटी में एक डिग्री-ऑफ-फ्रीडम पैरामीटर होता है जो टेल की मोटाई नियंत्रित करता है: छोटा मतलब फैट टेल्स, और जब होता है तो गॉसियन में बदल जाता है। समस्या यह है कि कच्चे डिस्ट्रीब्यूशन का वेरिएंस है, इसलिए इसे इनोवेशन के रूप में उपयोग करने से पहले हमें इसे यूनिट वेरिएंस में स्टैंडर्डाइज़ करना होगा — अन्यथा GARCH रिकर्शन में "" असल में कंडीशनल स्टैंडर्ड डेविएशन नहीं होगा।
यूनिट वेरिएंस वाले स्टैंडर्डाइज़्ड Student- इनोवेशन की डेंसिटी है
अंदर के पर ध्यान दें — यही स्टैंडर्डाइज़ेशन है, जो इस तरह री-स्केल करता है कि हो। GARCH कंडीशनल वेरिएंस और को देखते हुए, एक ऑब्ज़र्वेशन का लॉग-लाइकलीहुड योगदान है
टर्म से में ट्रांसफॉर्मेशन का जैकोबियन है — वही टर्म जो आपने भाग 1 में गॉसियन GARCH लाइकलीहुड में देखा था। केवल आकार बदलता है। GARCH पैरामीटर्स और पर संयुक्त रूप से को मैक्सिमाइज़ करना ठीक वही है जो arch तब करता है जब आप dist='t' पास करते हैं।
अनुमानित खुद जानकारीपूर्ण है। दैनिक BTC/ETH रिटर्न्स के लिए आप आमतौर पर रेंज में पहुंचते हैं — हैवी टेल्स, लेकिन फाइनाइट वेरिएंस (जिसके लिए चाहिए) और आमतौर पर फाइनाइट कर्टोसिस (जिसके लिए चाहिए) के साथ। अगर आपका फिट किया गया 4 से नीचे गिरता है, तो जान लें कि मॉडल में सैंपल कर्टोसिस तकनीकी रूप से अनंत है और कुछ एस्टिमेटर्स अस्थिर हो जाते हैं; यह आउटलायर्स और डेटा क्वालिटी को गंभीरता से देखने का संकेत है।
Hansen का Skewed-t
Student- फैट-टेल्ड है लेकिन फिर भी सममित है — बाईं और दाईं टेल समान रूप से भारी होती हैं। क्रिप्टो रिटर्न रेजिड्युअल्स अक्सर स्क्यूड भी होते हैं: बाईं टेल (क्रैशेस) दाईं से भारी होती है। Hansen का skewed- (1994) के साथ-साथ एक स्क्यूनेस पैरामीटर के साथ स्टैंडर्डाइज़्ड को सामान्यीकृत करता है:
जहां कॉन्स्टेंट्स , , और इस तरह चुने जाते हैं कि हर मान्य के लिए का मीन शून्य और वेरिएंस यूनिट हो। डिस्ट्रीब्यूशन पर विभाजित होता है, हर हिस्से में अलग स्केलिंग का उपयोग करके एक टेल में ज़्यादा मास मोड़ता है।
इंटरप्रिटेशन: एक लेफ्ट-स्क्यूड डिस्ट्रीब्यूशन देता है (भारी डाउनसाइड), जो क्रिप्टो के लिए सामान्य खोज है और जिसे आप लीवरेज इफेक्ट के साथ जोड़ने की उम्मीद करेंगे। सममित Student- को वापस लाता है, इसलिए का टेस्ट बताता है कि स्क्यू टर्म कुछ फायदा दे रहा है या नहीं। arch में यह dist='skewt' है, जो और दोनों का अनुमान लगाता है। फायदा एक ऐसा VaR है जिसका लेफ्ट-टेल क्वांटाइल ईमानदारी से उसके राइट-टेल क्वांटाइल से भारी होता है — ठीक वही जो आप चाहते हैं जब आप जिन नुकसानों से बचना चाहते हैं वे असममित हों। यह पोज़िशन आउटकम्स में नुकसान बनाम मुनाफे की असममितता से सीधे जुड़ता है: के ड्रॉडाउन को ठीक होने के लिए से ज़्यादा चाहिए होता है, इसलिए लेफ्ट टेल को गलत मॉडल करना राइट टेल को गलत मॉडल करने से ज़्यादा महंगा है।
Python इम्प्लीमेंटेशन
अब हम arch लाइब्रेरी के साथ यह सब फिट करते हैं। सेटअप भाग 1 जैसा है: दैनिक रिटर्न्स खींचें, न्यूमेरिकल कंडीशनिंग के लिए 100 से स्केल करें (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/7 ट्रेड होता है, इसलिए हम 365 से वार्षिकीकरण (annualize) करते हैं, न कि 252 से — जब आप क्रिप्टो शार्प या वोल की तुलना किसी इक्विटी डेस्क के आंकड़ों से करते हैं तो यह भ्रम का एक छोटा लेकिन बार-बार आने वाला स्रोत है।
चार मॉडल्स फिट करना
arch में पैटर्न: vol='Garch' के साथ p=1, q=1 सममित 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 आर्ग्यूमेंट असममित () टर्म को नियंत्रित करता है और p/q मैग्निट्यूड और लैग टर्म्स को नियंत्रित करते हैं; o=1, p=1, q=1 मानक EGARCH(1,1) है। एक बात ध्यान देने की: arch में EGARCH के पैरामीटर नाम वही अक्षर हैं लेकिन असममितता टर्म पर साइन कन्वेंशन Nelson का है, इसलिए एक नेगेटिव एस्टिमेट लीवरेज इफेक्ट है। हम इसे याददाश्त के बजाय न्यूज़ इम्पैक्ट कर्व से वेरिफाई करते हैं।
GJR फिट को पढ़ना
एक GJR- पैरामीटर टेबल कुछ इस तरह दिखती है (उदाहरण मान, कोई रिपोर्ट किया गया प्रयोग नहीं — अपने डेटा पर दोबारा फिट करें):
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जिसका -स्टैट 3 से ऊपर है, एक सांख्यिकीय रूप से महत्वपूर्ण लीवरेज इफेक्ट है। एक नेगेटिव शॉक के बाद स्क्वायर्ड-शॉक इम्पैक्ट है; एक पॉज़िटिव शॉक के बाद यह सिर्फ है। बुरी खबर इस मॉडल की वोलैटिलिटी को समान आकार की अच्छी खबर से लगभग ज़्यादा हिलाती है।nu = 4.3हैवी टेल्स की पुष्टि करता है — गॉसियन () से बहुत दूर, और इतना कम कि चौथा मोमेंट मुश्किल से फाइनाइट है। इस सीरीज़ पर गॉसियन VaR बुरी तरह आशावादी होगा।- पर्सिस्टेंस है — बहुत ऊंचा, दैनिक क्रिप्टो के लिए सामान्य: शॉक्स धीरे-धीरे क्षय होते हैं और वोलैटिलिटी दृढ़ता से क्लस्टर्ड है।
जांचने के लिए सबसे महत्वपूर्ण लाइन रो है। अगर इसका -वैल्यू बड़ा है, तो असममित टर्म इस एसेट और विंडो पर अपनी जगह नहीं कमा रहा है, और आपको सरल सममित मॉडल को प्राथमिकता देनी चाहिए। यह मॉडल-चयन अनुशासन है, सजावट नहीं — इस पर नीचे और।
इंफॉर्मेशन क्राइटेरिया द्वारा मॉडलों की तुलना
जब आप पैरामीटर जोड़ते हैं तो लॉग-लाइकलीहुड हमेशा सुधरता है, इसलिए आप केवल लॉग-लाइकलीहुड पर चयन नहीं कर सकते। 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))
अंगूठे का नियम: बेसलाइन से ~6 से ज़्यादा का BIC सुधार इस बात का मज़बूत सबूत है कि अतिरिक्त संरचना असली है; 1–2 का अंतर शोर है। अगर GJR-t, GARCH-N को 30+ BIC पॉइंट्स से हराता है लेकिन GJR-skewt, GJR-t को केवल 1 पॉइंट से हराता है, तो को रखें और स्क्यू को हटा दें — स्क्यू पैरामीटर इस डेटा पर खुद के लिए भुगतान नहीं कर रहा। AIC/BIC को out-of-sample वेलिडेशन का विकल्प न समझें; वे कॉम्प्लेक्सिटी के हिसाब से समायोजित इन-सैंपल फिट को इनाम देते हैं, जो ज़रूरी है लेकिन पर्याप्त नहीं। असली टेस्ट 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 कर्व शून्य पर केंद्रित एक साफ परबोला है — एक और शॉक समान वेरिएंस देते हैं। GJR-t मूल बिंदु पर एक किंक वाला परबोला है, बाईं भुजा पर ऊंचा। EGARCH-t एक्सपोनेंशियल V है, और अगर इसकी बाईं भुजा दाईं से ऊपर बैठती है तो आपने लीवरेज इफेक्ट और साइन कन्वेंशन दोनों को एक नज़र में कन्फर्म कर लिया है। अगर EGARCH की बाईं भुजा दाईं से नीचे बैठती है, तो या तो पॉज़िटिव अनुमानित हुआ (एक अप-वोल रेजीम) या आपके पास चिह्न उल्टा है — प्लॉट आपको बिना किसी अनुमान के बताता है कि कौन सा।
चारों मॉडल्स की साथ-साथ तुलना
रिस्क की ओर बढ़ने से पहले, चारों मॉडल्स को एक साथ रखना मददगार है। हर पंक्ति एक डिज़ाइन निर्णय है, और कॉलम दिखाते हैं कि वह निर्णय क्या खर्च करता है और क्या देता है।
| गुण | GARCH-N | GJR-t | EGARCH-t | GJR-skewt |
|---|---|---|---|---|
| असममितता (शॉक का चिह्न) | कोई नहीं | थ्रेशोल्ड | साइन्ड | थ्रेशोल्ड |
| इनोवेशन का टेल आकार | गॉसियन | Student- | Student- | skewed- |
| इनोवेशन में स्क्यू | नहीं | नहीं | नहीं | हां () |
| पॉज़िटिविटी बाध्यताएं | हां | हां () | कोई नहीं (लॉग फॉर्म) | हां |
| स्टेशनैरिटी शर्त | ||||
| बेसलाइन से अतिरिक्त पैरामीटर | 0 | |||
| सामान्य क्रिप्टो निर्णय | VaR बैकटेस्ट में विफल | मज़बूत, दृढ़ | मज़बूत, दृढ़ | GJR-t से मामूली बेहतर |
आत्मसात करने वाला पैटर्न: कॉलम 1 से कॉलम 2 की छलांग — एक साथ असममितता और फैट टेल्स जोड़ना — जहां लगभग सारा रिस्क-कैलिब्रेशन सुधार रहता है। बाद के परिष्करण (EGARCH का फंक्शनल फॉर्म, स्क्यू टर्म) असली हैं लेकिन दूसरे दर्जे के, और कई क्रिप्टो सीरीज़ पर वे शोर के भीतर होते हैं। अपना मॉडलिंग बजट पहली छलांग पर खर्च करें और बाकी के प्रति संदेहशील रहें।
रिस्क एप्लिकेशन: VaR और Expected Shortfall
एक फैंसी वोलैटिलिटी मॉडल फिट करना तभी सार्थक है जब यह किसी निर्णय को बेहतर बनाए। सुधारने के लिए सबसे साफ निर्णय एक-स्टेप टेल-रिस्क फोरकास्ट है: कल कितना बुरा हो सकता है? हम फिट किए गए GARCH-/skew- फोरकास्ट से सीधे एक-दिन-आगे का Value-at-Risk और Expected Shortfall (उर्फ Conditional VaR, जिसे HRP/CVaR पोर्टफोलियो पाइपलाइन अपने उद्देश्य के रूप में उपयोग करती है) प्रोड्यूस करते हैं।
कंडीशनल डिस्ट्रीब्यूशन से VaR तक
GARCH मशीनरी कंडीशनल मीन और कंडीशनल स्टैंडर्ड डेविएशन का एक-स्टेप फोरकास्ट देती है। रिटर्न को के रूप में मॉडल किया जाता है, जहां फिट किए गए स्टैंडर्डाइज़्ड डिस्ट्रीब्यूशन (गॉसियन, , या skew-) से लिया जाता है। तो रिटर्न का -क्वांटाइल स्टैंडर्डाइज़्ड डिस्ट्रीब्यूशन के -क्वांटाइल का बस एक अफाइन ट्रांसफॉर्म है:
जहां स्टैंडर्डाइज़्ड इनोवेशन का क्वांटाइल (इनवर्स CDF) है और आगे का माइनस चिह्न इस कन्वेंशन का पालन करता है कि VaR एक पॉज़िटिव नुकसान संख्या है। 99% VaR के लिए, है और आप प्लग इन करते हैं। /skew- का पूरा फायदा यहां दिखता है: गॉसियन से ज़्यादा नेगेटिव है, इसलिए VaR ईमानदारी से बड़ा है।
Expected Shortfall
VaR आपको थ्रेशोल्ड बताता है; यह इस बारे में कुछ नहीं कहता कि जब उल्लंघन होता है तो यह कितना बुरा है। Expected Shortfall — VaR से अधिक होने की शर्त पर औसत नुकसान — यह बताता है, और यह कोहेरेंट (सब-एडिटिव) है, यही कारण है कि यह CVaR ऑप्टिमाइज़ेशन के पीछे का रिस्क माप है और क्यों Basel इस पर स्थानांतरित हुआ। एक लोकेशन-स्केल मॉडल के लिए,
कंडीशनल-टेल-एक्सपेक्टेशन टर्म के मानक डिस्ट्रीब्यूशन्स के लिए क्लोज़्ड फॉर्म हैं। गॉसियन के लिए, के साथ,
जहां स्टैंडर्ड नॉर्मल pdf है। डिग्री ऑफ फ्रीडम और (स्टैंडर्डाइज़्ड स्केल पर) के साथ स्टैंडर्डाइज़्ड Student- के लिए, टेल एक्सपेक्टेशन है
जहां स्टैंडर्डाइज़्ड- pdf है। Expected Shortfall गॉसियन वाले से VaR से ज़्यादा मार्जिन से अधिक है, क्योंकि टेल केवल आगे ही नहीं है — यह ज़्यादा मोटी भी है, इसलिए थ्रेशोल्ड से आगे का औसत नुकसान असमान रूप से बड़ा होता है। यह अतिरिक्त अंतर वह संख्या है जिसे एक गॉसियन मॉडल आपसे छुपाता है।
फिट किए गए arch मॉडल से VaR और ES की गणना
arch डिस्ट्रीब्यूशन्स एक ppf (क्वांटाइल) मेथड एक्सपोज़ करते हैं, इसलिए हम बिना कुछ दोबारा derive किए सीधे स्टैंडर्डाइज़्ड क्वांटाइल पा सकते हैं। 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 कॉलम एक ही संख्या में पूरी कहानी है। गॉसियन मॉडल का उपयोग करता है; वाला लगभग के पास कुछ उपयोग करता है; skew- बाएं क्वांटाइल को और आगे धकेलता है जबकि दाएं को अंदर खींचता है। समान , काफी बड़ा VaR। अगर आप क्रिप्टो पर गॉसियन VaR चला रहे हैं, तो यह वह अंतर है जिसे आप चुपचाप सोख रहे हैं।
एक-स्टेप बनाम मल्टी-स्टेप: एक चेतावनी
ऊपर सब कुछ एक एक-दिन-आगे फोरकास्ट है, और यहीं GARCH VaR सबसे साफ है। दो चीज़ें लंबी अवधियों को जटिल बनाती हैं और एक्सट्रापोलेट करने से पहले आपको इन्हें जानना चाहिए।
पहला, वेरिएंस फोरकास्ट्स मीन-रिवर्ट होते हैं। एक स्टेशनरी GARCH से -स्टेप-आगे कंडीशनल वेरिएंस, जैसे-जैसे बढ़ता है, अनकंडीशनल स्तर की ओर कन्वर्ज होता है, और क्युमुलेटिव -दिन वेरिएंस प्रति-स्टेप फोरकास्ट्स का योग है — यह नहीं है जब तक वोलैटिलिटी अपने long-run मीन पर न हो। भोला "square-root-of-time" स्केलिंग इस मीन रिवर्शन को नज़रअंदाज़ करता है और ठीक शॉक के बाद गलत होता है, जब आपको उस संख्या की सबसे ज़्यादा ज़रूरत होती है। मॉडल के अपने मल्टी-स्टेप वेरिएंस पथ का उपयोग करें।
दूसरा, मल्टी-डे रिटर्न का डिस्ट्रीब्यूशन एक-दिन के इनोवेशन जैसा आकार नहीं है। (नॉनलीनियर GARCH रिकर्शन के ज़रिए) कई -डिस्ट्रीब्यूटेड दैनिक शॉक्स को जोड़ना -दिन क्षितिज पर डिस्ट्रीब्यूशन नहीं देता; कोई साफ क्लोज़्ड फॉर्म नहीं है। मल्टी-डे VaR के लिए ईमानदार रास्ता सिमुलेशन है: फिट किए गए स्टैंडर्डाइज़्ड डिस्ट्रीब्यूशन से इनोवेशन पथ खींचें, सिमुलेटेड रिटर्न पथ पाने के लिए उन्हें GARCH रिकर्शन से गुज़ारें, -दिन रिटर्न्स में एकत्र करें, और एम्पिरिकल क्वांटाइल पढ़ें। यह skew- मामले को भी स्वाभाविक रूप से संभालता है, जहां कोई एनालिटिकल मल्टी-होराइज़न क्वांटाइल बिल्कुल नहीं है। इस पोस्ट के एक-स्टेप एनालिटिकल फॉर्मूला सटीक हैं; किसी भी मल्टी-स्टेप शॉर्टकट को वेलिडेट करने योग्य एक सन्निकटन (approximation) मानें।
VaR को बैकटेस्ट करना: Kupiec और Christoffersen
एक VaR फोरकास्ट एक प्रोबेबिलिस्टिक दावा है: "नुकसान दिनों में ही इस थ्रेशोल्ड से अधिक होगा।" आप इसे वॉक-फॉरवर्ड एवैल्यूएशन में उल्लंघन (violations) (जिन दिनों वास्तविक नुकसान फोरकास्ट किए गए VaR से अधिक हुआ) गिनकर और दो बातें जांचकर टेस्ट करते हैं। पहला, क्या उल्लंघन की दर सही है? दूसरा, क्या उल्लंघन स्वतंत्र हैं, या वे क्लस्टर होते हैं (जिसका मतलब है कि मॉडल ठीक तब विफल होता है जब यह मायने रखता है, वोलैटिलिटी स्पाइक्स के दौरान)?
मान लें उल्लंघन क्रम है, दिनों में उल्लंघनों की संख्या है, और अवलोकित दर है। लक्ष्य दर ।
Kupiec का अनकंडीशनल कवरेज टेस्ट (1995) एक likelihood ratio के ज़रिए जांचता है:
Christoffersen का इंडिपेंडेंस टेस्ट (1998) जांचता है कि आज का उल्लंघन कल के उल्लंघन से भविष्यवाणी योग्य नहीं है। मान लें उल्लंघन क्रम में स्टेट से स्टेट में ट्रांज़िशन गिनता है, , , और । तब
दोनों मिलकर कंडीशनल कवरेज टेस्ट बनाते हैं, जो सही दर और स्वतंत्रता दोनों को एक साथ जांचता है। एक मॉडल 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 या rolling विंडो पर दोबारा फिट करते हैं (या कम से कम दोबारा फोरकास्ट करते हैं) और हर out-of-sample दिन के लिए एक-स्टेप-आगे VaR रिकॉर्ड करते हैं, फिर उसे उस दिन के वास्तविक नुकसान से तुलना करते हैं। VaR को कभी इन-सैंपल बैकटेस्ट न करें — जिस क्रैश की भविष्यवाणी करने के लिए कहा जा रहा है उसी पर फिट किया गया मॉडल असल से कहीं बेहतर दिखेगा। यह बैकटेस्ट-लाइव समता जैसा ही अनुशासन है: एवैल्यूएशन में केवल निर्णय के समय उपलब्ध जानकारी का उपयोग होना चाहिए।
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-Normal Kupiec में विफल होता है (बहुत ज़्यादा उल्लंघन, बहुत छोटा p_uc) जबकि GJR- या EGARCH- पास होता है या पास के करीब आता है। यह विरोधाभास इस पूरी पोस्ट के तर्क को एक हाइपोथीसिस टेस्ट के रूप में प्रस्तुत करता है। अगर मॉडल भी क्लस्टर्ड उल्लंघन दिखाता है (छोटा p_ind), तो आपकी वोलैटिलिटी डायनामिक्स अब भी मिसस्पेसिफाइड है — अक्सर यह संकेत कि आपको एक लंबी मेमोरी (component/FIGARCH) या एक रेजीम लेयर चाहिए, जो HMMs के साथ रेजीम डिटेक्शन से जुड़ता है।
मॉडलों को केवल पास/फेल से नहीं, टेल लॉस से रैंक करना
Kupiec और Christoffersen एक बाइनरी फैसला देते हैं — मॉडल या तो रिजेक्ट होता है या नहीं। यह ज़रूरी है लेकिन मोटा (coarse) है: दो मॉडल दोनों "पास" हो सकते हैं जबकि एक अर्थपूर्ण रूप से ज़्यादा तीक्ष्ण है। प्रतिस्पर्धी VaR फोरकास्ट्स को रैंक करने के लिए, उन्हें क्वांटाइल के लिए एक strictly consistent लॉस फंक्शन, पिनबॉल (क्वांटाइल) लॉस, से स्कोर करें:
जहां (साइन्ड) VaR क्वांटाइल है और वास्तविक रिटर्न। out-of-sample दिनों पर औसत करने पर, कम मीन पिनबॉल लॉस का मतलब है बेहतर-कैलिब्रेटेड और ज़्यादा तीक्ष्ण क्वांटाइल; क्योंकि लॉस -क्वांटाइल के लिए consistent है, इसे मिनिमाइज़ करना किसी मॉडल को आलसी रूप से चौड़ा होने के लिए इनाम नहीं देता। दो मॉडलों की औपचारिक रूप से तुलना करने के लिए, उनके प्रति-दिन लॉस अंतरों को एक 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))
विशेष रूप से Expected Shortfall के लिए, ध्यान दें कि ES अपने आप में एलिसिटेबल (elicitable) नहीं है (कोई ऐसा लॉस फंक्शन नहीं है जिसका मिनिमाइज़र अकेले ES हो), जो एक वास्तविक सैद्धांतिक पेच है: आप ES को VaR के साथ संयुक्त रूप से Fissler-Ziggel स्कोरिंग नियमों का उपयोग करके एवैल्यूएट करते हैं, या आप इस सरल प्रैक्टिस पर वापस जाते हैं कि जांचें कि औसत उल्लंघन मैग्निट्यूड मॉडल के अनुमानित ES से मेल खाता है। एक मोटा लेकिन उपयोगी ES चेक: VaR-उल्लंघन के दिनों में, उन दिनों पर औसत वास्तविक नुकसान की तुलना औसत फोरकास्ट ES से करें — वे करीब होने चाहिए।
नियामक फ्रेमिंग Basel ट्रैफिक-लाइट दृष्टिकोण है: 250 ट्रेडिंग दिनों में, 99% VaR के 0-4 उल्लंघन "हरा" (स्वीकार्य) है, 5-9 "पीला" (जांच) है, 10+ "लाल" (मॉडल रिजेक्ट हो जाता है और कैपिटल मल्टीप्लायर बढ़ जाते हैं) है। यह Kupiec का एक मोटा चचेरा भाई है, लेकिन यह वह भाषा है जो रिस्क कमेटियां असल में बोलती हैं, और इसे LR स्टैटिस्टिक्स के साथ रिपोर्ट करना उचित है।
व्यावहारिक विचार
जब अतिरिक्त पैरामीटर फायदा नहीं देते
ईमानदार डिफ़ॉल्ट कॉम्प्लेक्सिटी के प्रति संदेह है। हर पैरामीटर जो आप जोड़ते हैं, एक ऐसा नॉब है जिसे ऑप्टिमाइज़र ओवरफिट कर सकता है, और असममित फैट-टेल्ड GARCH में इनमें से कई हैं। ठोस मार्गदर्शन:
- इलिक्विड या छोटे सैंपल्स। कुछ सौ दैनिक अवलोकनों के साथ, और पर स्टैंडर्ड एरर बड़ा होगा, और आप उन असममितताओं को "पहचानेंगे" जो सैंपलिंग शोर हैं। एक नए या पतले altcoin पर, एक सममित GARCH- अक्सर सबसे जटिल मॉडल होता है जिसे डेटा सपोर्ट कर सकता है। 200 दिनों पर skew- EGARCH फिट करना खुद को धोखा देना है।
- स्क्यू टर्म अक्सर अपनी लागत नहीं चुकाता। व्यवहार में, Normal → जाना एक बड़ा, विश्वसनीय सुधार है (फैट टेल्स असली और मज़बूत हैं)। → skew- जाना अक्सर मामूली है — 1 या 2 का BIC लाभ, कभी-कभी नेगेटिव। स्क्यू केवल तभी जोड़ें जब डेटा स्पष्ट रूप से इसकी मांग करे।
- EGARCH बनाम GJR दैनिक डेटा पर आमतौर पर बराबर होता है। वे अलग-अलग फंक्शनल फॉर्म के साथ एक ही गुणात्मक कहानी एनकोड करते हैं। out-of-sample VaR बैकटेस्ट से चुनें, न कि इससे कि किसका इन-सैंपल लॉग-लाइकलीहुड ज़्यादा अच्छा है।
- उच्च फ्रीक्वेंसी उत्तर को बदल देती है। घंटे या मिनट के बार्स पर, इंट्राडे सीज़नैलिटी और माइक्रोस्ट्रक्चर हावी होते हैं, और असममितता चाहे जो भी हो, एक सामान्य दैनिक-शैली का GARCH मिसस्पेसिफाइड होता है। अलग समस्या, अलग टूलिंग।
यह कोई मज़बूत एज न होने पर ईमानदार मूल्यांकन जैसा ही सबक है: एक ज़्यादा जटिल मॉडल जो out-of-sample टेस्टिंग में जीवित नहीं रहता, वह उस सरल मॉडल से बुरा है जिसे उसने बदला, क्योंकि वह सटीकता का भ्रम पैदा करता है। नकारात्मक परिणाम को रिपोर्ट करें — "ETH पर स्क्यू ने मदद नहीं की" — एक असली खोज के रूप में, और मध्यस्थ के रूप में वॉक-फॉरवर्ड ऑप्टिमाइज़ेशन का उपयोग करें, इन-सैंपल AIC का नहीं।
ये वे मार्जिनल्स हैं जिन पर बाकी सब कुछ बनता है
यहां के मॉडल कोई अंतिम बिंदु नहीं हैं; वे joint-risk मशीनरी के लिए यूनिवेरिएट बिल्डिंग ब्लॉक हैं। क्रिप्टो के संयुक्त जोखिम के लिए कोपुला मॉडल पोस्ट vine copula फिट करने से पहले GARCH-EVT मार्जिनल्स के रूप में ठीक EGARCH/GJR- का उपयोग करती है — आप प्रति एसेट एक असममित फैट-टेल्ड GARCH फिट करते हैं, स्टैंडर्डाइज़्ड रेजिड्युअल्स निकालते हैं, और तभी क्रॉस-एसेट डिपेंडेंस मॉडल करते हैं। अगर आपका मार्जिनल एक सममित गॉसियन GARCH है, तो कोपुला उसकी टेल त्रुटियों को विरासत में लेता है चाहे डिपेंडेंस मॉडल कितना भी अच्छा हो। कचरा मार्जिनल्स, कचरा joint VaR।
मल्टीवेरिएट वोलैटिलिटी समस्या के लिए — प्रति-एसेट वेरिएंस के बजाय समय-परिवर्तनशील कोरिलेशन्स — भाग 3, DCC-GARCH देखें, जो इन यूनिवेरिएट फिट्स के ऊपर एक डायनामिक-कोरिलेशन मॉडल लेयर करता है। और एक वोलैटिलिटी फोरकास्ट को पोज़िशन साइज़िंग और एक ट्रेडिंग बैकटेस्ट में बदलने के लिए, वोलैटिलिटी टार्गेटिंग पर भाग 4 इन ठीक इन्हीं मॉडलों से फोरकास्ट्स का उपयोग करता है ताकि एक्सपोज़र को अनुमानित रिस्क के व्युत्क्रमानुपाती स्केल किया जा सके।
एक डिस्ट्रीब्यूशन-फ्री विकल्प
रिस्क सेक्शन में सब कुछ एक पैरामेट्रिक धारणा पर टिका है: कि स्टैंडर्डाइज़्ड रेजिड्युअल्स या skew- का पालन करते हैं। यह धारणा टेस्ट करने योग्य है और आमतौर पर उचित है, लेकिन यह विफल हो सकती है। अगर आप बिल्कुल भी टेल आकार के प्रति प्रतिबद्ध नहीं होना चाहते, तो कॉन्फॉर्मल प्रेडिक्शन फाइनाइट-सैंपल कवरेज गारंटी के साथ डिस्ट्रीब्यूशन-फ्री प्रेडिक्शन इंटरवल देता है — एक वास्तव में अलग दर्शन जो इनोवेशन डिस्ट्रीब्यूशन के बारे में कोई दावा नहीं करता। दोनों दृष्टिकोण पूरक हैं: पैरामेट्रिक GARCH- आपको एक पूर्ण कंडीशनल डेंसिटी देता है (और इसलिए ES, जो कॉन्फॉर्मल इंटरवल्स सीधे नहीं देते), जबकि कॉन्फॉर्मल आपको ऐसा कवरेज देता है जो तब भी बना रहता है जब आपकी डेंसिटी गलत हो। प्रोडक्शन में, दोनों का एक क्रॉस-चेक के रूप में उपयोग करना सस्ता बीमा है।
न्यूमेरिकल और वर्कफ़्लो हाइजीन
- रिटर्न्स को 100 से स्केल करें। GARCH ऑप्टिमाइज़र्स रॉ फ्रैक्शनल रिटर्न्स की तुलना में पर्सेंट रिटर्न्स पर कहीं ज़्यादा विश्वसनीय रूप से कन्वर्ज होते हैं। अगर आप फ्रैक्शनल यूनिट्स में रिपोर्ट करते हैं तो VaR/ES को अनस्केल करना याद रखें।
- पर्सिस्टेंस पर नज़र रखें। अगर अनुमान ~0.999 से ऊपर है, तो मॉडल near-integrated है (IGARCH जैसा); फोरकास्ट्स बहुत धीरे-धीरे मीन-रिवर्ट होते हैं और लंबी-अवधि के वेरिएंस फोरकास्ट अविश्वसनीय हो जाते हैं। ज़रूरी नहीं कि गलत हो, लेकिन इसे फ्लैग करें।
- रोलिंग विंडोज़ पर कन्वर्जेंस विफलताएं। EGARCH का लॉग फॉर्म पॉज़िटिविटी बाध्यताओं से बचता है लेकिन फिर भी किसी पैथोलॉजिकल विंडो पर कन्वर्ज होने में विफल हो सकता है।
fit()को try/except में रैप करें और लाइव बैकटेस्ट को क्रैश करने के बजाय पिछली विंडो के पैरामीटर्स पर वापस जाएं। - मीन मॉडल। हमने पूरे समय एक कॉन्स्टेंट मीन का उपयोग किया। ज़्यादातर दैनिक क्रिप्टो के लिए कंडीशनल मीन शून्य के करीब है और वोलैटिलिटी से दबा हुआ है; इसे फोरकास्ट करने की कोशिश में मॉडल कॉम्प्लेक्सिटी खर्च न करें जब तक आपके पास कोई असली कारण न हो।
सारांश
- सामान्य GARCH(1,1) में दो संरचनात्मक खामियां हैं: यह सममित है ( और पर समान रूप से प्रतिक्रिया करता है क्योंकि शॉक्स के रूप में प्रवेश करते हैं) और यह गॉसियन इनोवेशन्स मानता है (क्रिप्टो की फैट टेल्स को कम आंकते हुए)। दोनों आशावादी VaR के ज़रिए असली पैसे की कीमत चुकाते हैं।
- GJR-GARCH एक थ्रेशोल्ड टर्म जोड़ता है। एक महत्वपूर्ण लीवरेज इफेक्ट है: बुरी खबर वोलैटिलिटी को ज़्यादा बढ़ाती है। पॉज़िटिविटी के लिए चाहिए; पर्सिस्टेंस है।
- EGARCH मॉडल करता है, तो कोई पॉज़िटिविटी बाध्यता नहीं और स्टेशनैरिटी बस है। असममितता एक साइन्ड टर्म (इस कन्वेंशन में लीवरेज है) के ज़रिए प्रवेश करती है, जो एक मैग्निट्यूड टर्म से अलग है।
- न्यूज़ इम्पैक्ट कर्व — अगली-अवधि वेरिएंस बनाम अंतिम शॉक — असममितता को दृश्यमान बनाता है और एक नज़र में EGARCH साइन कन्वेंशन को वेरिफाई करता है।
- Student- इनोवेशन्स (
dist='t') एक डिग्री-ऑफ-फ्रीडम (क्रिप्टो के लिए आमतौर पर 3–6) के ज़रिए टेल्स को ठीक करते हैं; Hansen का skew- (dist='skewt') भारी लेफ्ट टेल के लिए एक स्क्यूनेस जोड़ता है। Normal → जाना एक बड़ा विश्वसनीय लाभ है; → skew- अक्सर मामूली होता है। - VaR और ES फिट किए गए कंडीशनल डिस्ट्रीब्यूशन से आते हैं: , फैट-टेल्ड क्वांटाइल के साथ रिस्क को गॉसियन से ईमानदारी से बड़ा बनाता है। ES (कोहेरेंट, CVaR) VaR से परे औसत नुकसान को पकड़ता है।
- Kupiec और Christoffersen से बैकटेस्ट करें। Kupiec उल्लंघन दर जांचता है; Christoffersen जांचता है कि उल्लंघन क्लस्टर्ड नहीं हैं। एक मॉडल एक में पास हो सकता है और दूसरे में फेल — क्लस्टर्ड उल्लंघन खतरनाक विफलता मोड हैं। सख्ती से out-of-sample बैकटेस्ट करें।
- कॉम्प्लेक्सिटी पर अनुशासन। असममितता/स्क्यू केवल तभी जोड़ें जब यह BIC और out-of-sample 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.
MarketMaker.cc Team
क्वांटिटेटिव रिसर्च और स्ट्रैटेजी