Python と PyPortfolioOpt によるポートフォリオの最適化

マーコウィッツのポートフォリオ理論

マーコウィッツ・ポートフォリオ理論(以下、PTM)(現代ポートフォリオ理論)は、ハリー・マーコウィッツによって開発された、必要なリターン/リスク比に基づいた最適な資産選択を目的とした投資ポートフォリオの形成方法論です。彼が 1950 年代に策定したアイデアは、現代ポートフォリオ理論の基礎を形成しています。





ポートフォリオ理論の主要な規定は、ギャリー マーコウィッツが 1950 年から 1951 年に博士論文を準備していたときに策定されました。





マーコウィッツのポートフォリオ理論の誕生は、1952年にファイナンシャル・ジャーナルに掲載された記事「ポートフォリオの選択」にあるとされています。その中で、彼は最初に最適なポートフォリオを形成するための数学的モデルを提案し、特定の条件下でポートフォリオを構築するための方法を示しました。マーコウィッツの主なメリットは、「収益性」と「リスク」の概念の確率的形式化を提案することでした。これにより、最適なポートフォリオを選択する問題を形式的な数学的言語に翻訳することができました。理論の作成の数年間、マーコウィッツは、線形および非線形最適化の創設者の 1 人であるジョージ・ダンツィグと共に RAND 社で働いており、彼自身がこれらの問題の解決に参加したことに注意してください。したがって、私自身の理論は、必要な形式化の後、示された方向にうまく適合します。





マーコウィッツは常に理論を改善しており、1959 年に最初の専用モノグラフ「ポートフォリオの選択: 効果的な投資の多様化」を発行しました。





モデルベース

1. ポートフォリオの期待リターン





ポートフォリオの期待収益は、ポートフォリオに含まれる各資産の期待収益に依存します。このアプローチでは、1 つの投資の損失が他の投資の収入によって相殺されるため、分散によってリスクを軽減すると同時に、投資家の収入を最大化することができます。





ポートフォリオの期待収益は、その構成証券の期待収益の合計であり、ポートフォリオにおけるそれらのシェアによって加重されます。





E (R_ {p}) = \ sum_ {i = 1} ^ nw_ {i} E (R_ {i})

2.ポートフォリオの分散





— , , . , , , , .





\ sigma_ {p} ^ {2} = \ sum_ {i} ^ {} \ omega_ {i} ^ {2} \ sigma_ {i} ^ {2} + \ sum_ {i} ^ {} \ sum_ {j \ neq i} ^ {} \ omega_ {i} ^ {} \ omega_ {j} ^ {} \ sigma_ {i} ^ {} \ sigma_ {j} ^ {} \ rho_ {ij}

3. (Sharpe Ratio)





\ フラク {R_ {p} - R_ {f}} {\ シグマ_ {p}}

4.  (The Efficient Frontier)





:





(. Efficient frontier) — , . , , , . 1952 .





«», ( ). , , . () , .





, , , ( ) . , .





Python





:





import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import pandas_datareader as web
from matplotlib.ticker import FuncFormatter
      
      



PyPortfolioOpt. , .





!pip install PyPortfolioOpt
      
      



:





from pypfopt.efficient_frontier import EfficientFrontier 
from pypfopt import risk_models 
from pypfopt import expected_returns
from pypfopt.cla import CLA
import pypfopt.plotting as pplt
from matplotlib.ticker import FuncFormatter
      
      







, . yahoo.





, — .





nullin_df = pd.DataFrame(df_stocks,columns=tickers)
print(nullin_df.isnull().sum())
      
      







. .





# 
mu = expected_returns.mean_historical_return(df_stocks) 
# 
Sigma = risk_models.sample_cov(df_stocks)
#  
ef = EfficientFrontier(mu, Sigma, weight_bounds=(0,1)) #weight bounds in negative allows shorting of stocks
sharpe_pfolio=ef.max_sharpe() #May use add objective to ensure minimum zero weighting to individual stocks
sharpe_pwt=ef.clean_weights()
print(sharpe_pwt)

OrderedDict([('AFLT.ME', 0.0), ('DSKY.ME', 0.22606), ('GMKN.ME', 0.48796), ('IRAO.ME', 0.0), ('LKOH.ME', 0.0), ('MTSS.ME', 0.02953), ('NKNC.ME', 0.25645), ('SBER.ME', 0.0)])
      
      



, weight_bounds=(0,1) weight_bounds=(-1,1), .





.





ef.portfolio_performance(verbose=True)

Expected annual return: 37.1%
Annual volatility: 20.7%
Sharpe Ratio: 1.70
(0.37123023494063007, 0.20717177784552962, 1.695357536597058)
      
      



, :





ef1 = EfficientFrontier(mu, Sigma, weight_bounds=(0,1)) 
minvol=ef1.min_volatility()
minvol_pwt=ef1.clean_weights()
print(minvol_pwt)

OrderedDict([('AFLT.ME', 0.02876), ('DSKY.ME', 0.24503), ('GMKN.ME', 0.10403), ('IRAO.ME', 0.0938), ('LKOH.ME', 0.01168), ('MTSS.ME', 0.41967), ('NKNC.ME', 0.09704), ('SBER.ME', 0.0)])

ef1.portfolio_performance(verbose=True, risk_free_rate = 0.27)

Expected annual return: 24.0%
Annual volatility: 16.9%
Sharpe Ratio: -0.18(0.239915644698749, 0.16885732511472468, -0.17816434839774456)
      
      







.





100 000 .





cl_obj = CLA(mu, Sigma)
ax = pplt.plot_efficient_frontier(cl_obj, showfig = False)
ax.xaxis.set_major_formatter(FuncFormatter(lambda x, _: '{:.0%}'.format(x)))
ax.yaxis.set_major_formatter(FuncFormatter(lambda y, _: '{:.0%}'.format(y)))
      
      



:





latest_prices = get_latest_prices(df_stocks)
allocation_minv, rem_minv = DiscreteAllocation(minvol_pwt, latest_prices, total_portfolio_value=100000).lp_portfolio() 
print(allocation_minv)
print("         - {:.2f} ".format(rem_minv))
print()

{'AFLT.ME': 41, 'DSKY.ME': 181, 'IRAO.ME': 1765, 'LKOH.ME': 1, 'MTSS.ME': 127, 'NKNC.ME': 107}
         - 6152.03 
      
      



:





latest_prices1 = get_latest_prices(df_stocks)
allocation_shp, rem_shp = DiscreteAllocation(sharpe_pwt, latest_prices1, total_portfolio_value=100000).lp_portfolio() 
print(allocation_shp)
print("          {:.2f} ".format(rem_shp))

{'DSKY.ME': 167, 'GMKN.ME': 2, 'MTSS.ME': 9, 'NKNC.ME': 283} 
          1319.05 
      
      



167 , 2 , 9 283 . 1319 .





, , .








All Articles