σμ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›الوحدة 5 · تحسين المحافظ›الموضوع 5.3·~50 دمتوسط

محفظة الحد الأدنى من التباين

الموضع في المسارالوحدة 5 من 11 · الموضوع 3 من 5
5.3 محفظة الحد الأدنى من التباين
—درجة المختبر— / 100إجمالي XP—التتابع—

أكثر المزيج أمانًا

الجمع بين الأصول يخفض المخاطر، لكن مقدار الخفض يعتمد على الأوزان. ومحفظة التباين الأدنى هي اختيار الأوزان، التي مجموعها 1، الذي له أصغر تباين ممكن. ولا تحتاج إلى أي توقع للعوائد، بل إلى مصفوفة التغاير فقط، وهذا سبب شعبيتها: فالعوائد المتوقعة شديدة الصعوبة في التقدير والتغايرات أقل صعوبة بكثير. وبالنسبة إلى أصلين تكون الإجابة صيغة، وبالنسبة إلى كثير منها حل نظام خطي.

# Two assets: volatility 20% and 10%, correlation 0.3
def variance(w, vol1, vol2, rho):
    return w * w * vol1 ** 2 + (1 - w) ** 2 * vol2 ** 2 + 2 * w * (1 - w) * rho * vol1 * vol2

vol1, vol2, rho = 0.20, 0.10, 0.3
w = (vol2 ** 2 - rho * vol1 * vol2) / (vol1 ** 2 + vol2 ** 2 - 2 * rho * vol1 * vol2)
print(round(w, 4), round(variance(w, vol1, vol2, rho) ** 0.5, 4))        # 0.1053 0.0979
print(round(variance(0.0, vol1, vol2, rho) ** 0.5, 4))                   # 0.1      all in the safe asset: riskier than the mix

أصول كثيرة: نظام خطي واحد

لتصغير w @ cov @ w بشرط sum(w) = 1 نجعل مشتقة اللاغرانجيان صفرًا. والنتيجة w = cov^-1 * 1 / (1' cov^-1 1): نحل النظام cov @ x = ones ثم نعيد تحجيم x ليجمع مجموع الأوزان إلى 1. والتباين الأدنى نفسه هو 1 / (1' cov^-1 1). وفي الكود نستخدم np.linalg.solve(cov, ones) لا np.linalg.inv(cov) @ ones: فهو أسرع وأدق لأنه لا يكوّن المعكوس أبدًا.

# Minimum-variance weights of three assets
import numpy as np

cov = np.array([[0.0400, 0.0060, 0.0100],
                [0.0060, 0.0100, 0.0020],
                [0.0100, 0.0020, 0.0225]])

x = np.linalg.solve(cov, np.ones(3))
weights = x / x.sum()
print(np.round(weights, 4), round(float(weights.sum()), 4))        # [0.0192 0.7082 0.2726] 1.0
print(round(float(weights @ cov @ weights), 6), round(1 / float(x.sum()), 6))      # 0.007742 twice: the same number
# No other mix with weights summing to 1 does better: try 5000 random ones
import numpy as np

cov = np.array([[0.0400, 0.0060, 0.0100],
                [0.0060, 0.0100, 0.0020],
                [0.0100, 0.0020, 0.0225]])
x = np.linalg.solve(cov, np.ones(3))
best = x / x.sum()

rng = np.random.default_rng(0)
trial = rng.normal(size=(5000, 3))
trial = trial / trial.sum(axis=1, keepdims=True)                  # each row sums to 1
variances = np.einsum("ij,jk,ik->i", trial, cov, trial)            # w @ cov @ w for every row
print(round(float(variances.min()), 6), round(float(best @ cov @ best), 6))
print(bool(variances.min() >= best @ cov @ best))                  # True

مراكز البيع والقيود

تسمح الصيغة بأوزان سالبة: فقد تبيع أصلًا على المكشوف لتحوط آخر. ولا يستطيع كثير من المستثمرين ذلك أو لا يريدونه، ويريدون أوزانًا طويلة فقط. وتقليص الأوزان السالبة إلى صفر ثم إعادة التحجيم حل سريع يُبقي الأوزان صالحة، لكنه ليس الأمثل الحقيقي للمراكز الطويلة، الذي يحتاج إلى محلّ عددي (برمجة تربيعية) لأن القيد w >= 0 يجعل المسألة ذات قيود متباينة. والمحفظة المقلَّصة يمكن حيازتها على الأقل ومقارنتها بسهولة بالمحفظة الحرة.

# The unconstrained solution shorts an asset; clip it and compare the risks
import numpy as np

cov = np.array([[0.04, 0.0342, 0.0],
                [0.0342, 0.0324, 0.0],
                [0.0, 0.0, 0.0225]])        # assets 1 and 2: volatility 20% and 18%, correlation 0.95

x = np.linalg.solve(cov, np.ones(3))
free = x / x.sum()
clipped = np.clip(free, 0, None)
clipped = clipped / clipped.sum()
print(np.round(free, 4), round(float(free @ cov @ free), 6))
print(np.round(clipped, 4), round(float(clipped @ cov @ clipped), 6))
أمثل نظريًا وهشّ عمليًاتستخدم الأوزان معكوس مصفوفة التغاير، وهو يضخم الأخطاء: فالأصول التي تبدو أقل ارتباطًا أو أقل تقلبًا قليلًا في العينة تحصل على أوزان كبيرة، وغالبًا مع مراكز بيع كبيرة، وتقفز الأوزان عندما تتحرك نافذة البيانات. ويقلّص الممارسون تقدير التغاير أو يحدّون الأوزان أو يضيفون عقوبة. والمحفظة ذات التباين الأدنى التي تبدو رائعة على بيانات ضبطها تُختبر على بيانات لاحقة لا على العينة نفسها.
  • التباين الأدنى لا يحتاج إلا إلى مصفوفة التغاير: لأصلين، (vol2**2 - rho * vol1 * vol2) / (vol1**2 + vol2**2 - 2 * rho * vol1 * vol2) في الأصل 1.
  • عمومًا w = solve(cov, ones) / sum(...) والتباين الأدنى 1 / (1' cov^-1 1)؛ استخدم np.linalg.solve لا المعكوس.
  • قد تبيع الإجابة الحرة أصولًا على المكشوف؛ والتقليص إلى صفر وإعادة التحجيم إصلاح سريع لا الأمثل الحقيقي، والأوزان هشة أمام خطأ التقدير.

التالي: تحسين المتوسط والتباين، بإضافة العوائد المتوقعة لإيجاد أفضل موازنة بين العائد والمخاطر.

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

  • امزج أصلين بأقل مخاطر باستخدام two_asset_weight25 نقطة
  • احسب أكثر الأوزان أمانًا باستخدام min_variance_weights25 نقطة
  • اذكر أدنى مخاطر باستخدام min_variance25 نقطة
  • تخلَّ عن مراكز البيع باستخدام long_only_weights25 نقطة
المستكشف · lab-84-1
▾ lab-84-1
…
bash · داخل المتصفح
learner@quantcraft:~/lab-84-1$
لم يتم تحميل Python بعدPythonLn 1, Col 1Spaces: 4UTF-8

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

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

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

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

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

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