ポートフォリオ最適化(2021年秋 Lab1)#
はじめに:ポートフォリオ最適化とは?#
ポートフォリオの最適化は、投資から得られるリターンを最大化したいと考える人にとって大変重要なプロセスです。 投資は通常、いわゆる資産(株式、債権、債券、デリバティブ、コール、プットなど)の集まりであり、この資産の集まりをポートフォリオと呼びます。
ポートフォリオの最適化のゴールは、リスク(金銭的損失)を最小化し、リターン(金銭的利益)を最大化することです。しかし、このプロセスはそう単純ではありません。リスクとリターンは通常トレードオフの関係にあり、これがポートフォリオの最適化を少し複雑にしています。ハリー・マーコウィッツ博士が1952年に発表した『現代ポートフォリオ理論』では、「リスクは、より高い報酬を得るための本質的な要素である」と述べています。
Note
現代ポートフォリオ理論
投資家は同じリターンが期待できる2つのポートフォリオを与えられたとき、リスクの少ない方を好むというリスク回避の考え方に基づく投資理論。投資家は、与えられた市場リスクに基づいて、期待リターンを最大化するようにポートフォリオを構築することができ、リスクはより高い報酬の本質的な部分であることを強調している。現代ポートフォリオ理論は、金融・投資に関する最も重要かつ影響力のある経済理論の一つとして、1952年にハリー・マーコウィッツ博士が提唱し、この功績によりマーコウィッツ博士は1990年にノーベル経済学賞を受賞した。
参照: 現代ポートフォリオ理論
Challenge#
Goal
ポートフォリオの最適化は、投資から得られるリターンを最大化したいと考える人にとって大変重要なプロセスです。この最初のチャレンジでは、ポートフォリオ最適化の基本的な理論と、量子コンピューターで解けるように問題を定式化する方法を学びます。その過程で、QiskitのFinanceアプリケーションクラスをつかって、問題を効率的に解決する方法を学びます。
Challenge 1a: QiskitのFinanceモジュールのPortfolioOptimization()メソッドを使って、ポートフォリオ最適化を二次プログラムに変換する方法を学びます。
Challenge 1b: Challenge 1aで作成したインスタンスに基づいて、4銘柄のポートフォリオ最適化問題をVQE (Variational Quantum Eigensolver:変分量子固有値ソルバー) をつかって解きます。
Challenge 1c: QAOA(Quantum Approximate Optimazation Algorithm:量子近似最適化アルゴリズム)を使って、ポートフォリオがとりうる4つのアセットから、予算=3かつ、ひとつの銘柄につきダブルウェイトまでを選択できる場合の問題を解きます。
事前学習としてQiskit Finance Demo Session with Julien Gaconの視聴と対応するdemo notebookをチェックして、QiskitのFinanceモジュールとポートフォリオ最適化への応用について学ぶことをお勧めします。
1. 効率的フロンティアを求めて#
現代ポートフォリオ理論(MPT)は、投資家にとって理想的なポートフォリオを決定するための理論的な枠組みを提供します。同理論は平均分散ポートフォリオ理論とも呼ばれ、投資家が以下のようなポートフォリオの集合から最適なポートフォリオを選択することを想定しています。
与えられたリスクに対して期待リターンを最大化する。
与えられたレベルの期待リターンに対して、リスクを最小化する。
下図は、横軸がリスク、縦軸が期待リターンを示す、現代ポートフォリオ理論の最小分散フロンティアです。
AとBの2つの銘柄があり、この2つの銘柄のどちらかに投資するという状況を考えてみましょう。あるいは、Aに10%、Bに90%、Aに20%、Bに80%、Aに70%、Bに30%などと投資することもできます。こうした2つの銘柄を考える場合の単純なケース下でもたくさんの投資パターンの組み合わせが考えられます。さらに何千もの銘柄を検討する場合には、膨大な数の組み合わせになります。
最小分散フロンティアは、ある想定される期待リターンに対して達成可能な最小分散を示します。あるポートフォリオの最小分散フロンティアを構築するには
過去のデータを用いて、ポートフォリオの各個別銘柄の平均、分散、および各組の銘柄の相関を推定する。
コンピュータプログラムを使って、事前に設定した期待リターンごとに、ポートフォリオの分散を最小化する全銘柄の重みを求める。
上記で決定した最小分散ポートフォリオすべてについて、期待リターンと分散を計算し、2つの変数をグラフ化する。
このとき、投資家は最小分散点以下のポートフォリオを保有したいとは思わないでしょう。投資家は最小分散フロンティアの正の方向に傾斜した部分に沿って、常に高いリターンを得ることができるため、最小分散フロンティアの正の傾斜部分は、効率的なフロンティアと呼ばれています。
最適なポートフォリオがどこにあるかを示す効率的フロンティアを求めることによって、投資家はよりリターンを期待できそうな様々なポートフォリオはどれかを絞り込むことができます。
2. 演習の目的#
この演習の目的は、量子的アプローチを用いて、ある特定のリスクに対する効率的フロンティアを見つけることです。QiskitのFinanceアプリケーションモジュールを使用して、ポートフォリオ最適化問題を二次計画問題に変換することで、VQEやQAOAなどの変分量子アルゴリズムを使用して最適化問題を解決していきます。それでは早速、今回のチャレンジ問題を見ていきましょう。
3. 四銘柄のポートフォリオ最適化問題#
ここで、4銘柄(e.g. STOCK0, STOCK1, STOCK2, STOCK3) のポートフォリオ最適化問題を考えてみましょう。目標は、リスクとリターン間のトレードオフを最小化する2つの資産の組み合わせを見つけることです。
4. 問題の定式化#
最適化問題については、検討している問題の定式化から行います。
効率的フロンティアを記述する関数は、以下のように線形制約を持つ二次計画問題に定式化することができます。
赤色で示されている用語はリスクに関連する項、青色で示されている項はリターンに関連するものです。
一般に、最適化したい関数は目的関数と呼ばれ、今回の目的は、このリスクとリターンのトレードオフを最小化することです。
\(x\) は資産配分を示す。
\(Σ\) (sigma) は、共分散行列です。 共分散行列は、2つの資産価格の値動きが互いにどのように相関しているかを統計的に示す指標で、金融工学で広く応用されています。共分散が高いということは、株価の値動きが激しく、ボラティリティーが高いことを意味します。そのため、この指数は、全体のリスクを減らすためにどのような資産をポートフォリオに含めるべきかを判断するのに役立ちます。
\(q\) iはリスクファクター(リスク許容度)と呼ばれ、個人のリスクを取る意思や能力を評価したものです。 例えば、自動化されたファイナンシャル・アドバイジング・サービス、いわゆるロボ・アドバイジングを利用する際には、通常、異なるリスク許容度が表示されます。このq値はそのようなものと同じで、0から1の間の値をとります。
\(𝝁\) (mu) は期待リターンで、当然ながら最大化を目指します。
\(n\) は選択可能なアセットの数です。
\(B\) はBudget(予算)の略ですが、ここでいう「予算」とは、ポートフォリオに割り当てることのできる資産の数を意味します。
ゴール:#
ゴールはx値を見つけることです。ここでいうx値とは、どの資産を選ぶか(𝑥[𝑖]=1)、どの資産を選ばないか(𝑥[𝑖]=0)を示すものです。
仮定:#
この演習では、簡単のために以下を仮定しています。
すべての資産の価格は同じである(1に正規化)。
予算\(B\)をすべて使わなければならない、つまり、正確に\(B\)個の資産を選択しなければならない。
等式制約 \(1^n x = B\) はペナルティ項 \((1^n x - B)^2\) にマッピングされ、このペナルティ項はパラメータでスケーリングされ、目的関数から減算される。
Step 1. 必要なライブラリをインポートします。#
#Let us begin by importing necessary libraries.
from qiskit import Aer
from qiskit.algorithms import VQE, QAOA, NumPyMinimumEigensolver
from qiskit.algorithms.optimizers import *
from qiskit.circuit.library import TwoLocal
from qiskit.utils import QuantumInstance
from qiskit.utils import algorithm_globals
from qiskit_finance import QiskitFinanceError
from qiskit_finance.applications.optimization import PortfolioOptimization
from qiskit_finance.data_providers import *
from qiskit_optimization.algorithms import MinimumEigenOptimizer
from qiskit_optimization.applications import OptimizationApplication
from qiskit_optimization.converters import QuadraticProgramToQubo
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import datetime
import warnings
from sympy.utilities.exceptions import SymPyDeprecationWarning
warnings.simplefilter("ignore", SymPyDeprecationWarning)
Step 2. 時系列データ(金融データ)の生成#
まず、全銘柄数n=4のランダムな時系列金融データを生成してみましょう。これにはRandomDataProviderを使います。ここではある4銘柄について、過去にさかのぼって、1955年11月5日から1985年10月26日までの金融データを取得しています。
# Set parameters for assets and risk factor
num_assets = 4 # set number of assets to 4
q = 0.5 # set risk factor to 0.5
budget = 2 # set budget as defined in the problem
seed = 132 #set random seed
# Generate time series data
stocks = [("STOCK%s" % i) for i in range(num_assets)]
data = RandomDataProvider(tickers=stocks,
start=datetime.datetime(1955,11,5),
end=datetime.datetime(1985,10,26),
seed=seed)
data.run()
# Let's plot our finanical data
for (cnt, s) in enumerate(data._tickers):
plt.plot(data._data[cnt], label=s)
plt.legend()
plt.xticks(rotation=90)
plt.xlabel('days')
plt.ylabel('stock value')
plt.show()
Step 3. 期待リターンと共分散行列の取得#
まず、期待リターンと共分散行列を計算しましょう。
期待リターン μ#
ポートフォリオの期待リターンとは、ポートフォリオが生み出す可能性のあるリターンの予想値であり、ポートフォリオの可能なリターン分布の平均(平均値)となります。
例えば、銘柄A、B、Cがそれぞれ50%、20%、30%の割合でポートフォリオに組み込まれていたとします。 各銘柄の期待リターンがそれぞれ15%、6%、9%だった場合、ポートフォリオの期待リターンの計算式は以下のようになります。
QiskitのRandomDataProviderが提供する以下のget_period_return_mean_vector()
メソッドを使用することで、先ほど生成した時系列データについて、期待リターンを計算することができます。
#Let's calculate the expected return for our problem data
mu = data.get_period_return_mean_vector() # Returns a vector containing the mean value of each asset's expected return.
print(mu)
共分散行列 Σ#
共分散Σは、2つの資産の平均リターンが互いにどのように変化するかを示す統計的な尺度で、投資ポートフォリオの観点からリスクの大きさを理解し、株式の売買を決定するのに役立ちます。
自分のポートフォリオにn個の銘柄がある場合、共分散行列の大きさはn×nとなります。 今回の4銘柄のポートフォリオの共分散行列をプロットすると、4×4の行列になります。
# Let's plot our covariance matrix Σ(sigma)
sigma = data.get_period_return_covariance_matrix() #Returns the covariance matrix of the four assets
print(sigma)
fig, ax = plt.subplots(1,1)
im = plt.imshow(sigma, extent=[-1,1,-1,1])
x_label_list = ['stock3', 'stock2', 'stock1', 'stock0']
y_label_list = ['stock3', 'stock2', 'stock1', 'stock0']
ax.set_xticks([-0.75,-0.25,0.25,0.75])
ax.set_yticks([0.75,0.25,-0.25,-0.75])
ax.set_xticklabels(x_label_list)
ax.set_yticklabels(y_label_list)
plt.colorbar()
plt.clim(-0.000002, 0.00001)
plt.show()
左から右への対角成分(下図の黄色で示された値)は、ある銘柄の「自身」との関係を示しています。また、非対角線上の値は、各銘柄の平均期待収益率の互いの偏差を示しています。 共分散行列の簡単な見方は次の通りです。
2つの銘柄が同時に増加・減少すれば、共分散の値は正の値になります。
一方が上昇し、他方が下降した場合、共分散の値は負になります。
“Don’t Put All Your Eggs in One Basket (卵は一つのカゴに盛るな)”という言葉を聞いたことがあるかもしれません。常に同じ方向に動くものに投資していると、同時にすべての資金を失うリスクがあります。共分散行列は、そのようなリスクを減らすために、投資家が資産を分散させるのに役立つ指標です。
これで、最適化のためのポートフォリオを構築するために必要なすべての値が揃ったので、ポートフォリオを二次計画問題に定式化し、最適化問題に落とし込んでくれるのを手助けしてくれるQiskit Financeのアプリケーションクラスをみていきましょう。
Qiskit Finance のポートフォリオ最適化クラス#
ステップ2からステップ4までのなかで計算したポートフォリオを特徴づける値を入力としえ、PortfolioOptimization(ポートフォリオ最適化クラス)
をつかってポートフォリオ・インスタンスをつくります。
PortfolioOptimization クラスは以下 5つの引数 をとり、そのインスタンスを二次計画問題に変換する準備を行います。
expected_returns
covariances
risk_factor
budget
bounds
ポートフォリオのインスタンスが二次計画問題に変換されれば、変分量子固有値ソルバー(VQE)や量子近似最適化アルゴリズム(QAOA)などの量子変分法を用いて、問題の最適解を求めることができます。
ポートフォリオの資産選択の変数がバイナリ変数の場合、「bounds = None」と設定してください。
すでにステップ3で期待リターンと共分散を得ており、リスクファクターとバジェットも事前に定義されています。それでは、 PortfolioOptimization
クラスを使って、ポートフォリオを構築してみましょう。
Challenge 1a#
PortfolioOptimizationクラスを使用したポートフォリオインスタンスの作成
PortfolioOptimization クラスを使って、ポートフォリオのインスタンスを生成するコードを完成させてください。5つの引数に前ステップで取得した値を代入し、インスタンスを二次計画問題 qp に変換してください。
##############################
# 以下にコードを入力
portfolio =
qp =
##############################
print(qp)
##############################
# 以下にコードを入力
portfolio =
qp =
##############################
print(qp)
If you were able to successfully generate the code, you should see a standard representation of the formulation of our qudratic program.
Minimum Eigen Optimizer(最小固有値オプティマイザー)#
興味深いことに、このポートフォリオ最適化問題は、ハミルトニアンの基底状態を求める問題として解くことができます。ハミルトニアンとは、シミュレーションしたい物理系の全エネルギーを表すエネルギー関数と考えることができます。この物理系は、さらに イジングモデル と呼ばれる数学モデルで表現することができます。この数学モデルは、バイナリ変数をスピンアップ(+1)またはスピンダウン(-1)と呼ばれる状態に変換するためのフレームワークを提供します。
最適化アルゴリズムを適用する際には、通常、適性なフォーマットに変換して適用可能な状態にする必要があります。今回適用するVQEやQAOAのような変分量子アルゴリズムは二次非制約二次最適化(QUBO)問題に適用するため, Qiskitは自動的に適切なフォーマットにマッピングするコンバータを提供します。
QUBOを解くことは、ハミルトニアンの基底状態を求めることに相当します。Minimum Eigen Optimizer(最小固有値オプティマイザー)は、二次プログラムをハミルトニアンに変換し、VQEやQAOAなどの所定の最小固有値ソルバーを呼び出して基底状態を計算し、最適化の結果を返します。
このアプローチにより、最適化問題を解く際に基底状態の計算を利用することができます。次のステップの課題でこの手続きを実装してみましょう。
Step 5. 古典的なオプティマイザーで参考値を取得#
参考値として、今回の最適化問題解の理論値をさNumPyMinimumEigensolverを使ってまずは取得します。問題は「ising」に設定しています。量子計算ではなく古典的に計算されるので、バックエンドは必要ありません。結果はdictionary型として返されます。
exact_mes = NumPyMinimumEigensolver()
exact_eigensolver = MinimumEigenOptimizer(exact_mes)
result = exact_eigensolver.solve(qp)
print(result)
Caution
ここで表示されるOptimal Valueとは、どの銘柄が選択されたかを示しています。例えばOptimal Value [1. 1. 0. 0.] は STOCK2とSTOCK3が選択されたポートフォリオを意味します。
Challenge 1b#
**Variational Quantum Eigensolver (VQE)**は、古典と量子のハイブリッドアルゴリズムであり、 Hamiltonianの基底エネルギー(最も低いエネルギー状態)を効率的に計算するために、処理負荷の一部を古典計算機に託します。 先ほど説明したように、二次プログラムをVQE で解く基底状態エネルギーの探索問題として再構築することができます。この課題では、VQEを用いて最適解を求めます。
VQEをつかったソリューション
Variational Quantum Eigensolver(VQE)を使って同じ最適解を求めます。以下に使用するオプティマイザー(optimizer)と変分形式を指定します。
optimizer = SLSQP(maxiter=1000)
algorithm_globals.random_seed = 1234
backend = Aer.get_backend('statevector_simulator')
##############################
# Provide your code here
vqe =
##############################
vqe_meo = MinimumEigenOptimizer(vqe) #please do not change this code
result = vqe_meo.solve(qp) #please do not change this code
print(result) #please do not change this code
Hint
行き詰まったら、このqiskitチュートリアルを参考に問題設定に応じて適宜調整してください。
https://qiskit.org/documentation/finance/tutorials/01_portfolio_optimization.html
optimizer = SLSQP(maxiter=1000)
algorithm_globals.random_seed = 1234
backend = Aer.get_backend('statevector_simulator')
##############################
# Provide your code here
vqe =
##############################
vqe_meo = MinimumEigenOptimizer(vqe) #please do not change this code
result = vqe_meo.solve(qp) #please do not change this code
print(result) #please do not change this code
古典のオプティマイザーから得られた基準解と同じ最適解がVQEでも求まるはずです。
Challenge 1c#
このチャレンジ演習では、同じ問題を、今度はB=3で、1つの銘柄を2つ保有できる場合を考えていきます。(例えば、STOCK3を2つ保有、STOCK2を1つ保有した場合のポートフォリオは[2, 1, 0, 0]となります。また、STOCK0、STOCK1、STOCK02をそれぞれ、1株ずつ保有した場合、ポートフォリオは[0, 1, 1, 1]となります。)
この新しい制約条件を用いて、リスクとリターンのトレードオフを最小化する最適なポートフォリオを求めてください。
B=3, n=4 銘柄のポートフォリオ最適化問題
PortfolioOptimization クラスを使用して、ポートフォリオのインスタンスを生成するコードを完成させます。
予算=3の場合、1つの資産に2倍のウェイトを割り当てることができる最適なポートフォリオを見つけてください。
最後にQAOAを使って最適解を見つけ、答えを提出してください。
# Step 4. Set parameters and constraints based on this challenge 1c
##############################
# Provide your code here
q2 = #Set risk factor to 0.5
budget2 = #Set budget to 3
##############################
# Step 5. Complete code to generate the portfolio instance
##############################
# Provide your code here
portfolio2 =
qp2 =
##############################
# Step 6. Now let's use QAOA to solve this problem.
optimizer = SLSQP(maxiter=1000)
algorithm_globals.random_seed = 1234
backend = Aer.get_backend('statevector_simulator')
##############################
# Provide your code here
qaoa =
##############################
qaoa_meo = MinimumEigenOptimizer(qaoa) #please do not change this code
result2 = qaoa_meo.solve(qp2) #please do not change this code
print(result2) #please do not change this code
Hint
STOCK0, STOCK1, STOCK2, STOCK3のどれでも、ポートフォリオの中で2倍のウェイトを持つことができるケースです。整数変数に対応するためには、どのようにコードを変更すればよいでしょうか。
Step 1: 必要なライブラリをインポートします。#
#Step 1: Let us begin by importing necessary libraries
import qiskit
from qiskit import Aer
from qiskit.algorithms import VQE, QAOA, NumPyMinimumEigensolver
from qiskit.algorithms.optimizers import *
from qiskit.circuit.library import TwoLocal
from qiskit.utils import QuantumInstance
from qiskit.utils import algorithm_globals
from qiskit_finance import QiskitFinanceError
from qiskit_finance.applications.optimization import *
from qiskit_finance.data_providers import *
from qiskit_optimization.algorithms import MinimumEigenOptimizer
from qiskit_optimization.applications import OptimizationApplication
from qiskit_optimization.converters import QuadraticProgramToQubo
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import datetime
import warnings
from sympy.utilities.exceptions import SymPyDeprecationWarning
warnings.simplefilter("ignore",SymPyDeprecationWarning)
以下にとりかかりのためのコードを提供します。######で区切られた箇所にご自身のコードを入力ください。
Step 2: 時系列データ(金融データ)の生成#
# Step 2. Generate time series data for four assets.
# Do not change start/end dates specified to generate problem data.
seed = 132
num_assets = 4
stocks = [("STOCK%s" % i) for i in range(num_assets)]
data = RandomDataProvider(tickers=stocks,
start=datetime.datetime(1955,11,5),
end=datetime.datetime(1985,10,26),
seed=seed)
data.run()
# Let's plot our finanical data (We are generating the same time series data as in the previous example.)
for (cnt, s) in enumerate(data._tickers):
plt.plot(data._data[cnt], label=s)
plt.legend()
plt.xticks(rotation=90)
plt.xlabel('days')
plt.ylabel('stock value')
plt.show()
Step 3: 期待リターンと共分散行列の取得#
# Step 3. Calculate mu and sigma for this problem
mu2 = data.get_period_return_mean_vector() #Returns a vector containing the mean value of each asset.
sigma2 = data.get_period_return_covariance_matrix() #Returns the covariance matrix associated with the assets.
print(mu2, sigma2)
Step 4: チャレンジ1cの問題設定に基づく変数設定を行ってください。#
# Step 4. Set parameters and constraints based on this challenge 1c
##############################
# Provide your code here
q2 = #Set risk factor to 0.5
budget2 = #Set budget to 3
##############################
Step 5: ポートフォリオ・インスタンスを生成するコードを完成させてください。#
# Step 5. Complete code to generate the portfolio instance
##############################
# Provide your code here
portfolio2 =
qp2 =
##############################
Step 6: QAOAをつかったソリューション#
Quantum Approximate Optimization Algorithm(QAOA) は、もう一つの変分量子アルゴリズムで、小中規模のノイズ有の量子デバイス上での組合せ最適化問題を解くのに応用されています。このアルゴリズムはハミルトニアンの基底状態を求めるのにも使われており、QiskitのQAOA アプリケーションをつかって簡単に実装することができます。(QAOAについては第4回の課題でより詳しい解説が予定されています。この演習ではまず、Qiskitを使ったQAOAの基本的な実装に焦点を当てています)。
# Step 6. Now let's use QAOA to solve this problem.
optimizer = SLSQP(maxiter=1000)
algorithm_globals.random_seed = 1234
backend = Aer.get_backend('statevector_simulator')
##############################
# Provide your code here
qaoa =
##############################
qaoa_meo = MinimumEigenOptimizer(qaoa) #please do not change this code
result2 = qaoa_meo.solve(qp2) #please do not change this code
print(result2) #please do not change this code
注:QAOAの実行には最大で数分かかることがあります。
更に学びたい方へ:#
入門レベルの最初のチャレンジを無事に解いた皆さん、おめでとうございます!
ポートフォリオ最適化について、またQiskitのFinanceモジュールを使った演習を解く方法について学ぶことができたのではないでしょうか。
今回登場した変分量子アルゴリズムをつかった最適化問題について更に深く学びたい方は以下の文献をご覧ください。
Additional information#
Created by: Yuri Kobayashi
Version: 1.0.0