Otama's Playground

AIで遊んだ結果などをつらつら載せていきます。

Pythonで解くモダンポートフォリオ理論:平均分散最適化と効率的フロンティアの計算法

前回はモンテカルロ法で簡易的に効率的フロンティアを求めてみましたが、この方法は効率的でないので最適化問題として計算する方法を紹介します。平均分散最適化の簡単な説明については、以下の記事に記載しているので、平均分散最適化って何っていう状態の方は下の記事を読んでいただけると良いかと思います。

otama-playground.com

マーコビッツの平均分散最適化問題

計算方法

Markowitzの平均分散モデルの中でも、ポートフォリオのリスク(分散)を最小化しつつ、期待リターンが目標値を達成するための最適化問題を解いてみます。具体的には以下の方法で計算します。

目的関数

 
\text{Minimize} \quad \frac{1}{2} w^T \Sigma w


ここで
-  wは資産のウェイトのベクトル  
-  \Sigmaは資産の共分散行列  

制約条件

制約1: 期待リターンが目標値  \mu_p に等しいこと

 
w^T \mu = \mu_p


ここで
-  \mu は資産の期待リターンのベクトル

制約2: 資産のウェイトの総和が1であること

 
\sum w_i = 1

制約3: ウェイトが0以上であること(ショートしない)

 
w_i \geq 0 \quad \forall i

実際にpythonで計算してみる

コード内の目標とするポートフォリオリターンを自分の目標リターンに書き換えて実行してください。

import yfinance as yf
import pandas as pd
import numpy as np
import cvxpy as cp

# ETFのシンボル
tickers = ['VTI', 'VEA', 'VWO', 'BND', 'HYG', 'EMB', 'IYR', 'GLDM']

# データを取得
data = yf.download(tickers, start="2010-01-01", end="2023-01-01")['Adj Close']

# 年次リターンを計算
annual_data = data.resample('Y').last()  # 年次のデータに変換
returns = annual_data.pct_change().dropna()

# 平均リターンと共分散行列を計算
mu = returns.mean().values
Sigma = returns.cov().values

# 目標とするポートフォリオリターン(データに基づいて適切な値を設定)
mu_p = mu.mean()  # 平均リターンに近い値を目標リターンとする

print("Mean returns:", mu)
print("Covariance matrix:\n", Sigma)
print("Target return (mu_p):", mu_p)

# 変数定義
w = cp.Variable(len(tickers))

# 目的関数:リスク(分散)の最小化
objective = cp.Minimize(cp.quad_form(w, Sigma))

# 制約条件
constraints = [
    cp.sum(w) == 1,
    w @ mu == mu_p,
    w >= 0  # ショートセール禁止
]

# 問題設定
problem = cp.Problem(objective, constraints)

# 最適化実行
result = problem.solve()

# 結果の確認
if w.value is None:
    print("Optimization failed. Check the constraints and objective function.")
else:
    optimal_weights = w.value
    optimal_weights_percentage = optimal_weights * 100  # パーセンテージに変換

    print("Optimal weights (in %):")
    for ticker, weight in zip(tickers, optimal_weights_percentage):
        print(f"{ticker}: {weight:.2f}%")
    
    print("Expected portfolio return:", np.dot(optimal_weights, mu))
    print("Portfolio variance:", np.dot(optimal_weights.T, np.dot(Sigma, optimal_weights)))

効率的フロンティアを最適化問題を使って計算してみる

上と同様に最適化問題として解けば、効率的フロンティアも(モンテカルロ法を使わずとも)効率よく求めることができます。

計算方法

効率的フロンティアは各リスクレベルにおいて最大のリターンをたたき出すポートフォリオのことなので、これを定式化します。

目的関数

 
\text{Maximize} \quad w^{T}\mu

制約条件

 
\frac{1}{2} w^T \Sigma w \leq \text{target_variance}

 
\sum w_i = 1

 
w_i \geq 0

実際にpythonで計算する

月次のデータで計算したい場合は年次のデータに変換になってる行のYMに変えてください。

import yfinance as yf
import pandas as pd
import numpy as np
import cvxpy as cp
import matplotlib.pyplot as plt

# ETFのシンボル
tickers = ['VTI', 'VEA', 'VWO', 'BND', 'HYG', 'EMB', 'IYR', 'GLDM']

# データを取得
data = yf.download(tickers, start="2010-01-01", end="2023-01-01")['Adj Close']

# 年次リターンを計算
annual_data = data.resample('Y').last()  # 年次のデータに変換
returns = annual_data.pct_change().dropna()

# 平均リターンと共分散行列を計算
mu = returns.mean().values
Sigma = returns.cov().values

# 効率的フロンティアを計算するためのリスクレベルを設定
num_portfolios = 100
target_variances = np.linspace(0, np.max(np.diag(Sigma)), num_portfolios)

# 効率的フロンティアを求める
risks = []
returns_list = []

for target_variance in target_variances:
    w = cp.Variable(len(tickers))
    
    # 目的関数:リターンの最大化
    objective = cp.Maximize(w @ mu)
    
    # 制約条件
    constraints = [
        cp.quad_form(w, Sigma) <= target_variance,
        cp.sum(w) == 1,
        w >= 0  # ショートセール禁止
    ]
    
    # 問題設定
    problem = cp.Problem(objective, constraints)
    
    # 最適化実行
    problem.solve()
    
    if w.value is not None:
        risk = np.sqrt(w.value.T @ Sigma @ w.value)
        ret = w.value @ mu
        risks.append(risk)
        returns_list.append(ret)

# グラフにプロット
plt.figure(figsize=(10, 6))
plt.plot(risks, returns_list, label='Efficient Frontier')
plt.xlabel('Risk (Standard Deviation)')
plt.ylabel('Return')
plt.title('Efficient Frontier')
plt.legend()
plt.grid(True)
plt.xlim(0, max(risks) * 1.1)  # x軸の範囲を設定
plt.ylim(0, max(returns_list) * 1.1)  # y軸の範囲を設定
plt.savefig('graph.png')
plt.show()

効率的フロンティアの計算結果

最後に

今回は、平均分散最適化と効率的フロンティアの計算方法について、Pythonを使って解説しました。この手法はモダンポートフォリオ理論の基盤となるもので、理解することで投資判断の精度が向上するでしょう。私も学習中の身ですので、自分の学びが皆さんの学びにも役立てば幸いです。一緒に頑張って勉強していきましょう。

ポートフォリオ構築に関連する他のモデルを知りたい方は下記のリンク集をぜひご活用ください。

otama-playground.com