التقلب يتجمع
العوائد اليومية شبه غير قابلة للتنبؤ، لكن حجمها ليس كذلك: حركة كبيرة اليوم ترجّح حركة كبيرة غدًا، والأيام الهادئة تأتي في سلاسل. وتجمع التقلب هذا من أرسخ الحقائق في المالية، ويكسر افتراض التقلب الثابت الكامن وراء القيمة المعرضة البسيطة. ويموذج GARCH (عدم تجانس التباين الشرطي الانحداري الذاتي المعمم) يمذج التباين الشرطي مباشرة فيتبع الخطر وأسعار الخيارات مزاج السوق.
import numpy as np
rng = np.random.default_rng(4)
n = 3000
omega, alpha, beta = 2e-6, 0.10, 0.85
var = np.empty(n)
returns = np.empty(n)
var[0] = omega / (1 - alpha - beta)
returns[0] = np.sqrt(var[0]) * rng.normal()
for t in range(1, n):
var[t] = omega + alpha * returns[t - 1] ** 2 + beta * var[t - 1]
returns[t] = np.sqrt(var[t]) * rng.normal()
# Clustering: the size of a return today predicts the size tomorrow, though the sign is a coin flip
print(round(float(np.corrcoef(returns[:-1], returns[1:])[0, 1]), 3)) # about 0
print(round(float(np.corrcoef(np.abs(returns[:-1]), np.abs(returns[1:]))[0, 1]), 3)) # clearly positiveتكرار GARCH(1,1)
للنموذج ثلاثة معاملات: var[t] = omega + alpha * r[t-1]**2 + beta * var[t-1]. فـomega حد أدنى، وalpha رد الفعل على صدمة الأمس، وbeta ثبات تباين الأمس. ولأن كل يوم يعتمد على السابق تُبنى السلسلة بحلقة تبدأ من تباين ابتدائي. والقيم المعتادة للأسهم اليومية alpha نحو 0.05 إلى 0.1 وbeta بين 0.85 و0.95: أي أن الصدمة تتلاشى ببطء.
import numpy as np
def garch_variance(returns, omega, alpha, beta, initial_var):
var = np.empty(len(returns))
var[0] = initial_var
for t in range(1, len(returns)):
var[t] = omega + alpha * returns[t - 1] ** 2 + beta * var[t - 1]
return var
returns = np.array([0.01, -0.02, 0.015, 0.0, -0.03, 0.01, 0.0, 0.0])
var = garch_variance(returns, 1e-6, 0.08, 0.9, 1e-4)
print(np.round(np.sqrt(var) * 100, 3)) # daily volatility in %: it jumps after the -3% day, then fadesأين تستقر، والتنبؤ
إذا كان alpha + beta < 1 فالتباين راجع إلى المتوسط ويستقر عند المستوى الطويل الأجل omega / (1 - alpha - beta)؛ وإن كان 1 أو أكثر فلا يستقر أبدًا. وفي التنبؤ يُعرف تباين الغد من عائد اليوم وتباينه. وبعد ذلك يساوي مربع العائد المتوقع التباين، فكل خطوة omega + (alpha + beta) * السابق: ينزلق التنبؤ من مستوى اليوم نحو المستوى الطويل الأجل بسرعة يحددها الثبات alpha + beta.
def long_run_variance(omega, alpha, beta):
if alpha + beta >= 1:
raise ValueError("alpha + beta must be below 1")
return omega / (1 - alpha - beta)
def garch_forecast(omega, alpha, beta, last_var, last_return, steps):
out = [omega + alpha * last_return ** 2 + beta * last_var]
for _ in range(steps - 1):
out.append(omega + (alpha + beta) * out[-1])
return out
omega, alpha, beta = 1e-6, 0.08, 0.9
print(long_run_variance(omega, alpha, beta) ** 0.5) # about 0.00707, 0.71% a day
forecast = garch_forecast(omega, alpha, beta, 4e-4, -0.03, 60) # after a -3% day in a volatile spell
print([round(v ** 0.5 * 100, 3) for v in (forecast[0], forecast[9], forecast[29], forecast[59])])اختيار المعاملات: دالة الإمكان
المعاملات غير معروفة؛ وتُقدَّر من البيانات بـالإمكان الأعظم. فإذا كانت العوائد طبيعية بتباين var[t] فإن لوغاريتم إمكان يوم هو -0.5 * (log(2 * pi * var[t]) + r[t]**2 / var[t]). وجمعه يعطي رقمًا واحدًا يقيّم اختيار (omega, alpha, beta): أفضل المعاملات تجعل العوائد المرصودة أرجح ما يكون. ويجرب المُحسِّن (مثل scipy.optimize.minimize) ثلاثيات كثيرة ويُبقي الأعلى.
# Score three parameter choices on data simulated with alpha = 0.10, beta = 0.85
import numpy as np
rng = np.random.default_rng(4)
n = 3000
true = (2e-6, 0.10, 0.85)
var = np.empty(n); returns = np.empty(n)
var[0] = true[0] / (1 - true[1] - true[2]); returns[0] = np.sqrt(var[0]) * rng.normal()
for t in range(1, n):
var[t] = true[0] + true[1] * returns[t - 1] ** 2 + true[2] * var[t - 1]
returns[t] = np.sqrt(var[t]) * rng.normal()
def loglik(params):
omega, alpha, beta = params
v = np.empty(n)
v[0] = returns.var()
for t in range(1, n):
v[t] = omega + alpha * returns[t - 1] ** 2 + beta * v[t - 1]
return float(np.sum(-0.5 * (np.log(2 * np.pi * v) + returns ** 2 / v)))
for params in ((2e-6, 0.10, 0.85), (2e-6, 0.30, 0.50), (1e-5, 0.0, 0.0)):
print(params, round(loglik(params), 1)) # the true parameters score highest- التقلب يتجمع: يبني GARCH(1,1) التباين بحلقة،
var[t] = omega + alpha * r[t-1]**2 + beta * var[t-1]. - عندما
alpha + beta < 1تعود إلىomega / (1 - alpha - beta)؛ والتنبؤات تستخدمomega + (alpha + beta) * السابق. - تُختار المعاملات بالإمكان الأعظم
sum(-0.5 * (log(2 * pi * var) + r**2 / var))؛ واستخدم صدمات ذات ذيول سميكة للذيول.
التالي: الحركة البراونية، المشي العشوائي في الزمن المستمر الذي تقوم عليه نماذج تسعير الخيارات.
المختبر: ما الذي يُقيَّم
- شغّل التكرار باستخدام
garch_variance25 نقطة - اعثر على مستقرها باستخدام
long_run_variance25 نقطة - تنبأ بالأيام القادمة باستخدام
garch_forecast25 نقطة - قيّم الملاءمة باستخدام
garch_loglik25 نقطة