تحليل المحافظ في pandas: مصفوفات الارتباط والتغاير وتقلب المحفظة المرجّح ومحاكاة إعادة التوازن
احسب مصفوفات التغاير والارتباط السنوية من العوائد، واشتقّ تقلب المحفظة ومساهمات المخاطر باستخدام NumPy، وحاكِ الانجراف مقابل إعادة التوازن وفق التقويم.
ما الذي ستتعلمه
- كيف توائم عدة سلاسل أسعار في إطار DataFrame واحد للعوائد، وتحسب
.cov()و.corr()محوَّلين إلى قيم سنوية بشكل صحيح. - الصيغة المصفوفية لتقلب المحفظة،
w.T @ Σ @ w، وكيف تقرأ مساهمة كل أصل في المخاطر. - كيف تحاكي محفظة شراء واحتفاظ تنجرف أوزانها مقابل محفظة يُعاد توازنها وفق التقويم.
- أي الفخاخ العددية (التواريخ غير المتوائمة، والعملات المختلطة، والاستباق في نافذة التغاير) تُنتج إجابات خاطئة.
الشرح
جرى في مواضع أخرى تدريس الارتباط وحرارة المحفظة (دورة «إدارة المخاطر والصفقات»، الدرس 6)، والجمع بين نظامين (دورة «التداول المنهجي والاختبار الرجعي»، الدرس 10)، وقواعد إعادة التوازن (دورة «صناديق ETF والصناديق الاستثمارية والاستثمار طويل الأجل»، الدرس 10)؛ أما هذا الدرس فينفّذها بالكود لأي عدد من الأصول.
من الأسعار إلى مصفوفة العوائد
حمّل سعر الإغلاق المعدّل لكل أداة (الدرس 4) في إطار DataFrame واحد، بعمود لكل رمز: prices = pd.concat(series_dict, axis=1). العطلات التي تختلف بين الأسواق تُنشئ صفوفًا تحتوي على NaN؛ فقرّر صراحةً بين prices.dropna() (الأيام المشتركة فقط) وprices.ffill() (نقل آخر سعر إلى الأمام). ثم rets = prices.pct_change().dropna(). حوّل كل شيء إلى عملة واحدة أولًا؛ فصندوق ETF أمريكي يحتفظ به مستثمر باليورو يجب تحويله باستخدام سلسلة EUR/USD، وإلا فإن تقلبه وارتباطاته تصف شيئًا آخر غير المقصود.
التغاير والارتباط والتحويل إلى قيم سنوية
rets.cov() هي مصفوفة التغاير للعيّنة للعوائد اليومية؛ اضربها في 252 لتحويلها إلى قيم سنوية (يتناسب التباين مع الزمن). أما rets.corr() فخالية من الوحدات ولا تحتاج إلى تحجيم. يحمل القطر تباين كل أصل، لذا يعطي np.sqrt(np.diag(cov_a)) التقلبات السنوية. وتتيح لك العلاقة Σ_ij = ρ_ij × σ_i × σ_j بناء مصفوفة من التقلبات والارتباطات لاختبار سيناريو افتراضي مثل «ارتفاع الارتباطات إلى 0.8 في أزمة».
تقلب المحفظة ومساهمات المخاطر
w = np.array([0.5, 0.3, 0.2]) # الأوزان، ومجموعها 1cov_a = rets.cov().values * 252port_var = w @ cov_a @ wport_vol = np.sqrt(port_var)marginal = cov_a @ w # d(var)/d(w)risk_contrib = w * marginal / port_var # حصص مجموعها 1
الرمز @ هو ضرب المصفوفات. يخبرك risk_contrib بالنسبة من تباين المحفظة التي يتحمّل كل أصل مسؤوليتها؛ وعادةً ما تكون بعيدة عن الوزن الرأسمالي، وهذه الفجوة هي نقطة انطلاق ميزانية المخاطر (دورة «بناء المحفظة بتعمّق: ميزانيات المخاطر والأنظمة السوقية واختبارات الضغط»، الدرس 1).
محاكاة إعادة التوازن
يترك الشراء والاحتفاظ الأوزان تنجرف: فتنمو الأصول الرابحة لتشغل حصة أكبر. أما إعادة التوازن وفق التقويم فتعيد الأوزان إلى أهدافها في تواريخ ثابتة. في pandas، أعِد تشكيل العوائد إلى تواتر إعادة التوازن ومُرّ بحلقة على الفترات:
period_rets = (1 + rets).resample('ME').prod() - 1 # العوائد الشهريةtarget = np.array([0.6, 0.4]); hold = 10_000 * target; path = []for _, r in period_rets.iterrows():hold = hold * (1 + r.values) # نمّ كل شريحةpath.append(hold.sum())hold = hold.sum() * target # أعِد التوازن إلى الأهداف
للنسخة المنجرفة، احذف السطر الأخير. استخدم 'QE' للتواتر الفصلي و'YE' للسنوي (pandas 2.2 وما بعده؛ تستخدم الإصدارات الأقدم 'M' و'Q' و'A'). دوران إعادة التوازن هو abs(new_hold - old_hold).sum()؛ اضربه في معدل تكلفة مثل 0.1 % واطرحه. وفي حساب خاضع للضريبة في ألمانيا، تؤدي إعادة التوازن أيضًا إلى تحقيق الأرباح؛ فراجع الأثر الضريبي مع مستشار ضريبي (Steuerberater).
مثال محلول
مثال افتراضي بمدخلات مختلَقة؛ والرسوم والفوارق السعرية والضرائب مستبعدة.
الجزء 1: تقلب ثلاثة أصول. التقلبات السنوية 20 % و10 % و15 %؛ والارتباطات ρ₁₂ = 0.2 وρ₁₃ = 0.6 وρ₂₃ = 0.1؛ والأوزان 50 / 30 / 20 %.
- التغايرات: Σ₁₂ = 0.2 × 0.20 × 0.10 = 0.0040؛ Σ₁₃ = 0.6 × 0.20 × 0.15 = 0.0180؛ Σ₂₃ = 0.1 × 0.10 × 0.15 = 0.0015. القطر: 0.0400، 0.0100، 0.0225.
- تباين المحفظة = Σ wᵢ wⱼ Σᵢⱼ = 0.25 × 0.04 + 0.09 × 0.01 + 0.04 × 0.0225 + 2 × (0.5 × 0.3 × 0.004 + 0.5 × 0.2 × 0.018 + 0.3 × 0.2 × 0.0015) = 0.0100 + 0.0009 + 0.0009 + 2 × (0.0006 + 0.0018 + 0.00009) = 0.01678.
- تقلب المحفظة = √0.01678 = 12.95 %، مقابل متوسط مرجّح للتقلبات قدره 16.0 %؛ والفرق هو منفعة التنويع.
- مساهمات المخاطر: يتحمّل الأصل 1 نسبة 73.9 % من التباين مقابل 50 % من رأس المال؛ والأصل 2 نسبة 9.5 % مقابل 30 %؛ والأصل 3 نسبة 16.6 % مقابل 20 %.
الجزء 2: الانجراف مقابل إعادة التوازن. €10,000 مقسّمة 60 / 40 بين الأصل A والأصل B. العوائد السنوية: A +20 %، −10 %، +15 %؛ B +2 %، +4 %، +1 %.
- الانجراف: A: 6,000 × 1.20 × 0.90 × 1.15 = €7,452؛ B: 4,000 × 1.02 × 1.04 × 1.01 = €4,285.63. الإجمالي €11,737.63؛ وقد انجرف وزن A إلى 63.5 %.
- إعادة التوازن السنوية: إجمالي السنة 1 = 7,200 + 4,080 = €11,280 ← إعادة الضبط إلى 6,768 / 4,512؛ السنة 2 = 6,091.20 + 4,692.48 = €10,783.68 ← إعادة الضبط؛ السنة 3 = 7,440.74 + 4,356.61 = €11,797.35.
- انتهت إعادة التوازن أعلى بمقدار €59.72 لأنها باعت من A بعد +20 % وأعادت الشراء بعد −10 %. ولو كان اتجاه A صاعدًا بثبات لفاز الانجراف؛ فإعادة التوازن تضبط المخاطر، ولا تضمن العائد.
خطأ شائع
rets.cov() على الفترة 2015–2025 ويستخدم النتيجة لتحديد الأوزان في عام 2015 إنما يستخدم معلومات من المستقبل. قدّر التغاير على نافذة متحركة أو متوسّعة (rets.rolling(252).cov() أو rets.loc[:date].cov()) وطبّقه على الفترة التالية فقط. كما ترتفع الارتباطات في الأزمات، لذا فإن مصفوفة من فترة هادئة تقلّل من تقدير المخاطر في اللحظة التي تكون فيها أهم.نشاط تطبيقي
على الورق: أصلان تقلبهما السنوي 18 % و6 %، والارتباط 0.3، والأوزان 70 / 30 %. (أ) ابنِ مصفوفة التغاير 2 × 2. (ب) احسب تباين المحفظة وتقلبها. (ج) احسب مساهمة كل أصل في المخاطر بوصفها حصة من التباين. (د) أعد حساب التقلب مع ارتباط قدره 0.9، واذكر في جملة واحدة لماذا يهمّ ذلك.
عرض الحل
(أ) Σ₁₁ = 0.0324؛ Σ₂₂ = 0.0036؛ Σ₁₂ = 0.3 × 0.18 × 0.06 = 0.00324.
(ب) التباين = 0.49 × 0.0324 + 0.09 × 0.0036 + 2 × 0.7 × 0.3 × 0.00324 = 0.015876 + 0.000324 + 0.0013608 = 0.0175608؛ والتقلب = 13.25 %.
(ج) الهامشية: الأصل 1: 0.7 × 0.0324 + 0.3 × 0.00324 = 0.023652؛ الأصل 2: 0.7 × 0.00324 + 0.3 × 0.0036 = 0.003348. المساهمات: 0.7 × 0.023652 / 0.0175608 = 94.3 %؛ 0.3 × 0.003348 / 0.0175608 = 5.7 %.
(د) مع ρ = 0.9: Σ₁₂ = 0.00972؛ التباين = 0.015876 + 0.000324 + 0.0040824 = 0.0202824؛ التقلب = 14.24 %. لا يضيف «الأصل المنوِّع» إلا القليل عندما يرتفع الارتباط، وهذا تحديدًا ما يميل إلى الحدوث في موجات البيع؛ لذا ينبغي الحكم على المحفظة بالارتباطات في ظروف الضغط، لا بالمتوسط التاريخي وحده.
القيود: التغاير للعيّنة المحسوب من بضع سنوات من البيانات اليومية مشوَّش؛ وتغييرات صغيرة في النافذة قد تحرّك الارتباطات بمقدار 0.1 أو أكثر.
أهم النقاط
- وائم التواريخ والعملات قبل حساب العوائد؛ وقرّر صراحةً كيف تتعامل مع الأيام المفقودة.
- حوّل التغاير إلى قيم سنوية بضربه في عدد الفترات في السنة؛ أما الارتباط فلا يحتاج إلى تحجيم.
- تقلب المحفظة هو √(wᵀ Σ w)؛ ومساهمات المخاطر w × (Σw) / التباين تُظهر أين تكمن المخاطر فعلًا.
- حاكِ إعادة التوازن بإعادة تشكيل العوائد وإعادة ضبط الحيازات؛ وقدّر التغاير فقط من البيانات المتاحة في حينه.
الخطوة التالية
يؤتمت الدرس 12 الروتين اليومي: سكربت مجدول يجلب البيانات ويحسب الإشارات ويكتب تقريرًا، مع التعامل السليم مع مفاتيح API وحدود معدّل الطلبات.
تقييم ذاتي
أجب عن الأسئلة، ثم تحقّق من إجاباتك. يمكنك إعادة المحاولة بقدر ما تشاء.
تقييم ذاتي تلقائي لمراجعتك الشخصية. تُفحَص إجاباتك في متصفحك ولا نطّلع عليها ولا نقيّمها. هذا ليس امتحانًا ولا مؤهّلًا.
تقدّمك
«مكتمل» يعني فقط أنك علّمت الدرس كمنتهٍ. وهو ليس اختبارًا لفهمك. يُحفظ التقدّم والملاحظات فقط في هذا المتصفح على هذا الجهاز — وليس في حساب.