GARCH फोरकास्ट के साथ वोलैटिलिटी टारगेटिंग और ट्रेडिंग
इस सीरीज के पहले तीन भागों ने आपको वोलैटिलिटी फोरकास्ट करना सिखाया। हमने Part 1 में एक यूनिवैरिएट GARCH(1,1) बनाया, Part 2 में GJR और Student-t इनोवेशन के साथ लीवरेज और फैट टेल्स जोड़े, और Part 3 में DCC-GARCH के जरिए समय के साथ पूरी कोवेरियंस मैट्रिक्स को मॉडल किया। हर भाग के अंत में, हमने एक संख्या प्रिंट की: कल की अपेक्षित वोलैटिलिटी। और फिर, अगर ईमानदार रहें, तो हम रुक गए — मानो फोरकास्ट बनाना ही असली मकसद हो।
पर ऐसा नहीं है। वोलैटिलिटी फोरकास्ट कोई P&L नहीं है। किसी को कभी कम QLIKE स्कोर के लिए पैसे नहीं मिले। फोरकास्ट तभी उपयोगी बनता है जब वह ठीक उसी क्षण किसी निर्णय को बदल दे जो आप अन्यथा अलग तरीके से लेते — कितना खरीदना है, कब कटौती करनी है, कितनी पूंजी आवंटित करनी है। अगर आपका फोरकास्ट किसी पोजीशन को नहीं हिलाता, तो उसकी सांख्यिकीय सटीकता एक निजी शौक भर है।
यह अंतिम भाग उस लूप को बंद करने के बारे में है। हम Parts 1-3 के फोरकास्ट लेते हैं और उन्हें सबसे साफ-सुथरे निर्णय में इस्तेमाल करते हैं: वोलैटिलिटी टारगेटिंग — किसी पोजीशन को इस तरह साइज करना कि पोर्टफोलियो की रियलाइज्ड वोलैटिलिटी एक स्थिर टारगेट पर पहुंचे। फिर हम वह करते हैं जिसकी परवाह इस ब्लॉग को किसी एक मॉडल से ज्यादा है: हम ईमानदारी से मूल्यांकन करते हैं। हम GARCH को मूर्ख-लेकिन-मजबूत बेसलाइन (रोलिंग रियलाइज्ड वोल, EWMA) के मुकाबले बेंचमार्क करते हैं, हम ऐसे लॉस फंक्शन इस्तेमाल करते हैं जो इस तथ्य के प्रति रोबस्ट हों कि हम कभी सच्ची वोलैटिलिटी नहीं देख सकते, हम कॉस्ट के साथ और बिना लुक-अहेड के एक वॉक-फॉरवर्ड बैकटेस्ट चलाते हैं, और हम साफ-साफ बताते हैं कि वोल टारगेटिंग क्या देती है और क्या नहीं देती। स्पॉइलर: यह रिस्क-एडजस्टेड रिटर्न सुधारती है और अल्फा पैदा करने से कहीं ज्यादा भरोसेमंद ढंग से ड्रॉडाउन को काबू में रखती है।
वोलैटिलिटी टारगेटिंग ही सही टेस्ट क्यों है
वोलैटिलिटी फोरकास्ट का इस्तेमाल करने के और भी फैंसी तरीके हैं — ऑप्शन प्राइसिंग, VaR लिमिट, डायनामिक हेजिंग — लेकिन वोलैटिलिटी टारगेटिंग वह है जो फोरकास्ट के मूल्य को अन्य दांवों के सबसे कम मिश्रण के साथ अलग करती है। यह विचार एक ही समीकरण है।
एक जोखिम-भरी संपत्ति को सिग्नल-निर्दिष्ट दिशा के साथ पकड़ें (अभी के लिए, सिर्फ "लॉन्ग")। एक स्थिर पोजीशन के बजाय, एक्सपोजर को फोरकास्ट वोलैटिलिटी के व्युत्क्रम अनुपात में स्केल करें:
जहां अगली अवधि की वोलैटिलिटी का आपका फोरकास्ट है (केवल तक के डेटा से बना), और वह वार्षिक वोलैटिलिटी है जिस पर आप स्ट्रैटेजी चलाना चाहते हैं — मान लीजिए 15% या 20%। जब मॉडल शांत बाजार का पूर्वानुमान करता है, तो आप 1.0 की ओर (या उससे आगे) लीवर बढ़ाते हैं; जब यह तूफान का पूर्वानुमान करता है, तो आप सिकुड़ते हैं। स्केल्ड पोजीशन की रियलाइज्ड वोलैटिलिटी, पहले क्रम में, है
जब भी । इसलिए पूरी कवायद की गुणवत्ता एक ही चीज पर टिकी है: आपका फोरकास्ट अगली अवधि की वास्तविक वोलैटिलिटी के कितना करीब है। एक बेहतर फोरकास्ट एक फ्लैटर रियलाइज्ड-वोलैटिलिटी प्रोफाइल पैदा करता है और — जैसा हम देखेंगे — एक बेहतर शार्प रेशियो। यही कारण है कि यह सही टेस्ट है। फोरकास्ट सजावट नहीं है; यह डिनॉमिनेटर है।
यह शार्प क्यों बढ़ाता है और ड्रॉडाउन को नियंत्रित करता है
यहां दो अनुभवजन्य तथ्य काम करते हैं।
वोलैटिलिटी रिटर्न की तुलना में कहीं ज्यादा पूर्वानुमेय है। डेली फ्रीक्वेंसी पर कल के BTC रिटर्न की दिशा लगभग सिक्का उछालने जैसी है; परिमाण नहीं। वोलैटिलिटी क्लस्टर करती है — बड़ी चालों के बाद बड़ी चालें आती हैं — यही वह पूरा कारण है जिसकी वजह से GARCH मौजूद है (Part 1 ने AR(1)-इन-वेरिएंस संरचना निकाली जो इसे एनकोड करती है)। एक दिन आगे की वेरिएंस के लिए 0.4-0.6 का आम बात है; रिटर्न के लिए वही संख्या एक Renaissance-स्तरीय सिग्नल होगी। वोल टारगेटिंग उस मात्रा का लाभ उठाती है जो पूर्वानुमेय है और जो पूर्वानुमेय नहीं है उसके प्रति उदासीन रहती है।
शार्प रेशियो समय के साथ स्थिर नहीं रहते; जब वोलैटिलिटी बढ़ती है तो वे गिरते हैं। क्रिप्टो में हाई-वोलैटिलिटी रेजीम — डीलीवरेजिंग कैस्केड, एक्सचेंज फेल्योर, वे दिन जब सब कुछ 30% गैप करता है — का रिटर्न-प्रति-यूनिट-रिस्क बेहतर नहीं, बदतर होता है। जब भी फोरकास्ट वोल ज्यादा हो तभी यांत्रिक रूप से एक्सपोजर कम करके, आप उन अवधियों को कम भार देते हैं जो ड्रॉडाउन में सबसे ज्यादा और कंपाउंडेड रिटर्न में सबसे कम योगदान करती हैं। Moreira और Muir (2017) ने इक्विटीज के लिए दिखाया कि वोलैटिलिटी-मैनेज्ड पोर्टफोलियो — यही स्केलिंग — शार्प रेशियो बढ़ाते हैं और अनमैनेज्ड फैक्टर के मुकाबले पॉजिटिव अल्फा पैदा करते हैं। यह तंत्र जादू नहीं है; यह पूर्वानुमेय रूप से अशांत विंडो में स्थिर डॉलर पोजीशन रखने से इनकार करना भर है।
ड्रॉडाउन का लाभ और भी सीधा है। मैक्सिमम ड्रॉडाउन पर पोजीशन-रिटर्न डिस्ट्रीब्यूशन की टेल का दबदबा होता है। चूंकि की वोलैटिलिटी के पास पिन की गई है, वह फैट लेफ्ट टेल जिसे एक फिक्स्ड-नोशनल स्ट्रैटेजी वोल विस्फोट के दौरान झेलती है, संकुचित हो जाती है: आप पहले से ही छोटे थे। वोल टारगेटिंग क्रैश का पूर्वानुमान नहीं करती, लेकिन यह व्यवस्थित रूप से तब कम-एक्सपोज्ड होती है जब बाजार उत्तेजित होता है, और उत्तेजना तभी होती है जब क्रैश होते हैं।
Kelly और फ्रैक्शनल साइजिंग से संबंध
वोलैटिलिटी टारगेटिंग Kelly criterion की पहली चचेरी बहन है। अपेक्षित एक्सेस रिटर्न और वेरिएंस वाली एक सिंगल एसेट के लिए, ग्रोथ-ऑप्टिमल (फुल-Kelly) फ्रैक्शन है
अगर आप मान लें कि शार्प रेशियो लगभग स्थिर है — एक मजबूत धारणा, लेकिन वह जो "बाजार जोखिम के लिए स्थिर कीमत चुकाता है" में निहित है — तो और , जो बिल्कुल वोलैटिलिटी टारगेटिंग है जिसमें । दूसरे शब्दों में, वोलैटिलिटी टारगेटिंग इस धारणा के तहत Kelly साइजिंग है कि अपेक्षित रिटर्न वोलैटिलिटी के साथ स्केल करता है। हम Kelly criterion and strategy sizing में फुल और फ्रैक्शनल Kelly को विस्तार से देखते हैं, और यह भी कि कोई समझदार व्यक्ति फुल Kelly पर ट्रेड क्यों नहीं करता। वहां का व्यावहारिक सबक यहां भी लागू होता है: सैद्धांतिक साइज का एक फ्रैक्शन इस्तेमाल करें, क्योंकि डिनॉमिनेटर (आपका वोल फोरकास्ट) और खासकर न्यूमरेटर (अपेक्षित रिटर्न) में एस्टीमेशन एरर पूरी साइजिंग को खतरनाक रूप से आक्रामक बना देता है।
दो और संबंध याद रखने लायक हैं। पहला, वोल टारगेटिंग रिटर्न के सिमेट्रिक डिस्पर्शन पर साइज करती है, लेकिन क्रिप्टो पेऑफ सिमेट्रिक नहीं होते — एक बार लीवरेज और लिक्विडेशन शामिल हो जाने पर 20% डाउन डे की लागत 20% अप डे की दर्पण छवि नहीं होती। हम इस असममिति को loss-profit asymmetry में सीधे संबोधित करते हैं, और एक GJR/EGARCH फोरकास्ट (Part 2) पहले से ही नेगेटिव शॉक्स पर ज्यादा प्रतिक्रिया देकर इसका कुछ हिस्सा में समाहित कर लेता है। दूसरा, वोल फोरकास्ट एक पॉइंट एस्टीमेट है; एक ज्यादा संपूर्ण रिस्क व्यू उसके साथ एक इंटरवल जोड़ता है। Conformal prediction for trading दिखाता है कि मॉडल आउटपुट को डिस्ट्रीब्यूशन-फ्री इंटरवल में कैसे बदला जाए जिनके खिलाफ आप साइज कर सकते हैं, जो इस लेख की ईमानदार-मूल्यांकन थीम के साथ स्वाभाविक रूप से जुड़ता है।
प्रतिद्वंद्वी: GARCH को किसे हराना है
यहीं वह अनुशासन है जो असली मूल्यांकन को डेमो से अलग करता है। GARCH को ताज पहनाने से पहले, आपको उसे ऐसे प्रतिद्वंद्वी देने होंगे जो सस्ते, स्पष्ट, और आश्चर्यजनक रूप से हराना मुश्किल हों। अगर आपका विस्तृत GJR-t मॉडल एक पांच-लाइन EWMA को नहीं हरा सकता, तो आपने कुछ मूल्यवान सीखा है और अपने आप को बहुत सारी प्रोडक्शन जटिलता से बचाया है।
हम अगली अवधि की वोलैटिलिटी के चार फोरकास्टर बेंचमार्क करते हैं।
(a) ट्रेलिंग रियलाइज्ड वोलैटिलिटी (रोलिंग स्टैंडर्ड डिविएशन)
सबसे भोला फोरकास्ट: कल की वोलैटिलिटी पिछले डेली रिटर्न के सैंपल स्टैंडर्ड डिविएशन के बराबर होती है।
इसका एक ही हाइपरपैरामीटर है (विंडो , आम तौर पर 20-60 दिन) और कोई मॉडल नहीं। इसकी खामी यह है कि विंडो में हर ऑब्जर्वेशन को बराबर वेट मिलता है और फिर जब वह बाहर निकलता है तो अचानक एक खाई में गिर जाता है — "घोस्टिंग" या "इको" प्रभाव, जहां एक ही क्रैश डे फोरकास्ट को ठीक दिनों तक फुला देता है और फिर रातोंरात गायब हो जाता है, चाहे बाजार वास्तव में शांत हुआ हो या नहीं।
(b) EWMA / RiskMetrics ()
एक्सपोनेंशियली वेटेड मूविंग एवरेज पुराने स्क्वेयर्ड रिटर्न को ज्यामितीय रूप से क्षीण होता वेट देकर इको समस्या ठीक करता है:
यह RiskMetrics (J.P. Morgan, 1996) एस्टीमेटर है। डेली डेटा के लिए कैनोनिकल के साथ, प्रभावी मेमोरी लगभग दिन है, लेकिन क्षय स्मूथ है — कोई खाई नहीं। ध्यान दें EWMA वास्तव में क्या है: यह और वाला एक इंटीग्रेटेड GARCH(1,1) है, यानी बिना मीन रिवर्जन और बिना लॉन्ग-रन वेरिएंस वाला GARCH। अगर आप स्वीकार करते हैं तो इसमें शून्य फ्री पैरामीटर हैं, और यह पूरे लेख में इकलौती सबसे कठिन बेसलाइन है। "GARCH X को हराता है" जैसे कई पेपर्स चुपचाप आउट ऑफ सैंपल EWMA को हराने में विफल रहते हैं।
import numpy as np
import pandas as pd
def ewma_vol(returns: pd.Series, lam: float = 0.94, sigma0: float | None = None) -> pd.Series:
"""RiskMetrics EWMA conditional volatility (returns in decimal, e.g. 0.03).
sigma2_t = lam * sigma2_{t-1} + (1 - lam) * r_t^2
Returns a series aligned to `returns` where value at t uses info up to t.
"""
r2 = np.square(returns.values)
var = np.empty_like(r2)
var[0] = sigma0**2 if sigma0 is not None else r2[0]
for t in range(1, len(r2)):
var[t] = lam * var[t - 1] + (1.0 - lam) * r2[t - 1] # note: r_{t-1}, no look-ahead
return pd.Series(np.sqrt(var), index=returns.index, name="ewma_vol")
वह एक सूक्ष्मता जो लोगों को उलझा देती है: अवधि के लिए फोरकास्ट (जिसे के दौरान रखी गई पोजीशन को साइज करने में इस्तेमाल किया जा सकता है) से पहले देखे गए रिटर्न से बनाया जाना चाहिए। ऊपर के रिकर्शन में, var[t], r2[t-1] इस्तेमाल करता है, इसलिए यह सीरीज एक वास्तविक वन-स्टेप-अहेड फोरकास्ट है। इस इंडेक्स को सही करना बैकटेस्ट और कल्पना के बीच का फर्क है — इस पर और वॉक-फॉरवर्ड सेक्शन में।
(c) GARCH(1,1) और GJR-t (Parts 1-2)
हमारे नायक। स्टैंडर्ड GARCH(1,1):
लॉन्ग-रन वेरिएंस के साथ और वन-स्टेप फोरकास्ट सीधे रिकर्शन से निकलता है (Part 1)। GJR-GARCH एक्सटेंशन एक लीवरेज टर्म जोड़ता है ताकि नेगेटिव शॉक्स वेरिएंस को पॉजिटिव से ज्यादा बढ़ाएं:
और क्रिप्टो की फैट टेल्स संभालने के लिए Student-t इनोवेशन के साथ जोड़ा गया, यह Part 2 का GJR-t है। GARCH के EWMA को हराने सकने का कारण मीन रिवर्जन है: एक शॉक के बाद, GARCH फोरकास्ट को की दर से की ओर वापस खींचता है, जबकि EWMA (इंटीग्रेटेड होने के कारण) कभी वापस नहीं आता। जब वोलैटिलिटी बढ़ती है और फिर सामान्य हो जाती है — आम मामला — GARCH का फोरकास्ट तेजी से और ज्यादा सटीक रूप से वापस क्षय होता है। जब वोलैटिलिटी वास्तव में स्थायी होती है, तो दोनों लगभग अभेद्य होते हैं।
(d) रियलाइज्ड वेरिएंस पर HAR-RV (अगर आपके पास इंट्राडे डेटा है)
अगर आपके पास इंट्राडे बार हैं — और 24/7 क्रिप्टो बाजारों में लगभग हमेशा होते हैं — तो आप डेली स्क्वेयर्ड रिटर्न से कहीं कम शोरगुल वाला वोलैटिलिटी प्रॉक्सी बना सकते हैं: रियलाइज्ड वेरिएंस, दिन भर के इंट्राडे स्क्वेयर्ड रिटर्न का योग।
Corsi (2009) का Heterogeneous Autoregressive मॉडल कल के रियलाइज्ड वेरिएंस का पूर्वानुमान बीते के डेली, वीकली, और मंथली औसत से करता है — तीन रीग्रेसर के साथ लॉन्ग-मेमोरी पर्सिस्टेंस पकड़ने का एक कच्चा लेकिन उल्लेखनीय रूप से प्रभावी तरीका:
जहां और डेली के ट्रेलिंग 5-दिन और 22-दिन औसत हैं। यह एक सादा OLS रिग्रेशन है, यह उच्च-गुणवत्ता वाले इंट्राडे प्रॉक्सी का लाभ उठाता है, और यह अक्सर चारों में सबसे अच्छा डेली-वोल फोरकास्टर है — अक्सर GARCH को ठीक इसलिए हराता है क्योंकि , की तुलना में एक साफ-सुथरा टारगेट है।
import numpy as np
import pandas as pd
def realized_variance(intraday_returns: pd.Series, day_index) -> pd.Series:
"""Daily realized variance = sum of squared intraday (log) returns per day.
`intraday_returns` indexed by timestamp; `day_index` maps to calendar day.
"""
return intraday_returns.pow(2).groupby(day_index).sum()
def har_features(rv: pd.Series) -> pd.DataFrame:
"""Build HAR regressors from a daily realized-variance series."""
df = pd.DataFrame({"rv": rv})
df["rv_d"] = df["rv"].shift(1) # yesterday
df["rv_w"] = df["rv"].shift(1).rolling(5).mean() # trailing week
df["rv_m"] = df["rv"].shift(1).rolling(22).mean() # trailing month
df["target"] = df["rv"] # predict today's RV
return df.dropna()
def fit_har(rv: pd.Series):
"""Fit HAR-RV by OLS. Returns (coef_dict, predict_fn)."""
df = har_features(rv)
X = np.column_stack([np.ones(len(df)), df["rv_d"], df["rv_w"], df["rv_m"]])
y = df["target"].values
beta, *_ = np.linalg.lstsq(X, y, rcond=None)
names = ["const", "rv_d", "rv_w", "rv_m"]
def predict(rv_d, rv_w, rv_m):
return float(beta @ np.array([1.0, rv_d, rv_w, rv_m]))
return dict(zip(names, beta)), predict
log-HAR पर एक नोट: चूंकि दाईं ओर तिरछा और सख्ती से पॉजिटिव है, कई प्रैक्टिशनर log HAR फीचर्स पर को रीग्रेस करते हैं, जो फिट सुधारता है और पॉजिटिव फोरकास्ट सुनिश्चित करता है। जब आप वापस एक्सपोनेंशिएट करते हैं तो आपको एक हाफ-वेरिएंस Jensen करेक्शन जोड़ना चाहिए, , वरना आप व्यवस्थित रूप से अंडर-फोरकास्ट करेंगे।
चार फोरकास्टर हाथ में — RV, EWMA, GARCH/GJR-t, HAR — सवाल यह बनता है: हम कैसे तय करें कि कौन सबसे अच्छा है, जब हम कभी उस चीज को देख ही नहीं सकते जिसे वे सभी पूर्वानुमानित करने की कोशिश कर रहे हैं?
एक वोलैटिलिटी फोरकास्ट का ईमानदार मूल्यांकन
यह लेख की मूल शिक्षा है, इसलिए यहां धीमे चलें।
आप फोरकास्ट की तुलना सच्चे कंडीशनल वेरिएंस से करना चाहते हैं। लेकिन एक लेटेंट मात्रा है — यह डेटा-जनरेटिंग प्रोसेस का एक पैरामीटर है, कभी सीधे देखा नहीं जाता। आपको प्रति दिन केवल एक रियलाइज्ड रिटर्न मिलता है। इसलिए हर वोलैटिलिटी मूल्यांकन असल में सच्चाई के लिए एक शोरगुल वाले प्रॉक्सी के मुकाबले आपके फोरकास्ट की तुलना है। दो मानक प्रॉक्सी:
- स्क्वेयर्ड रिटर्न । एक जीरो-मीन मॉडल के तहत के लिए अनबायस्ड (), लेकिन बेहद शोरगुल वाला: एक सिंगल डेली रिटर्न एक स्टैंडर्ड डिविएशन का वन-ऑब्जर्वेशन एस्टीमेट है। प्रॉक्सी 0 हो सकता है (एक फ्लैट दिन) भले ही सच्ची वोल ऊंची हो, या एक लकी टेल डे पर विशाल।
- रियलाइज्ड वेरिएंस इंट्राडे डेटा से। कहीं कम शोरगुल वाला — इंट्राडे सैंपलिंग व्यक्तिगत सिंगल-रिटर्न शोर को औसत कर देती है — यही ठीक वह कारण है कि HAR-RV काम करता है और आपको प्रॉक्सी के रूप में इस्तेमाल करना चाहिए अगर आपके पास बिल्कुल भी इंट्राडे डेटा है।
वह सूक्ष्मता जो लगभग हर किसी को पकड़ लेती है: चूंकि प्रॉक्सी शोरगुल वाला है, लॉस फंक्शन का चुनाव निर्दोष नहीं है। गलत लॉस के साथ दो फोरकास्ट को रैंक करें और शोरगुल वाला प्रॉक्सी रैंकिंग पलट सकता है, आपको बता सकता है कि खराब फोरकास्ट बेहतर है। Patton (2011) ने ठीक-ठीक पता लगाया कि कौन-से लॉस फंक्शन इस अर्थ में "रोबस्ट" हैं कि शोरगुल वाले प्रॉक्सी पर अपेक्षित लॉस से फोरकास्ट को रैंक करना वही रैंकिंग देता है जो आपको सच्चे (अवलोकन-अयोग्य) वेरिएंस पर मिलती। केवल एक विशिष्ट परिवार योग्य है। व्यवहार में दो सदस्य मायने रखते हैं।
MSE बनाम QLIKE
वेरिएंस पर मीन स्क्वेयर्ड एरर:
जहां फोरकास्ट है और को या द्वारा प्रॉक्सी किया गया है। MSE Patton के अर्थ में रोबस्ट है (इसकी रैंकिंग प्रॉक्सी-कंसिस्टेंट है), लेकिन यह सिमेट्रिक और स्केल-डिपेंडेंट है: यह समान निरपेक्ष आकार के ओवर-फोरकास्ट और अंडर-फोरकास्ट को बराबर दंडित करता है, और यह हाई-वोलैटिलिटी अवधियों की एरर को शांत अवधियों की एरर से कहीं ज्यादा वेट देता है। एक मॉडल जो शांत 95% दिनों को सटीक पकड़ता है लेकिन तीन संकट के दिनों पर वेरिएंस फोरकास्ट में गड़बड़ करता है, MSE के तहत भयानक दिखेगा, भले ही उसका संकट व्यवहार वही हो जो आप वास्तव में चाहते हैं।
QLIKE (क्वासी-लाइकलीहुड) लॉस वर्कहॉर्स है:
यह वेरिएंस पर एक गॉसियन लाइकलीहुड द्वारा निहित लॉस है, यह भी Patton के अर्थ में रोबस्ट है, और इसके दो गुण हैं जो इसे वोलैटिलिटी के लिए पसंदीदा चुनाव बनाते हैं। पहला, यह सही दिशा में असममित है: यह वेरिएंस के अंडर-प्रेडिक्शन को ओवर-प्रेडिक्शन से ज्यादा दंडित करता है। एक रिस्क मैनेजर या वोल-टारगेटर के लिए, वह सही असममिति है — वोल को अंडर-फोरकास्ट करने का मतलब है कि आपने ठीक तब बहुत ज्यादा साइज ले लिया जब उसकी अहमियत थी, जो सबसे महंगी गलती है। दूसरा, यह (लगभग) स्केल-इनवेरिएंट है: क्योंकि यह अनुपात पर निर्भर करता है, एक 10% फोरकास्ट एरर की कीमत लगभग समान होती है चाहे वह शांत दिन पर हो या संकट के दिन पर, इसलिए मूल्यांकन उन कुछ हाई-वेरिएंस ऑब्जर्वेशन द्वारा हाईजैक नहीं होता जैसा MSE के साथ होता है। प्रॉक्सी की हेटेरोस्केडैस्टिसिटी के प्रति वह रोबस्टनेस ठीक वही है जो आप चाहते हैं जब पूरी बात यह हो कि वोलैटिलिटी बेतहाशा बदलती है।
ध्यान दें , बराबरी तभी जब । कम बेहतर है, MSE की तरह ही।
import numpy as np
def qlike(proxy: np.ndarray, forecast_var: np.ndarray) -> np.ndarray:
"""Per-observation QLIKE loss. `proxy` is r^2 or RV (a variance proxy),
`forecast_var` is h = sigma_hat^2. Both strictly positive, same units.
"""
ratio = proxy / forecast_var
return ratio - np.log(ratio) - 1.0
def mse_var(proxy: np.ndarray, forecast_var: np.ndarray) -> np.ndarray:
"""Per-observation MSE on the variance scale."""
return np.square(proxy - forecast_var)
दो ऑपरेशनल चेतावनियां। प्रॉक्सी और फोरकास्ट को समान यूनिट में रखें (दोनों डेली वेरिएंस, या दोनों वार्षिक) वरना अनुपात निरर्थक है। और forecast_var को कभी शून्य मत होने दें — इसे एक छोटे फ्लोर तक क्लिप करें, क्योंकि पूरे औसत को जहरीला बना देगा।
Mincer-Zarnowitz रिग्रेशन
एक अकेली लॉस संख्या बताती है कि कौन-सा फोरकास्ट बेहतर है; यह नहीं बताती कि फोरकास्ट कैसे गलत है। Mincer-Zarnowitz (1969) रिग्रेशन बताता है। प्रॉक्सी को फोरकास्ट पर रीग्रेस करें:
एक ऑप्टिमल, अनबायस्ड फोरकास्ट के तहत, और : औसतन रियलाइज्ड वेरिएंस फोरकास्ट के बराबर होता है। विचलन विकृति का निदान करते हैं:
- के साथ : एक ऐसे फोरकास्ट का क्लासिक संकेत जो बहुत ज्यादा वोलेटाइल है — यह ओवर-रिएक्ट करता है, ऐसे एक्सट्रीम की भविष्यवाणी करता है जो पूरी तरह से साकार नहीं होते। कच्चे स्क्वेयर्ड-रिटर्न-चालित मॉडल के लिए बहुत आम है।
- : फोरकास्ट अंडर-रिएक्ट करता है, सच्चे वेरिएंस के साथ बहुत कम स्केल करता है।
- कम रिग्रेशन : भले ही औसतन ठीक लगें, फोरकास्ट रोज-रोज वेरिएंस को खराब ढंग से ट्रैक करता है। चूंकि प्रॉक्सी इतना शोरगुल वाला है, चौंकिए मत कि के मुकाबले MZ अक्सर केवल 0.05-0.20 होता है; के मुकाबले यह कहीं ज्यादा होगा। के मुकाबले 1 से काफी नीचे बंधा हुआ है फोरकास्ट चाहे जितना अच्छा हो, सिर्फ प्रॉक्सी शोर के कारण।
का एक संयुक्त -टेस्ट एक औपचारिक कैलिब्रेशन जांच देता है। व्यवहार में, एक फोरकास्ट को समझने के लिए MZ का इस्तेमाल एक डायग्नोस्टिक के रूप में करें, और फोरकास्ट को रैंक करने के लिए QLIKE का।
Diebold-Mariano: क्या फर्क असली है?
मान लीजिए GARCH का मीन QLIKE 0.183 है और EWMA का 0.191। GARCH "जीत गया।" लेकिन क्या 0.008 एक असली एज है या सैंपलिंग नॉइज? Diebold-Mariano (1995) टेस्ट ठीक इसी का जवाब देता है। प्रति-अवधि लॉस डिफरेंशियल को परिभाषित करें
दो फोरकास्ट और के लिए (यहां = QLIKE)। नल हाइपोथीसिस समान पूर्वानुमान सटीकता है, । स्टैटिस्टिक अपने लॉन्ग-रन (HAC) स्टैंडर्ड एरर से स्टैंडर्डाइज्ड किया गया मीन डिफरेंशियल है, क्योंकि सीरियली सहसंबद्ध है:
जहां एक Newey-West-प्रकार का लॉन्ग-रन वेरिएंस एस्टीमेट है। से परे एक DM स्टैटिस्टिक 5% पर समान सटीकता को खारिज करता है। महत्वपूर्ण रूप से, DM फोरकास्ट के बारे में एक टेस्ट है, नेस्टेड मॉडल के बारे में नहीं, और यह लॉस सीरीज में सीरियल डिपेंडेंस को संभालता है जिसे पर एक सादा -टेस्ट नजरअंदाज कर देगा।
import numpy as np
from scipy import stats
def diebold_mariano(loss_a: np.ndarray, loss_b: np.ndarray, h: int = 1):
"""Diebold-Mariano test of equal predictive accuracy.
loss_a, loss_b: per-period losses (e.g. QLIKE) for forecasts A and B.
h: forecast horizon; Newey-West lag = h - 1 (>=0), plus a small-sample buffer.
Returns (DM_stat, p_value). Negative DM => A has lower loss (A better).
"""
d = np.asarray(loss_a) - np.asarray(loss_b)
T = len(d)
d_bar = d.mean()
lag = max(h - 1, 0)
gamma0 = np.mean((d - d_bar) ** 2)
lrv = gamma0
for k in range(1, lag + 1):
w = 1.0 - k / (lag + 1)
cov = np.mean((d[k:] - d_bar) * (d[:-k] - d_bar))
lrv += 2.0 * w * cov
dm = d_bar / np.sqrt(lrv / T)
adj = np.sqrt((T + 1 - 2 * h + h * (h - 1) / T) / T)
dm *= adj
p = 2.0 * (1.0 - stats.t.cdf(abs(dm), df=T - 1))
return float(dm), float(p)
उस कमेंट में दिया गया उदाहरण परिणाम ईमानदार और आम आउटकम है, और यही इस सेक्शन के होने का पूरा कारण है: GARCH अक्सर EWMA से थोड़ा कम औसत लॉस पोस्ट करता है, और उतनी ही बार वह एज DM सिग्निफिकेंस बार पार करने में विफल रहता है। अगर आप कभी सिर्फ मीन QLIKE रिपोर्ट करते हैं, तो आप खुद को ऐसे एज के बारे में समझा लेंगे जिन्हें एक DM टेस्ट खारिज कर देता। DM स्टैटिस्टिक रिपोर्ट करें। यह वही अनुशासन है जो हम honest evaluation with no robust edge में स्ट्रैटेजी रिटर्न पर लागू करते हैं — एक बेंचमार्क को हराने वाला पॉइंट एस्टीमेट तब तक एज नहीं है जब तक आपने यह बाहर न कर दिया हो कि यह नॉइज है।
बैकटेस्ट: एक वॉक-फॉरवर्ड वोल-टारगेटेड स्ट्रैटेजी
अब हम दोनों हिस्सों को जोड़ते हैं — एक फोरकास्टर और एक साइजिंग नियम — एक स्ट्रैटेजी में और इसे एकमात्र सार्थक तरीके से मूल्यांकित करते हैं: वॉक-फॉरवर्ड, आउट ऑफ सैंपल, कॉस्ट के साथ।
स्ट्रैटेजी जानबूझकर सरल है, क्योंकि सरलता ही वह चीज है जो हमें परिणाम को किसी चतुर सिग्नल की बजाय वोल फोरकास्ट को श्रेय देने देती है। लॉन्ग-ओनली, वोल-टारगेटेड BTC। हर दिन, अगले दिन की वोलैटिलिटी का पूर्वानुमान करें, पोजीशन को पर सेट करें, रात भर होल्ड करें, और दोहराएं। एक लॉन्ग/फ्लैट वेरिएंट पोजीशन को गेट करता है जब एक ट्रेंड फिल्टर नेगेटिव हो; एक छोटा-पोर्टफोलियो वेरिएंट किसी सिंगल एसेट के वेरिएंस के बजाय Part 3 के DCC कोवेरियंस मैट्रिक्स पर साइज करता है। हम लॉन्ग-ओनली केस को पूरी तरह वर्णित करते हैं और एक्सटेंशन को नोट करते हैं।
वॉक-फॉरवर्ड मैकेनिक्स और नो-लुक-अहेड कॉन्ट्रैक्ट
इस बैकटेस्ट की सबसे महत्वपूर्ण संपत्ति यह है कि दिन पर पोजीशन साइज करने के लिए इस्तेमाल की गई हर मात्रा दिन के क्लोज पर उपलब्ध डेटा से ही कंप्यूट होने योग्य है। GARCH पैरामीटर पर समाप्त होने वाली एक रोलिंग विंडो पर फिर से एस्टीमेट किए जाते हैं; फोरकास्ट उस फिट से वन-स्टेप-अहेड है; पोजीशन उस फोरकास्ट से सेट होती है; और कमाया गया रिटर्न है, जहां अगले दिन का रिटर्न है, जो मॉडल ने कभी नहीं देखा। पूरे सैंपल पर GARCH को फिर से फिट करना और फिर अतीत का "फोरकास्ट" करना, एक शानदार बैकटेस्ट को गलती से मनगढ़ंत बनाने का सबसे आम तरीका है। हम इस लुक-अहेड ट्रैप और सामान्य पद्धति को walk-forward optimization में संबोधित करते हैं।
import numpy as np
import pandas as pd
from arch import arch_model
def walk_forward_voltarget(
returns: pd.Series, # daily log returns in decimal (e.g. 0.021)
proxy_var: pd.Series, # variance proxy aligned to returns (RV or r^2)
target_vol_annual: float = 0.20,
window: int = 750, # rolling estimation window (days)
refit_every: int = 5, # refit GARCH weekly, forecast daily (cost saver)
w_max: float = 3.0, # leverage cap
cost_bps: float = 5.0, # per-unit-turnover cost in basis points
ann: int = 365, # crypto trades 365 days/yr
):
"""Long-only vol-targeted BTC, GARCH(1,1)-t forecasts, strictly walk-forward.
Returns a DataFrame with position, forecast vol, net returns, and turnover.
"""
idx = returns.index
target_daily = target_vol_annual / np.sqrt(ann)
fcast_vol = pd.Series(index=idx, dtype=float, name="fcast_vol")
last_res = None
for i in range(window, len(returns) - 1):
if (i - window) % refit_every == 0 or last_res is None:
train = returns.iloc[i - window:i + 1] * 100.0 # scale for the optimizer
am = arch_model(train, mean="Constant", vol="GARCH",
p=1, o=1, q=1, dist="t") # GJR-t, Part 2
last_res = am.fit(disp="off")
f = last_res.forecast(horizon=1, reindex=False)
var_next = f.variance.values[-1, 0] / (100.0 ** 2) # unscale
fcast_vol.iloc[i + 1] = np.sqrt(var_next)
raw_w = (target_daily / fcast_vol).clip(upper=w_max)
position = raw_w.shift(0) # w_{i+1} known at close i
gross_ret = position * returns # earned on day i+1
turnover = position.diff().abs().fillna(0.0)
cost = turnover * (cost_bps / 1e4)
net_ret = (gross_ret - cost).dropna()
out = pd.DataFrame({
"position": position,
"fcast_vol": fcast_vol,
"gross_ret": gross_ret,
"turnover": turnover,
"net_ret": net_ret,
}).dropna()
return out
def performance_stats(net_ret: pd.Series, ann: int = 365) -> dict:
"""Sharpe, realized vol, max drawdown, CAGR, annual turnover."""
mu = net_ret.mean() * ann
sigma = net_ret.std() * np.sqrt(ann)
sharpe = mu / sigma if sigma > 0 else np.nan
equity = (1.0 + net_ret).cumprod()
peak = equity.cummax()
max_dd = (equity / peak - 1.0).min()
cagr = equity.iloc[-1] ** (ann / len(net_ret)) - 1.0
return {
"sharpe": round(sharpe, 2),
"realized_vol": round(sigma, 3),
"max_drawdown": round(max_dd, 3),
"cagr": round(cagr, 3),
}
कुछ इम्प्लीमेंटेशन नोट्स जो दिखने से ज्यादा मायने रखते हैं:
- ऑप्टिमाइजर के लिए स्केलिंग। जब रिटर्न पर्सेंट में हों तो
archफिट संख्यात्मक रूप से ज्यादा खुश रहते हैं, इसलिए* 100और अनस्केलिंग के समय मिलता-जुलता/ 100**2। अनस्केल करना भूल जाएं तो आपका टारगेट वोल 10,000x से गलत हो जाएगा। - रीफिट कैडेंस। हर एक दिन GARCH पैरामीटर को फिर से एस्टीमेट करना महंगा है और लगभग कुछ नहीं जोड़ता — पैरामीटर हफ्ते-दर-हफ्ते स्थिर रहते हैं। हर हफ्ते रीफिट करना (
refit_every=5) जबकि रोज फोरकास्ट करना (रीफिटिंग के बिना भी रिकर्शन नए रिटर्न से को अपडेट करता है) मानक समझौता है। यह copula models for joint risk में कोपुला पाइपलाइन से कैशिंग सलाह को प्रतिध्वनित करता है। - कैप सजावटी नहीं है। जब एक बिल्कुल-शांत रेजीम में फोरकास्ट वोल गिर जाता है, तो फूट कर 5x, 10x लीवरेज तक पहुंच सकता है। अनकैप्ड वोल टारगेटिंग एक वोलैटिलिटी रेजीम परिवर्तन से ठीक पहले खुशी-खुशी आपको विनाशकारी लीवरेज सौंप देगी — ठीक वही क्षण जब फोरकास्ट सबसे ज्यादा गलत होने वाला है। इसे कैप करें (यहां 3x) और पहचानें कि कैप ठीक उन्हीं अवधियों में बाइंड करेगा जो सबसे शांत, पीछे मुड़ कर देखने पर सबसे खतरनाक हैं।
- कॉस्ट टर्नओवर के साथ स्केल करती है, और वोल टारगेटिंग एक टर्नओवर मशीन है। फोरकास्ट में हर डगमगाहट पोजीशन को फिर साइज करती है। एक कम-वोल एसेट पर एक झटकेदार फोरकास्ट के साथ आप बुक को रोज चर्न कर सकते हैं।
cost_bpsटर्म कोई राउंडिंग डिटेल नहीं है; एक हाई-टर्नओवर वोल-टारगेट के लिए यह ग्रॉस शार्प सुधार का एक बड़ा हिस्सा खा सकती है।
आउटपुट कैसा दिखता है (उदाहरणात्मक)
BTC डेली डेटा पर बहु-वर्षीय विंडो में इसे चलाना, चारों फोरकास्टर की साइजिंग डिनॉमिनेटर के रूप में तुलना करते हुए, आम तौर पर निम्नलिखित आकार की तालिका पैदा करता है। नीचे की संख्याएं उदाहरणात्मक हैं — विशिष्ट पैटर्न दिखाने के लिए हाथ से चुनी गई, किसी असली बैकटेस्ट का आउटपुट नहीं — लेकिन क्रम और परिमाण उस चीज के प्रतिनिधि हैं जो प्रैक्टिशनर रिपोर्ट करते हैं।
| साइजिंग फोरकास्ट | शार्प | रियलाइज्ड वोल | टारगेट वोल | मैक्स ड्रॉडाउन | वार्षिक टर्नओवर |
|---|---|---|---|---|---|
| फिक्स्ड नोशनल (कोई टारगेटिंग नहीं) | 0.71 | 0.68 | — | -0.78 | 0.1x |
| रोलिंग RV (60d) | 0.94 | 0.24 | 0.20 | -0.41 | 12x |
| EWMA () | 1.02 | 0.21 | 0.20 | -0.35 | 19x |
| GARCH(1,1)-t | 1.05 | 0.21 | 0.20 | -0.33 | 22x |
| HAR-RV (इंट्राडे प्रॉक्सी) | 1.09 | 0.20 | 0.20 | -0.31 | 20x |
दो वेरिएंट बनाने लायक
लॉन्ग-ओनली केस फोरकास्ट को अलग करता है, लेकिन दो एक्सटेंशन इतने आम हैं कि उन्हें स्पष्ट रूप से दिखाया जाए।
ट्रेंड गेट के साथ लॉन्ग/फ्लैट। वोल टारगेटिंग पोजीशन को साइज करती है लेकिन कोई दिशात्मक व्यू नहीं लेती — यह हमेशा लॉन्ग होती है। एक सस्ता, ईमानदार सुधार यह है कि जब एक धीमा ट्रेंड फिल्टर नेगेटिव हो जाए तो पोजीशन को गेट करके बंद कर दें, ताकि आप वोल-टारगेटेड लॉन्ग केवल अपट्रेंड में रखें और अन्यथा फ्लैट बैठें। यह साइजिंग लॉजिक को समान रखता है और उसके ऊपर एक कच्चा रेजीम फिल्टर परत चढ़ाता है; यह एंट्री को टाइम करने का दिखावा नहीं करता, केवल स्पष्ट डाउनट्रेंड में बने रहने से बचने का।
def apply_trend_gate(position: pd.Series, price: pd.Series, fast: int = 20, slow: int = 100):
"""Zero out the (already vol-targeted) position when the fast SMA is below
the slow SMA. Both SMAs use only past prices, so no look-ahead is introduced.
"""
fast_ma = price.rolling(fast).mean().shift(1) # shift: known at prior close
slow_ma = price.rolling(slow).mean().shift(1)
gate = (fast_ma > slow_ma).astype(float) # 1.0 in uptrend, 0.0 otherwise
return position * gate.reindex(position.index).fillna(0.0)
ट्रेंड गेट डाउनसाइड पर टर्नओवर कम करता है (आप बियर मार्केट में सिकुड़ती पोजीशन को चर्न करना बंद कर देते हैं) लेकिन अपना खुद का रेजीम रिस्क जोड़ता है — यह चॉपी साइडवेज बाजारों में व्हिपसॉ करता है और मोड़ पर पीछे रह जाता है। क्या यह मदद करता है यह एक अनुभवजन्य सवाल है जिसका जवाब आपको साइजिंग नियम जितनी ही वॉक-फॉरवर्ड, DM-टेस्टेड सख्ती से देना चाहिए; एक ट्रेंड फिल्टर ठीक वही ऐड-ऑन है जो इन-सैंपल शानदार दिखता है और आउट ऑफ सैंपल गायब हो जाता है।
DCC कोवेरियंस पर पोर्टफोलियो वोल टारगेटिंग। कई एसेट्स की बुक के लिए, स्केलर फोरकास्ट पोर्टफोलियो वोलैटिलिटी बन जाता है, जहां Part 3 के DCC-GARCH से समय-परिवर्तनशील कोवेरियंस मैट्रिक्स है। आप बेस वेट चुनते हैं (इक्वल वेट, मार्केट कैप, या एक मीन-वेरिएंस टिल्ट), के तहत पोर्टफोलियो के फोरकास्ट वोल की गणना करते हैं, और पोर्टफोलियो टारगेट हिट करने के लिए पूरे वेट वेक्टर को स्केल करते हैं।
def portfolio_voltarget_weights(base_w, cov_forecast, target_vol_daily, w_gross_max=3.0):
"""Scale a base weight vector so forecast portfolio vol hits the target.
base_w: (n,) base allocation (need not sum to 1).
cov_forecast: (n, n) one-step-ahead covariance from DCC-GARCH (daily units).
"""
base_w = np.asarray(base_w, dtype=float)
port_var = float(base_w @ cov_forecast @ base_w)
port_vol = np.sqrt(max(port_var, 1e-12))
scale = min(target_vol_daily / port_vol, w_gross_max / np.abs(base_w).sum())
return scale * base_w
यह पोर्टफोलियो-निर्माण साहित्य का स्वाभाविक पुल है: बेस वेट Markowitz mean-variance या HRP/CVaR जैसी रिस्क-आधारित विधि से आ सकते हैं, और वोल टारगेटिंग फिर एक ओवरले के रूप में ऊपर बैठती है जो कुल जोखिम को एक स्थिरांक तक स्केल करती है। DCC मैट्रिक्स इसलिए मायने रखती है क्योंकि क्रैश में सहसंबंध बढ़ते हैं (Part 3) — एक पोर्टफोलियो जो शांत बाजारों में विविधीकृत दिखता है, ठीक तब कहीं ऊंचा फोरकास्ट वोल रख सकता है जितना कि एक स्थैतिक कोवेरियंस बताती है, जब यह वास्तव में मायने रखता है, और ओवरले जवाब में ग्रॉस एक्सपोजर कम करता है।
वे डायग्नोस्टिक जो आपको हमेशा प्लॉट करने चाहिए
कभी सिर्फ सारांश तालिका पर भरोसा न करें। किसी भी वोल-टारगेट के लिए, तीन चीजें प्लॉट करें और किसी भी शार्प संख्या पर विश्वास करने से पहले उन्हें नजर से जांचें। पहला, स्ट्रैटेजी की रियलाइज्ड रोलिंग वोल बनाम टारगेट लाइन — इसे टारगेट से चिपकना चाहिए; उससे ऊपर व्यवस्थित बहाव का मतलब है कि आपका फोरकास्ट कम की ओर पक्षपाती है (महंगी दिशा)। दूसरा, पोजीशन/लीवरेज सीरीज — कैप के बाइंड होने और ड्रॉडाउन से ठीक पहले लीवरेज स्पाइक की तलाश करें, एक ऐसे फोरकास्ट का हस्ताक्षर जो एक रेजीम परिवर्तन में पकड़ा गया। तीसरा, फोरकास्ट-बनाम-प्रॉक्सी स्कैटर (Mincer-Zarnowitz चित्र) — 1 से बहुत दूर स्लोप वाला एक बादल बताता है कि फोरकास्ट इस तरह मिस-स्केल्ड है जिसे QLIKE औसत छुपा सकता है। ये तीन प्लॉट किसी भी एक सांख्यिकी से ज्यादा बग और आत्म-भ्रम पकड़ते हैं।
इस तालिका को उस तरह पढ़ें जैसे आपको हर बैकटेस्ट तालिका पढ़नी चाहिए: देखें कि क्या रोबस्ट है और क्या मार्जिनल है। रोबस्ट तथ्य उभर कर सामने आते हैं। हर वोल-टारगेटेड वेरिएंट शार्प पर, और ज्यादा नाटकीय रूप से, ड्रॉडाउन और रियलाइज्ड-वोल स्थिरता पर फिक्स्ड नोशनल को कुचल देता है — फिक्स्ड-नोशनल स्ट्रैटेजी 68% वार्षिक वोल पर 78% ड्रॉडाउन के साथ चलती है, जो बिल्कुल निवेश-योग्य नहीं है। और हर टारगेटिंग विधि 20% टारगेट के करीब रियलाइज्ड वोल देती है, जो इस मैकेनिज्म के काम करने का पूरा वादा है। मार्जिनल तथ्य फोरकास्टर के बीच के फर्क हैं: HAR, GARCH को पछाड़ता है, GARCH, EWMA को पछाड़ता है, EWMA, रोलिंग RV को पछाड़ता है, लेकिन गैप छोटे हैं — शार्प पॉइंट का दसवां हिस्सा — और, फोरकास्ट पर Diebold-Mariano से या रिटर्न पर एक बूटस्ट्रैप से टेस्ट किए जाने पर, अक्सर सिग्निफिकेंस पार करने में विफल रहेंगे। सोफिस्टिकेटेड और नाइव फोरकास्टर के बीच वह छोटा, नाजुक, रेजीम-निर्भर गैप इस पूरी सीरीज की ईमानदार हेडलाइन है।
ईमानदार रहें कि यह आपको क्या देता है
इस ब्लॉग के पास खुद को धोखा दिए बिना बैकटेस्टिंग पर एक पूरा संग्रह है, तो आइए इसे अपने ही परिणाम पर लागू करें बजाय चुपचाप उम्मीद करने के कि आप ऐसा नहीं करेंगे।
वोलैटिलिटी टारगेटिंग रिस्क-एडजस्टेड रिटर्न और ड्रॉडाउन सुधारती है। यह शून्य से अल्फा नहीं बनाती। तालिका को फिर देखें। टारगेटिंग से शार्प सुधार वास्तविक है और रखने लायक है — लेकिन इसे विघटित करें और इसका ज्यादातर हिस्सा हाई-वोल रेजीम में एक स्थिर पोजीशन न रखने से आता है, जो यांत्रिक रूप से सबसे खराब ड्रॉडाउन से बचाता है और कंपाउंडिंग पथ को स्थिर करता है। स्ट्रैटेजी अभी भी लॉन्ग BTC है; इसके पास ऐसा कोई व्यू नहीं है जो बाजार खुद न दे। अगर आपके सैंपल में BTC का शार्प नेगेटिव है, तो वोल टारगेटिंग आपको एक कम बुरा नेगेटिव शार्प देगी, पॉजिटिव नहीं। यह रिटर्न डिस्ट्रीब्यूशन को नया आकार देती है — पतली टेल, स्थिर वोल, बेहतर ज्यामितीय कंपाउंडिंग — लेकिन कच्चा दिशात्मक एज वही है जो अंतर्निहित लॉन्ग है। एक खूबसूरत इक्विटी कर्व को आपको यह विश्वास दिलाने न दें कि आपको अल्फा मिला है जब असल में आपको रिस्क मैनेजमेंट मिला है। Moreira-Muir ने वोल मैनेजमेंट से इक्विटी फैक्टर में असली अल्फा पाया, लेकिन वह परिणाम फैक्टर के समय-परिवर्तनशील रिस्क-रिटर्न ट्रेडऑफ के बारे में है, और यह किसी अलग सैंपल पर एक सिंगल क्रिप्टो एसेट में अपने आप ट्रांसफर नहीं होता।
EWMA के मुकाबले GARCH का फोरकास्ट-गुणवत्ता एज अक्सर छोटा और रेजीम-निर्भर होता है। यह Parts 1-3 का असहज परिणाम है। आपने तेजी से परिष्कृत मॉडल बनाए — लीवरेज टर्म, Student-t टेल, डायनामिक सहसंबंध — और एक नाइव EWMA के मुकाबले वोल-टारगेटिंग P&L में हर एक का सीमांत योगदान अक्सर नॉइज बैंड के भीतर होता है। GARCH का फायदा (शॉक्स के बाद मीन रिवर्जन) मुख्य रूप से विशिष्ट रेजीम में दिखाई देता है: तीखे स्पाइक जो फिर सामान्य हो जाते हैं। लगातार ट्रेंड या स्थायी हाई-वोल रेजीम में यह EWMA से मुश्किल से अलग होता है। यह GARCH को बेकार नहीं बनाता — मीन-रिवर्जन संरचना, व्याख्या योग्य पैरामीटर, आगे के पथों को सिमुलेट करने और फोरकास्ट के मुकाबले ऑप्शन प्राइस करने की क्षमता, इन सबका मूल्य है जो EWMA में नहीं है — लेकिन अगर आपका एकमात्र इस्तेमाल साइजिंग है, तो जटिलता की कीमत चुकाने से पहले DM टेस्ट चलाएं, और जान लें कि regime detection एक अलग कोण से आपको वही बात बता रहा है: जीतने वाला मॉडल रेजीम पर निर्भर करता है।
बैकटेस्ट शार्प लाइव शार्प की एक ऊपरी सीमा है, और वोल टारगेटिंग वह गैप चौड़ा करती है। क्योंकि स्ट्रैटेजी टर्नओवर-भारी और लीवरेज-स्केल्ड है, यह उन घर्षणों के प्रति असाधारण रूप से संवेदनशील है जिन्हें एक नाइव बैकटेस्ट छोड़ देता है: आपके फिल्स उस क्लोज से खराब हैं जिस पर आपने साइज किया, लीवरेज्ड पर्प पोजीशन पर फंडिंग कॉस्ट लगातार जमा होती है, और लीवरेज कैप मार्जिन और लिक्विडेशन मैकेनिक्स के साथ इंटरैक्ट करती है जिन्हें एक सादा w * return नजरअंदाज करता है। इनमें से हर एक लाइव को बैकटेस्ट से खराब बनाता है। हम इस गैप को backtest-live parity में व्यवस्थित रूप से संबोधित करते हैं; खासकर वोल टारगेटिंग के लिए, कंजर्वेटिव कॉस्ट, एक यथार्थवादी (कम) लीवरेज कैप का इस्तेमाल करके, और उस क्लोज की बजाय अगले बार के ओपन पर एक्जीक्यूट करके इसके लिए बजट बनाएं जिस पर आपने सिग्नल की गणना की थी।
वोलैटिलिटी रिस्क प्रीमियम पर एक बात। ऊपर की सब चीज रियलाइज्ड वोलैटिलिटी का पूर्वानुमान करती है। एक समानांतर, ट्रेडेबल ऑब्जेक्ट है: इम्प्लाइड वोलैटिलिटी, जो ऑप्शन में मूल्यांकित होती है, जो औसतन बाद की रियलाइज्ड वोल से ऊपर बैठती है — वोलैटिलिटी रिस्क प्रीमियम, एक वोल स्पाइक का जोखिम उठाने का मुआवजा। वह गैप खुद रिटर्न का एक स्रोत है (वेरिएंस बेचना इसे हार्वेस्ट करता है, इसे खरीदना टेल रिस्क को हेज करता है), और यह वोल टारगेटिंग से एक बिल्कुल अलग खेल है: यह वोलैटिलिटी के फोरकास्ट के इस्तेमाल की बजाय वोलैटिलिटी की कीमत पर एक दांव है। हम यहां इसका पीछा नहीं करते, लेकिन मशीनरी Black-Scholes options pricing में प्राइसिंग मॉडल से शुरू होती है, और एक अच्छा रियलाइज्ड-वोल फोरकास्ट (Parts 1-2) ठीक वही इनपुट है जो आपको यह जज करने के लिए चाहिए कि इम्प्लाइड वोल महंगी है या सस्ती। अपने GARCH फोरकास्ट की तुलना ऑप्शन बाजार की इम्प्लाइड वोल से करना इस सीरीज में बनाई गई हर चीज के सबसे ईमानदार इस्तेमालों में से एक है।
व्यावहारिक विचार
एक काम करते वोल-टारगेट और एक नाजुक वोल-टारगेट को अलग करने वाली चीजों का एक झुंड।
- सही होराइजन पर एस्टीमेट करें। अगर आप एक दिन के लिए रखी गई पोजीशन को साइज करते हैं, तो एक दिन के वोल का पूर्वानुमान करें। अगर आप साप्ताहिक रीबैलेंस करते हैं, तो साप्ताहिक वोल का पूर्वानुमान करें (और टारगेट करें), या होराइजन पर डेली GARCH फोरकास्ट को एकत्रित करें — मल्टी-स्टेप GARCH फोरकास्ट की ओर मीन-रिवर्ट करता है, जिसे नाइव "" स्केलिंग नजरअंदाज करती है। Part 1 मल्टी-स्टेप GARCH फोरकास्टिंग को कवर करता है।
- 24/7 बाजारों में वार्षिकीकरण। क्रिप्टो साल के 365 दिन बिना वीकेंड या छुट्टी के ट्रेड करता है, तो डेली वोल को से वार्षिक बनाएं, इक्विटीज के से नहीं। इसे गलत करना आपके टारगेट को चुपचाप ~20% मिस-स्केल कर देता है।
- डिनॉमिनेटर एक कोवेरियंस मैट्रिक्स हो सकता है। एक मल्टी-एसेट बुक के लिए, स्केलर की जगह Part 3 के DCC-GARCH से पोर्टफोलियो वोल लें, और पोर्टफोलियो टारगेट वोल हिट करने के लिए वेट के पूरे वेक्टर को स्केल करें। यह वोल टारगेटिंग को मीन-वेरिएंस साइजिंग (Markowitz for crypto) और रिस्क-आधारित आवंटन (HRP and CVaR pipelines) से जोड़ता है — वोल टारगेटिंग एक पोर्टफोलियो रिस्क बजट पर स्केल करने का सिंगल-एसेट विशेष मामला है।
- वोल टारगेटिंग एक सूक्ष्म तरीके से प्रोसाइक्लिकल है। जब हर कोई वही नियम चलाता है, एक वोल स्पाइक सिंक्रोनाइज्ड डीलीवरेजिंग को मजबूर करता है, जो कीमतें नीचे धकेलता है, जो रियलाइज्ड वोल बढ़ाता है, जो और ज्यादा डीलीवरेजिंग मजबूर करता है। यह फीडबैक (2018 के "volmageddon" और विभिन्न क्रिप्टो डीलीवरेजिंग कैस्केड में अच्छी तरह दस्तावेजीकृत) का मतलब है कि यह नियम ठीक तभी कम अच्छी तरह काम करता है जब कई खिलाड़ी इसका इस्तेमाल करते हैं। यह इसे छोड़ देने का कारण नहीं है, लेकिन यह लीवरेज कैप करने और यह न मान लेने का कारण है कि एक वोल स्पाइक के दौरान आपके फिल्स शांत-बाजार फिल्स जैसे दिखेंगे।
- फोरकास्ट को फ्लोर और क्लिप करें। एक शून्य या शून्य-के-करीब फोरकास्ट वोल अनंत लीवरेज पैदा करती है। हमेशा को एक सुविज्ञ न्यूनतम पर फ्लोर करें और पोजीशन को कैप करें, और लॉग करें कि हर एक कितनी बार बाइंड करता है — अगर कैप ज्यादातर समय बाइंड करता है, तो आपका टारगेट एसेट के लिए बहुत आक्रामक है।
सारांश
- एक वोलैटिलिटी फोरकास्ट का तब तक कोई मूल्य नहीं जब तक वह कोई निर्णय न बदले। वोलैटिलिटी टारगेटिंग — एक्सपोजर को (कैप्ड) के रूप में साइज करना — एक फोरकास्ट के मूल्य का सबसे साफ टेस्ट है, क्योंकि फोरकास्ट क्वालिटी सीधे एक फ्लैटर रियलाइज्ड-वोल प्रोफाइल और एक ऊंचे शार्प रेशियो में मैप होती है।
- वोल टारगेटिंग रिस्क-एडजस्टेड रिटर्न बढ़ाती है और, खासकर, ड्रॉडाउन को नियंत्रित करती है, क्योंकि वोलैटिलिटी पूर्वानुमेय है (यह क्लस्टर करती है) जबकि दिशा नहीं है, और क्योंकि शार्प रेशियो हाई-वोल रेजीम में गिरते हैं जिन्हें यह नियम स्वचालित रूप से कम भार देता है। यह इस धारणा के तहत Kelly साइजिंग है कि अपेक्षित रिटर्न वोलैटिलिटी के साथ स्केल करता है।
- GARCH को मजबूत बेसलाइन के मुकाबले ईमानदारी से बेंचमार्क करें: रोलिंग रियलाइज्ड वोल, EWMA/RiskMetrics (, शून्य फ्री पैरामीटर वाला एक IGARCH), और इंट्राडे रियलाइज्ड-वेरिएंस प्रॉक्सी पर HAR-RV। EWMA और HAR को हराना मुश्किल है।
- आप सच्ची वोलैटिलिटी को देख नहीं सकते, इसलिए प्रॉक्सी नॉइज के प्रति रोबस्ट लॉस फंक्शन का इस्तेमाल करते हुए एक प्रॉक्सी ( या, कहीं बेहतर, ) के मुकाबले मूल्यांकन करें। MSE की बजाय QLIKE पसंद करें: यह अंडर-फोरकास्टिंग को ज्यादा दंडित करता है (महंगी गलती) और स्केल-इनवेरिएंट है, इसलिए यह कुछ हाई-वोल दिनों द्वारा हाईजैक नहीं होता। पक्षपात का निदान करने के लिए Mincer-Zarnowitz का इस्तेमाल करें और यह तय करने के लिए Diebold-Mariano टेस्ट का कि किसी फोरकास्ट का एज असली है या नॉइज।
- एक वॉक-फॉरवर्ड, कॉस्ट-अवेयर बैकटेस्ट में, वोल टारगेटिंग भरोसेमंद ढंग से शार्प और ड्रॉडाउन पर फिक्स्ड नोशनल को हराती है, और चारों फोरकास्टर एक-दूसरे के करीब क्लस्टर करते हैं — EWMA के मुकाबले GARCH का एज छोटा, रेजीम-निर्भर, और अक्सर सांख्यिकीय रूप से महत्वपूर्ण नहीं है। सिर्फ मीन लॉस नहीं, DM टेस्ट रिपोर्ट करें।
- ईमानदार रहें: वोल टारगेटिंग रिस्क मैनेजमेंट है, अल्फा नहीं। यह आपके पास पहले से मौजूद जो भी दिशात्मक दांव है उसके रिटर्न डिस्ट्रीब्यूशन को नया आकार देती है; यह शून्य से एज नहीं बनाती। और यह टर्नओवर-भारी और लीवरेज-स्केल्ड है, इसलिए लाइव परिणाम सामान्य से ज्यादा बैकटेस्ट से पीछे रहते हैं।
संदर्भ:
- Patton, A. J. (2011). Volatility forecast comparison using imperfect volatility proxies. Journal of Econometrics, 160(1), 246-256. DOI
- Corsi, F. (2009). A simple approximate long-memory model of realized volatility. Journal of Financial Econometrics, 7(2), 174-196. DOI
- Diebold, F. X., & Mariano, R. S. (1995). Comparing predictive accuracy. Journal of Business & Economic Statistics, 13(3), 253-263. DOI
- Mincer, J., & Zarnowitz, V. (1969). The evaluation of economic forecasts. In Economic Forecasts and Expectations, NBER.
- Moreira, A., & Muir, T. (2017). Volatility-managed portfolios. Journal of Finance, 72(4), 1611-1644. DOI
- J.P. Morgan / Reuters (1996). RiskMetrics Technical Document, 4th ed.
- Bollerslev, T. (1986). Generalized autoregressive conditional heteroskedasticity. Journal of Econometrics, 31(3), 307-327. 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
- Harvey, D., Leybourne, S., & Newbold, P. (1997). Testing the equality of prediction mean squared errors. International Journal of Forecasting, 13(2), 281-291. DOI
MarketMaker.cc Team
क्वांटिटेटिव रिसर्च और स्ट्रैटेजी