σμ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.6·~45 دمتقدم

المتغيرات المتعاكسة

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

الدقة مكلفة

ينخفض الخطأ المعياري لتقدير مونت كارلو مثل 1 / sqrt(N): عشرة أضعاف الدقة تحتاج مئة ضعف المسارات. وعندما تكون المحاكاة مكلفة فالرافعة الأفضل من زيادة المسارات هي تقليل الضجيج في كل مسار. وهذه طرق تقليل التباين، وأبسطها المتغيرات المتقابلة. تستخدم الأعداد العشوائية نفسها مرتين: مع كل عينة z نشغّل أيضًا مسار -z.

import numpy as np

def terminal_price(s0, rate, sigma, t, z):
    return s0 * np.exp((rate - 0.5 * sigma ** 2) * t + sigma * np.sqrt(t) * z)

z = np.array([-1.0, 0.0, 1.0])
print(np.round(terminal_price(100.0, 0.05, 0.2, 1.0, z), 3))         # the price for z = -1, 0, 1
print(np.round(terminal_price(100.0, 0.05, 0.2, 1.0, -z), 3))        # and for the opposite draws: mirror images

لماذا يفيد الاقتران

إذا كانت z كبيرة وموجبة تنتهي المسار عاليًا ويدفع الكول كثيرًا؛ ومع -z تنتهي منخفضة ويدفع قليلًا. فمدفوعاتهما مرتبطة سلبيًا ومتوسط الزوج أثبت بكثير من كل منهما. وفي المدفوع الرتيب كالكول يكون لتباين متوسط الزوج (f(z) + f(-z)) / 2 قيمة (1 + corr) / 2 من تباين مدفوع واحد، مع corr سالب. ويبقى السعر متوسط كمية غير متحيزة فلا انحياز.

import numpy as np

def terminal_price(s0, rate, sigma, t, z):
    return s0 * np.exp((rate - 0.5 * sigma ** 2) * t + sigma * np.sqrt(t) * z)

z = np.random.default_rng(1).standard_normal(20000)
up = np.maximum(terminal_price(100.0, 0.05, 0.2, 1.0, z) - 100.0, 0.0)       # call payoffs for z
down = np.maximum(terminal_price(100.0, 0.05, 0.2, 1.0, -z) - 100.0, 0.0)    # ... and for -z
print(round(float(np.corrcoef(up, down)[0, 1]), 3))                           # negative: the payoffs offset each other

المقدّر وهامش خطئه

عامِل كل زوج كمشاهدة واحدة: pair = (payoff(z) + payoff(-z)) / 2. التقدير هو المتوسط المخصوم لمدفوعات الأزواج، والخطأ المعياري هو الانحراف المعياري المخصوم (ddof=1) للأزواج على sqrt(عدد الأزواج). والعدد هو عدد *الأزواج* لأن عضوي الزوج غير مستقلين. ولتقدير المكسب قارن بتقدير عادي يستخدم العدد نفسه من المدفوعات من عينات مستقلة.

import numpy as np

def terminal_price(s0, rate, sigma, t, z):
    return s0 * np.exp((rate - 0.5 * sigma ** 2) * t + sigma * np.sqrt(t) * z)

def mc_estimate(payoffs, discount):
    return discount * payoffs.mean(), discount * payoffs.std(ddof=1) / np.sqrt(len(payoffs))

def call_payoff(z):
    return np.maximum(terminal_price(100.0, 0.05, 0.2, 1.0, z) - 100.0, 0.0)

rng = np.random.default_rng(3)
z, w = rng.standard_normal(5000), rng.standard_normal(5000)
discount = np.exp(-0.05)

plain = mc_estimate(call_payoff(np.concatenate([z, w])), discount)           # 10,000 independent payoffs
anti = mc_estimate((call_payoff(z) + call_payoff(-z)) / 2, discount)         # 5,000 pairs: the same 10,000 evaluations
print([round(float(v), 4) for v in plain], [round(float(v), 4) for v in anti])
print(round(float(plain[1] / anti[1]), 2), "times smaller error")
# A call profits from pairing; a straddle (symmetric in z) does not
import numpy as np

def terminal_price(z):
    return 100.0 * np.exp((0.05 - 0.5 * 0.2 ** 2) + 0.2 * z)

rng = np.random.default_rng(4)
z = rng.standard_normal(20000)
for name, payoff in (("call", lambda p: np.maximum(p - 100.0, 0.0)), ("straddle", lambda p: np.abs(p - 100.0))):
    pairs = (payoff(terminal_price(z)) + payoff(terminal_price(-z))) / 2
    plain = payoff(terminal_price(np.concatenate([z, rng.standard_normal(20000)])))
    ratio = (plain.std(ddof=1) / np.sqrt(len(plain))) / (pairs.std(ddof=1) / np.sqrt(len(pairs)))
    print(name, round(float(ratio), 2))                       # the call gains (1.41); the straddle gets worse (0.78)
متى تفيد ومتى لا تفيديعمل أخذ العينات المتقابل حين يكون المدفوع رتيبًا في العينة (الكول والبوت وكثير من الفروق). وقد لا يفيد شيئًا بل قد يضر مع مدفوع متماثل في z كالستراددل حيث يتشابه f(z) وf(-z) فلا يضيف الزوج معلومة. لكنه مجاني: لا حاجة لأعداد عشوائية إضافية، ويمكن دمجه مع المتغيرات الضابطة في الموضوع التالي.
  • استخدم كل عينة z مع -z؛ وخذ متوسط المدفوعين في مدفوع زوج أقل ضجيجًا بكثير للمدفوع الرتيب.
  • يُحسب الخطأ المعياري على عدد الأزواج بـddof=1: discount * std(pairs) / sqrt(pairs).
  • قارن بتقدير عادي بالكلفة نفسها؛ لا تفيد المدفوعات المتماثلة في z، وتُدمج مع المتغيرات الضابطة.

التالي: المتغيرات الضابطة، استخدام كمية قيمتها الدقيقة معروفة لإلغاء الضجيج.

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

  • حوّل العينات إلى أسعار باستخدام terminal_price25 نقطة
  • أبلغ عن التقدير وخطئه باستخدام mc_estimate25 نقطة
  • قرن كل عينة بعكسها باستخدام antithetic_call_price25 نقطة
  • قِس المكسب باستخدام variance_ratio25 نقطة
المستكشف · lab-107-1
▾ lab-107-1
…
bash · داخل المتصفح
learner@quantcraft:~/lab-107-1$
لم يتم تحميل Python بعدPythonLn 1, Col 1Spaces: 4UTF-8

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

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

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

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

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

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