ポートフォリオはウェイトのベクトル
ポートフォリオは資産ごとのウェイト、つまりそこに投じた価値の割合で表されます。ウェイトの合計は1で、負のウェイトは他の資産の資金を作るショートです。ある期間のリターンは各資産のリターンの加重平均なので、期待リターンは内積 w @ mu です。リターンは簡単な半分で、線形であり資産間の相互作用がありません。リスクはそうではありません。
import numpy as np
weights = np.array([0.6, 0.4]) # 60% in asset A, 40% in asset B
mu = np.array([0.08, 0.05]) # expected annual returns
print(weights.sum()) # 1.0
print(weights @ mu) # 0.068 = 0.6 * 0.08 + 0.4 * 0.05分散は2次形式
2つの資産では、w1 * A + w2 * B の分散は w1**2 * var(A) + w2**2 * var(B) + 2 * w1 * w2 * cov(A, B) で、各資産自身の分散に交差項が加わります。n 個の資産では w_i * w_j * cov[i, j] が n * n 個あり、その総和全体が2次形式 w @ cov @ w で、NumPy では1行です。重要なのは交差項で、2つの資産の相関が完全でなければ互いに一部打ち消し合うため、ポートフォリオのリスクはリスクの加重平均より小さくなります。
# The variance two ways: the explicit formula and the matrix form
import numpy as np
weights = np.array([0.6, 0.4])
cov = np.array([[0.04, 0.006], [0.006, 0.01]]) # variances 0.04 and 0.01 (volatilities 20% and 10%), covariance 0.006
explicit = weights[0] ** 2 * cov[0, 0] + weights[1] ** 2 * cov[1, 1] + 2 * weights[0] * weights[1] * cov[0, 1]
matrix_form = weights @ cov @ weights
print(round(explicit, 6), round(matrix_form, 6)) # 0.01888 0.01888
print(round(float(np.sqrt(matrix_form)), 4)) # 0.1374 a 13.7% volatility, below 0.6*20% + 0.4*10% = 16%# Diversification: 50/50 in two assets of 20% volatility, for several correlations
import numpy as np
weights = np.array([0.5, 0.5])
for rho in (1.0, 0.5, 0.0, -0.5):
cov = 0.2 * 0.2 * np.array([[1.0, rho], [rho, 1.0]])
print(rho, round(float(np.sqrt(weights @ cov @ weights)), 4)) # 1.0: 0.2, 0.5: 0.1732, 0.0: 0.1414, -0.5: 0.1リスクはどこから来るのか
運用者はどのポジションがリスクを生んでいるかを知りたいものです。資産 i のリスク寄与は w_i * (cov @ w)_i / sigma_p で、そのウェイトに、ポートフォリオ全体とどれだけ強く連動するかを掛け、ポートフォリオのボラティリティ sigma_p で割ったものです。寄与の合計はちょうど sigma_p になり、全体を部分に分解できます。ウェイトが小さくても他との共分散が高い資産は、ウェイトから想像するよりずっと大きく寄与しえますし、ヘッジは負に寄与することもあります。
# Risk contributions of a three-asset portfolio: they add up to the volatility
import numpy as np
weights = np.array([0.5, 0.3, 0.2])
cov = np.array([[0.0400, 0.0060, 0.0100],
[0.0060, 0.0100, 0.0020],
[0.0100, 0.0020, 0.0225]])
variance = weights @ cov @ weights
contributions = weights * (cov @ weights) / np.sqrt(variance)
print(np.round(contributions, 4), round(float(contributions.sum()), 4))
print(round(float(np.sqrt(variance)), 4))式よりも入力が重要式は正確ですが、
mu と cov は推定値で、二つのうち分散のほうが信頼できます。期待リターンは非常にノイズが多く、共分散はずっと少ないからです。また、ウェイト・mu・cov は同じ期間でなければなりません。日次の共分散に年率のリターンを組み合わせるのはよくある誤りです。分散は期間数倍、ボラティリティはその平方根倍にスケールします。- ポートフォリオのリターンは線形で
w @ mu。分散は2次形式w @ cov @ wで、n * n個の項と交差項があり、相関が1未満ならリスクが下がる - ボラティリティは
sqrt(variance * periods)。年率化はcovの期間と合わせる - リスク寄与
w_i * (cov @ w)_i / sigma_pはボラティリティを資産別にちょうど分解する。ヘッジは負の寄与になりうる
次は最小分散ポートフォリオです。このリスクをできるだけ小さくするウェイトを選びます。
ラボ:採点される内容
portfolio_returnで期待リターンを合計する25点portfolio_varianceでリスクを測る25点portfolio_volでボラティリティを示す25点risk_contributionsでリスクを資産別に分ける25点