أكثر المزيج أمانًا
الجمع بين الأصول يخفض المخاطر، لكن مقدار الخفض يعتمد على الأوزان. ومحفظة التباين الأدنى هي اختيار الأوزان، التي مجموعها 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 نقطة