σμ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.1·~45 دمتوسط

مصفوفات التباين المشترك والارتباط

الموضع في المسارالوحدة 5 من 11 · الموضوع 1 من 5
5.1 مصفوفات التباين المشترك والارتباط
—درجة المختبر— / 100إجمالي XP—التتابع—

من أصل واحد إلى أصول كثيرة

كل ما سبق نظر في سلسلة عوائد واحدة. أما المحفظة فتضم أصولًا كثيرة، ولا يعتمد خطرها على خطر كل أصل فقط بل على كيفية حركتها *معًا*. والتغاير بين أصلين هو متوسط حاصل ضرب انحرافيهما عن المتوسط: موجب إن مالا إلى الصعود والهبوط معًا، وسالب إن صعد أحدهما بينما هبط الآخر. وبالنسبة إلى n أصلًا توجد n * n تغايرات تُرتَّب في مصفوفة تغاير، وهي متماثلة وعلى قطرها التباينات.

import numpy as np

# Five days of returns for two assets: shape (days, assets)
returns = np.array([[0.01, 0.02], [-0.02, -0.01], [0.03, 0.01], [0.00, -0.02], [0.01, 0.03]])

centered = returns - returns.mean(axis=0)            # subtract each column's mean
cov = centered.T @ centered / (len(returns) - 1)     # (assets x days) @ (days x assets) -> (assets x assets)
print(np.round(cov, 6))
print(np.allclose(cov, np.cov(returns, rowvar=False)))     # True

مصفوفة التغاير للعينة

مع جدول عوائد بالشكل (days, assets) تصبح المصفوفة كلها سطرًا واحدًا من الجبر الخطي. نطرح متوسط كل عمود (axis=0، المتوسط عبر الأيام)، ونضرب منقول الجدول المركّز في نفسه: العنصر (i, j) في centered.T @ centered هو مجموع x_i * x_j عبر الأيام. ثم نقسم على days - 1 كما في تباين العينة. وهذا ما يحسبه np.cov(returns, rowvar=False) وDataFrame.cov()؛ لاحظ rowvar=False لأن np.cov يتوقع الأصول في الصفوف.

الارتباط: التغاير بلا وحدات

تغاير قدره 0.0004 لا يقول الكثير: فهو يعتمد على مدى تقلب الأصلين. والقسمة على حاصل ضرب الانحرافين المعياريين تزيل المقياس وتعطي الارتباط الذي يقع دائمًا بين -1 و1: corr[i, j] = cov[i, j] / (std[i] * std[j]) حيث std الجذر التربيعي للقطر. وفي الكود يبني np.outer(std, std) جدول الحواصل وتعيد قسمة واحدة تحجيم المصفوفة كلها بآحاد على القطر. يخبرنا الارتباط بمدى تلازم حركة أصلين؛ أما التغاير الذي يحتفظ بالمقياس فهو ما تحتاجه صيغ المخاطر.

# From covariance to correlation and annualised volatilities
import numpy as np

returns = np.array([[0.01, 0.02], [-0.02, -0.01], [0.03, 0.01], [0.00, -0.02], [0.01, 0.03]])
cov = np.cov(returns, rowvar=False)

std = np.sqrt(np.diag(cov))
corr = cov / np.outer(std, std)
print(np.round(corr, 4))
print(np.round(np.sqrt(np.diag(cov) * 252), 4))      # daily variances scaled to a year: volatility grows with sqrt(252)

هل يمكن أن تكون هذه المصفوفة حقيقية؟

جدول أرقام عشوائي ليس مصفوفة تغاير. فيجب أن تكون متماثلة وشبه معرّفة موجبة: فمن أجل أي أوزان w فإن العدد w' C w هو تباين محفظة فلا يمكن أن يكون سالبًا. وبصورة مكافئة لا توجد قيمة ذاتية سالبة. المصفوفات المقدَّرة تجتاز الاختبار، أما المعدّلة يدويًا أو المركّبة من ارتباطات من مصادر مختلفة (مثل A~B = 0.9 وB~C = 0.9 وA~C = -0.9) فتفشل. ويُفحص ذلك بـ np.linalg.eigvalsh للمصفوفات المتماثلة وهي تعيد قيمًا ذاتية حقيقية، مع تسامح صغير للتقريب.

# A validity check: symmetry and no negative eigenvalue
import numpy as np

def is_valid_cov(matrix, tol=1e-10):
    symmetric = bool(np.all(np.abs(matrix - matrix.T) <= tol))
    return symmetric and bool(np.linalg.eigvalsh(matrix).min() >= -tol)

good = np.array([[1.0, 0.5, 0.2], [0.5, 1.0, 0.3], [0.2, 0.3, 1.0]])
bad = np.array([[1.0, 0.9, -0.9], [0.9, 1.0, 0.9], [-0.9, 0.9, 1.0]])
print(is_valid_cov(good), np.round(np.linalg.eigvalsh(good), 3))
print(is_valid_cov(bad), np.round(np.linalg.eigvalsh(bad), 3))
# Few days, many assets: the sample covariance matrix is singular
import numpy as np

rng = np.random.default_rng(0)
returns = rng.normal(0, 0.01, size=(5, 8))              # 5 days, 8 assets
cov = np.cov(returns, rowvar=False)
print(np.linalg.matrix_rank(cov), "of", cov.shape[0])  # 4 of 8: some portfolios seem to have zero variance
ملاحظات قليلة وأصول كثيرةمصفوفة لـ500 سهم فيها 125,250 عنصرًا مختلفًا تُقدَّر من نحو 250 يومًا. وعندما تقل الأيام عن الأصول تكون مصفوفة العينة شاذة: تبدو محفظة ما بتباين صفر، وهو ما لا ينبغي لأي مُحسِّن أن يصدقه. ويقوم الممارسون بتقليص المصفوفة نحو هدف بسيط أو يستخدمون نموذج عوامل. والتقدير متوسط للماضي أيضًا: فلفترات الهدوء والأزمات تغايرات مختلفة جدًا.
  • مصفوفة التغاير لجدول (days, assets) هي centered.T @ centered / (days - 1): متماثلة والتباينات على القطر.
  • الارتباط هو cov / np.outer(std, std): بلا وحدات، بين -1 و1، وآحاد على القطر؛ وتُسنَّى التباينات بـ periods والتقلبات بجذره.
  • مصفوفة التغاير الصالحة متماثلة بلا قيم ذاتية سالبة (np.linalg.eigvalsh)؛ وقد تخرق التقديرات من أيام قليلة أو المعدلة يدويًا ذلك.

التالي: عائد المحفظة وتباينها، تحويل الأوزان وهذه المصفوفة إلى خطر المحفظة.

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

  • ابنِ جدول التغاير باستخدام cov_matrix25 نقطة
  • حوّلها إلى ارتباطات باستخدام corr_from_cov25 نقطة
  • اقرأ تقلب كل أصل باستخدام annualised_vols25 نقطة
  • اختبر إن كانت ممكنة فعلًا باستخدام is_valid_cov25 نقطة
المستكشف · lab-82-1
▾ lab-82-1
…
bash · داخل المتصفح
learner@quantcraft:~/lab-82-1$
لم يتم تحميل Python بعدPythonLn 1, Col 1Spaces: 4UTF-8

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

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

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

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

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

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