σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft Academyالمسارات
Ctrl K
AO
+1.2k متعلّم
تسجيل الدخولانضم ↗
المسارات
AO
+1.2k متعلّم
تسجيل الدخول
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
مسار Python›الوحدة 7 · بحث ألفا والمخاطر›الموضوع 7.9·~1 سمتقدم

نماذج التقلب GARCH

الموضع في المسارالوحدة 7 من 11 · الموضوع 9 من 9
7.9 نماذج التقلب GARCH
—درجة المختبر— / 100إجمالي XP—التتابع—

التقلب يتجمع

العوائد اليومية شبه غير قابلة للتنبؤ، لكن حجمها ليس كذلك: حركة كبيرة اليوم ترجّح حركة كبيرة غدًا، والأيام الهادئة تأتي في سلاسل. وتجمع التقلب هذا من أرسخ الحقائق في المالية، ويكسر افتراض التقلب الثابت الكامن وراء القيمة المعرضة البسيطة. ويموذج 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 وما لا يصلحهيجعل تنبؤ GARCH بالتقلب القيمة المعرضة تستجيب للسوق: فبعد صدمة يرتفع الحد فورًا وينخفض حين يعود الهدوء. ومع صدمات طبيعية تظل تقلل الذيول السميكة، فيستخدم الممارسون توزيع ستيودنت t ونسخًا مثل GJR-GARCH التي تجعل الأخبار السيئة ترفع التقلب أكثر من الجيدة. وتتراجع دقة التنبؤ مع الأفق وهو يعود إلى المستوى الطويل الأجل.
  • التقلب يتجمع: يبني 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 نقطة
المستكشف · lab-101-1
▾ lab-101-1
…
bash · داخل المتصفح
learner@quantcraft:~/lab-101-1$
لم يتم تحميل Python بعدPythonLn 1, Col 1Spaces: 4UTF-8

هل تريد إعادة ضبط هذا الموضوع؟

سيعود كل ما في lab-101-1 إلى الملفات الابتدائية وستُمسح الطرفية. ستفقد حلّك الحالي ولا يمكن التراجع عن ذلك.

سيُعاد ضبطه
  • main.py ← الشيفرة الابتدائية
  • سجل الطرفية ومخرجات الاختبارات
  • التغييرات غير المُرسلة
سيُحتفظ به
  • أفضل درجة في المختبر
  • نقاط XP والتتابع
  • تقدّم المحاضرة والملاحظات

سجّل الدخول لتشغيل الكود الخاص بك.

قراءة كل المحاضرات مجانية. أنشئ حسابًا أو سجّل الدخول لتشغيل الكود وتنفيذ الاختبارات وتسليم هذا المختبر.

  • بيئة تطوير داخل المتصفح مع طرفية bash — لا حاجة لتثبيت أي شيء
  • تصحيح فوري ونقاط خبرة ومكانك في المسار
إنشاء حسابتسجيل الدخول
أو
المتابعة عبر GitHub