σμ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›الوحدة 8 · النماذج العشوائية والتعلم الآلي›الموضوع 8.2·~55 دمتقدم

الحركة البراونية الهندسية

الموضع في المسارالوحدة 8 من 11 · الموضوع 2 من 10
8.2 الحركة البراونية الهندسية
—درجة المختبر— / 100إجمالي XP—التتابع—

الأسعار تتغير بالنسبة المئوية

تضيف الحركة البراونية الحسابية الضجيج نفسه بالدولار سواء كان السهم بـ5 أو 500، ويمكن أن تنزل تحت الصفر. أما السهم فيتصرف بشكل مختلف: حركة 1% هي 1% عند أي سعر. والحركة البراونية الهندسية تضع العشوائية في التغير النسبي: dS = mu * S * dt + sigma * S * dW. وهي نموذج بلاك-شولز. وmu العائد المتوقع السنوي وsigma التقلب، وهو الكمية المعلنة في السوق.

import math

def gbm_step(s, mu, sigma, dt, z):
    return s * math.exp((mu - 0.5 * sigma ** 2) * dt + sigma * math.sqrt(dt) * z)

print(round(gbm_step(100.0, 0.08, 0.2, 1 / 252, 0.0), 4))     # a calm day: only the (mu - sigma^2/2) drift acts
print(round(gbm_step(100.0, 0.08, 0.2, 1 / 252, 1.0), 4))     # a one-sigma up day
print(round(gbm_step(100.0, 0.08, 0.2, 1 / 252, -50.0), 4))   # an absurd fall: still positive

الحل الدقيق وسالب نصف سيغما تربيع

حل المعادلة يعطي S(t) = S(0) * exp((mu - sigma**2 / 2) * t + sigma * W(t)). لماذا هذا الحد الغريب - sigma**2 / 2؟ لأن الأسية محدبة: وبحسب متباينة ينسن يرفع الضجيج متوسط exp(الضجيج)، وطرح sigma**2 / 2 يلغي ذلك تمامًا، فينمو السعر *المتوقع* بمعدل mu. أما *المسارات* النموذجية فتنمو أبطأ، بمعدل mu - sigma**2 / 2، ولذلك يقع وسيط سعر السهم دون متوسطه. والموضوع التالي، مبرهنة إيتو، يشتق هذا الحد.

import numpy as np

def gbm_path(s0, mu, sigma, dt, z):
    log_moves = (mu - 0.5 * sigma ** 2) * dt + sigma * np.sqrt(dt) * z
    return s0 * np.exp(np.concatenate([[0.0], np.cumsum(log_moves)]))

rng = np.random.default_rng(1)
z = rng.standard_normal(252)
path = gbm_path(100.0, 0.08, 0.2, 1 / 252, z)
print(path[:4].round(3), round(float(path[-1]), 3))

مسارات كثيرة: المتوسط والوسيط

حاكِ آلاف المسارات لسنة واحدة وانظر أين تنتهي. فمتوسط السعر النهائي قريب من S0 * exp(mu * T) صيغة السعر المتوقع. أما *الوسيط* فأقل، S0 * exp((mu - sigma**2/2) * T)، ومع التقلب العالي يكون الفارق كبيرًا: تنتهي معظم المسارات دون المتوسط الذي ترفعه مسارات قليلة مذهلة. وهذا الالتواء نحو اليمين، توزيع لوغاريتمي طبيعي، هو شكل أسعار الأسهم على الآفاق الطويلة.

import numpy as np

rng = np.random.default_rng(5)
s0, mu, sigma, T, steps, paths = 100.0, 0.08, 0.4, 1.0, 252, 20000
dt = T / steps
z = rng.standard_normal((paths, steps))
final = s0 * np.exp(np.sum((mu - 0.5 * sigma ** 2) * dt + sigma * np.sqrt(dt) * z, axis=1))

print(round(float(final.mean()), 1), round(s0 * np.exp(mu * T), 1))                      # close to each other: the expected price
print(round(float(np.median(final)), 1), round(s0 * np.exp((mu - 0.5 * sigma ** 2) * T), 1))   # the median is lower
print(round(float(np.mean(final < s0)), 3))                                              # the share of paths that lose money

تقدير mu و sigma

من أسعار تؤخذ كل dt سنة تكون العوائد اللوغاريتمية r = diff(log(prices)) طبيعية مستقلة بمتوسط (mu - sigma**2/2) * dt وانحراف معياري sigma * sqrt(dt). فـsigma = std(r) / sqrt(dt) وmu = mean(r) / dt + sigma**2 / 2. وتقدير التقلب جيد بمئات النقاط؛ أما الانجراف فمضطرب بشدة لأن خطؤه المعياري لا يتقلص إلا مع *الزمن* الكلي لا مع عدد المشاهدات.

import numpy as np

def estimate_gbm(prices, dt):
    r = np.diff(np.log(prices))
    sigma = r.std(ddof=1) / np.sqrt(dt)
    return r.mean() / dt + 0.5 * sigma ** 2, sigma

rng = np.random.default_rng(8)
dt = 1 / 252
for years in (1, 10, 100):
    n = int(years * 252)
    log_moves = (0.10 - 0.5 * 0.25 ** 2) * dt + 0.25 * np.sqrt(dt) * rng.standard_normal(n)
    prices = 100 * np.exp(np.concatenate([[0.0], np.cumsum(log_moves)]))
    mu, sigma = estimate_gbm(prices, dt)
    print(years, "years:", round(float(mu), 3), round(float(sigma), 3))           # true mu 0.10 and sigma 0.25
الحركة الهندسية بداية جيدة وليست الحقيقةللأسعار الحقيقية ذيول سميكة وقفزات وتقلب متحرك (موضوع GARCH)، ولا شيء من ذلك في الحركة الهندسية. وميزتها أن كل شيء صريح فيها: الأسعار لوغاريتمية طبيعية وللسعر المتوقع صيغة وتنتج منها أسعار الخيارات. والنماذج التي تصلح عيوبها (القفزات والتقلب العشوائي) تُبنى فوقها.
  • الحركة الهندسية: S(t) = S(0) * exp((mu - sigma**2 / 2) * t + sigma * W(t))؛ التغيرات النسبية عشوائية والأسعار موجبة.
  • يلغي - sigma**2 / 2 تحدب exp: السعر المتوقع S0 * exp(mu * t) لكن المسار الوسيط ينمو بـ mu - sigma**2 / 2.
  • قدّر من العوائد اللوغاريتمية: sigma = std(r) / sqrt(dt) وmu = mean(r) / dt + sigma**2 / 2؛ يُقدَّر التقلب جيدًا والانجراف رديئًا.

التالي: مبرهنة إيتو، قاعدة السلسلة التي تفسر أصل الحد - sigma**2 / 2.

المختبر: ما الذي يُقيَّم

  • اتخذ خطوة دقيقة واحدة باستخدام gbm_step25 نقطة
  • حاكِ مسار سعر باستخدام gbm_path25 نقطة
  • احسب متوسط كل المستقبلات باستخدام gbm_expected25 نقطة
  • استخرج المعاملات باستخدام estimate_gbm25 نقطة
المستكشف · lab-103-1
▾ lab-103-1
…
bash · داخل المتصفح
learner@quantcraft:~/lab-103-1$
لم يتم تحميل Python بعدPythonLn 1, Col 1Spaces: 4UTF-8

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

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

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

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

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

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