Portfolio optimization using multiple risk models#
Let \(w \in \mathbb{R}^n\) be a vector of portfolio weights, where negative values correspond to short positions, and the weights are normalized such that \(\mathbb{1}^T w = 1\). The expected return of the portfolio is \(\mu^T w\), where \(\mu\in \mathbb{R}^n\) is the (known) vector of expected asset returns.
As usual we measure the risk of the portfolio using the variance of the portfolio return. However, in this problem we do not know the covariance matrix \(\Sigma\) of the asset returns; instead we assume that \(\Sigma\) is one of \(M\) (known) covariance matrices \(\Sigma^{(k)} \in \mathbb{S}_{++}^n\), \(k = 1 , \ldots , M\). We can think of the \(\Sigma^{(k)}\) as representing \(M\) different risk models, associated with \(M\) different market regimes (say). For a weight vector \(w\), there are \(M\) different possible values of the risk: \(w^T\Sigma^{(k)}w\), \(k=1, \ldots, M\).
The worst-case risk, across the different models, is given by \(\max_{k=1,\ldots, M} w^T\Sigma^{(k)}w\). (This is the same as the worst-case risk over all covariance matrices in the convex hull of \(\Sigma^{(1)}, \ldots, \Sigma^{(M)}\).)
We will choose the portfolio weights in order to maximize the expected return, adjusted by the worst-case risk, \ie, as the solution \(w^\star\) of the problem
with variable \(w\), where \(\gamma>0\) is a given risk-aversion parameter. We call this the mean-worst-case-risk portfolio problem.
Exercise#
Find the optimal portfolio weights for the problem instance with data given below. Report the weights, give the \(M\) possible values of the risk associated with your weights, and the worst-case risk.
# data for multi risk portfolio portfolio problem
import numpy as np
n = 10
M = 6
gamma = 1.0
mu = np.array(
[
0.0,
0.01401,
0.03426,
0.07843,
0.06536,
-0.0342,
0.03325,
-0.0053,
-0.00361,
0.01437,
]
)
Sigma_1 = np.array(
[
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[
0.0,
0.09551,
0.0349,
0.06526,
0.02499,
0.08272,
0.0574,
0.0279,
0.06016,
0.02578,
],
[
0.0,
0.0349,
0.10862,
0.05107,
0.04959,
0.08917,
0.03489,
0.03575,
0.05086,
0.04512,
],
[
0.0,
0.06526,
0.05107,
0.08159,
0.04136,
0.06879,
0.05743,
0.03721,
0.05037,
0.03557,
],
[
0.0,
0.02499,
0.04959,
0.04136,
0.05882,
0.05781,
0.03069,
0.02881,
0.04037,
0.04467,
],
[
0.0,
0.08272,
0.08917,
0.06879,
0.05781,
0.11844,
0.05441,
0.03745,
0.07088,
0.05695,
],
[
0.0,
0.0574,
0.03489,
0.05743,
0.03069,
0.05441,
0.06421,
0.0201,
0.05843,
0.02407,
],
[
0.0,
0.0279,
0.03575,
0.03721,
0.02881,
0.03745,
0.0201,
0.04035,
0.03334,
0.01554,
],
[
0.0,
0.06016,
0.05086,
0.05037,
0.04037,
0.07088,
0.05843,
0.03334,
0.07538,
0.02431,
],
[
0.0,
0.02578,
0.04512,
0.03557,
0.04467,
0.05695,
0.02407,
0.01554,
0.02431,
0.04693,
],
]
)
Sigma_2 = np.array(
[
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[
0.0,
0.09527,
0.04324,
0.06411,
0.03937,
0.08697,
0.0531,
0.02343,
0.04872,
0.03118,
],
[
0.0,
0.04324,
0.10897,
0.05601,
0.0504,
0.07851,
0.02892,
0.05001,
0.05234,
0.03949,
],
[
0.0,
0.06411,
0.05601,
0.08566,
0.04111,
0.07517,
0.05672,
0.04489,
0.04828,
0.02699,
],
[
0.0,
0.03937,
0.0504,
0.04111,
0.0629,
0.06144,
0.03637,
0.01778,
0.03433,
0.03934,
],
[
0.0,
0.08697,
0.07851,
0.07517,
0.06144,
0.11296,
0.04474,
0.04238,
0.0637,
0.04279,
],
[
0.0,
0.0531,
0.02892,
0.05672,
0.03637,
0.04474,
0.06381,
0.02148,
0.04539,
0.02673,
],
[
0.0,
0.02343,
0.05001,
0.04489,
0.01778,
0.04238,
0.02148,
0.04386,
0.02824,
0.02502,
],
[
0.0,
0.04872,
0.05234,
0.04828,
0.03433,
0.0637,
0.04539,
0.02824,
0.07299,
0.01923,
],
[
0.0,
0.03118,
0.03949,
0.02699,
0.03934,
0.04279,
0.02673,
0.02502,
0.01923,
0.0441,
],
]
)
Sigma_3 = np.array(
[
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[
0.0,
0.09758,
0.036,
0.05946,
0.03143,
0.08617,
0.05603,
0.02755,
0.04373,
0.03548,
],
[
0.0,
0.036,
0.11032,
0.07466,
0.04976,
0.06889,
0.04397,
0.0413,
0.0693,
0.05059,
],
[
0.0,
0.05946,
0.07466,
0.08391,
0.04429,
0.06875,
0.05999,
0.03834,
0.05702,
0.03957,
],
[
0.0,
0.03143,
0.04976,
0.04429,
0.0628,
0.0601,
0.04081,
0.02044,
0.0435,
0.03797,
],
[
0.0,
0.08617,
0.06889,
0.06875,
0.0601,
0.11514,
0.05033,
0.03409,
0.05194,
0.05301,
],
[
0.0,
0.05603,
0.04397,
0.05999,
0.04081,
0.05033,
0.0634,
0.03646,
0.055,
0.03016,
],
[
0.0,
0.02755,
0.0413,
0.03834,
0.02044,
0.03409,
0.03646,
0.04068,
0.03718,
0.02399,
],
[
0.0,
0.04373,
0.0693,
0.05702,
0.0435,
0.05194,
0.055,
0.03718,
0.07564,
0.02574,
],
[
0.0,
0.03548,
0.05059,
0.03957,
0.03797,
0.05301,
0.03016,
0.02399,
0.02574,
0.04612,
],
]
)
Sigma_4 = np.array(
[
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[
0.0,
0.09257,
0.05796,
0.06027,
0.02972,
0.07934,
0.04614,
0.03909,
0.04214,
0.04069,
],
[
0.0,
0.05796,
0.11237,
0.07639,
0.06354,
0.07092,
0.05474,
0.05455,
0.04729,
0.05416,
],
[
0.0,
0.06027,
0.07639,
0.08818,
0.04459,
0.07078,
0.06168,
0.03892,
0.05792,
0.02804,
],
[
0.0,
0.02972,
0.06354,
0.04459,
0.05821,
0.04937,
0.03315,
0.02327,
0.03579,
0.04053,
],
[
0.0,
0.07934,
0.07092,
0.07078,
0.04937,
0.11239,
0.04701,
0.04395,
0.05605,
0.05801,
],
[
0.0,
0.04614,
0.05474,
0.06168,
0.03315,
0.04701,
0.06062,
0.02048,
0.03839,
0.02321,
],
[
0.0,
0.03909,
0.05455,
0.03892,
0.02327,
0.04395,
0.02048,
0.0407,
0.03774,
0.03034,
],
[
0.0,
0.04214,
0.04729,
0.05792,
0.03579,
0.05605,
0.03839,
0.03774,
0.07333,
0.03067,
],
[
0.0,
0.04069,
0.05416,
0.02804,
0.04053,
0.05801,
0.02321,
0.03034,
0.03067,
0.04903,
],
]
)
Sigma_5 = np.array(
[
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[
0.0,
0.09782,
0.03566,
0.07154,
0.02311,
0.08306,
0.04749,
0.02112,
0.0424,
0.03644,
],
[
0.0,
0.03566,
0.10871,
0.07059,
0.06327,
0.07008,
0.05601,
0.03631,
0.04979,
0.03542,
],
[
0.0,
0.07154,
0.07059,
0.08676,
0.03368,
0.07664,
0.04439,
0.03324,
0.04954,
0.04171,
],
[
0.0,
0.02311,
0.06327,
0.03368,
0.06425,
0.06407,
0.03624,
0.02072,
0.03599,
0.03501,
],
[
0.0,
0.08306,
0.07008,
0.07664,
0.06407,
0.12031,
0.05653,
0.04843,
0.07035,
0.0477,
],
[
0.0,
0.04749,
0.05601,
0.04439,
0.03624,
0.05653,
0.06048,
0.02421,
0.04491,
0.03085,
],
[
0.0,
0.02112,
0.03631,
0.03324,
0.02072,
0.04843,
0.02421,
0.04139,
0.03155,
0.01375,
],
[
0.0,
0.0424,
0.04979,
0.04954,
0.03599,
0.07035,
0.04491,
0.03155,
0.07377,
0.02758,
],
[
0.0,
0.03644,
0.03542,
0.04171,
0.03501,
0.0477,
0.03085,
0.01375,
0.02758,
0.04266,
],
]
)
Sigma_6 = np.array(
[
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[
0.0,
0.09255,
0.04784,
0.06448,
0.03509,
0.0763,
0.04992,
0.02928,
0.0457,
0.03255,
],
[
0.0,
0.04784,
0.1073,
0.06532,
0.06136,
0.08782,
0.04596,
0.04693,
0.05876,
0.04758,
],
[
0.0,
0.06448,
0.06532,
0.08067,
0.04062,
0.07364,
0.05039,
0.03586,
0.06005,
0.03123,
],
[
0.0,
0.03509,
0.06136,
0.04062,
0.05804,
0.05872,
0.03194,
0.02341,
0.04013,
0.03734,
],
[
0.0,
0.0763,
0.08782,
0.07364,
0.05872,
0.10969,
0.05726,
0.04673,
0.05876,
0.0505,
],
[
0.0,
0.04992,
0.04596,
0.05039,
0.03194,
0.05726,
0.06021,
0.02738,
0.04926,
0.02845,
],
[
0.0,
0.02928,
0.04693,
0.03586,
0.02341,
0.04673,
0.02738,
0.0397,
0.02841,
0.02057,
],
[
0.0,
0.0457,
0.05876,
0.06005,
0.04013,
0.05876,
0.04926,
0.02841,
0.07194,
0.0291,
],
[
0.0,
0.03255,
0.04758,
0.03123,
0.03734,
0.0505,
0.02845,
0.02057,
0.0291,
0.04176,
],
]
)