研究・リサーチ

Rで効率的フロンティアを計算!eMAXIS Slimの実現可能領域をグラフ化

最近は, 自分の復習と今後の分析の準備のためファイナンスの基本的な分析ツールを整理しています.

リスク・リターン平面上のあらゆる資産の組み合わせ, いわゆる実現可能領域をどう算出するべきか調べていたところ, ランダムなウェイトをもつポートフォリオを大量計算する方法で対応することができました.

せっかくなのでバランスファンドの最適なウェイトについても試算してみたいと思います.

スポンサーリンク

実現可能領域とは

n個の資産が存在する場合に, ウェイトの合計が1となるあらゆる組み合わせによって得られるリスク・リターン平面上の点の集合のことを実現可能領域といいます.

リスク・リターンの観点から効率的フロンティア以外の点を選ぶ理由はない, とさらっと流されることが多いですが, その内側もきちんと概念として存在しています.

この実現可能領域を図示するかしないかで, 図表が一本の弧になるか, 多数の点が表示された図表になるかが変わるため, それっぽさが全然違ったりします.

スポンサーリンク

データ

分析対象は, 三菱UFJ国際投信が運用する4本のインデックスファンドとしました.

  • eMAXIS Slim 国内債券インデックス
  • eMAXIS Slim 国内株式(TOPIX)
  • eMAXIS Slim 先進国債券インデックス
  • eMAXIS Slim 先進国株式インデックス

2018年1月から2020年12月の3年間の月次の基準価額を利用します. 期待リターンは過去3年間の平均リターンとし, 分散共分散行列は36ヶ月の月次リターンから推定しました. ポートフォリオのウェイトについては, 空売りなしとしています.

スポンサーリンク

結果

それでは結果を見ていきます. ここでの結果は, 大量計算したポートフォリオの中から条件に合ったものを選んでおり, 最適化の結果とは異なることに注意が必要です.

まずは, 実現可能領域において最もリスクが低い最小分散ポートフォリオを実現するウェイトです.

国内債券が68%, 外国債券が31%, 国内株式が1%, 外国株式が0%となりました. ポートフォリオの99%が債券となりましたが, 株式と債券のリスクを比較すると直感的な結果です. 必ずしも国内債券だけではない点や国内株式が少しだけ入ってくるのは面白いですね.

続いては, 実現可能領域において最もリスク・リターン効率が良い接点ポートフォリオを実現するウェイトです.

国内債券が48%, 外国債券が45%, 外国株式が7%, 国内株式が0%となりました. 最小分散ポートフォリオよりは株式のウェイトが増えましたが, 引き続き, ポートフォリオにおける債券のウェイトは90%以上です.

最後に, 5,000個のポートフォリオをリスク・リターン平面にプロットし, 4資産の実現可能領域を図示します.

良い感じです. 赤い点が最小分散ポーフォリオと接点ポートフォリオですが, かなり左端に寄っています. あるリスク水準において最も期待リターンが高い点をつないだものが, いわゆる効率的フロンティアになります.

スポンサーリンク

まとめ

この記事では, 伝統4資産のインデックスファンドの基準価額を用いて, 実現可能領域をグラフ化してみました.

伝統4資産だと, やはり債券のリスク・リターン効率は高いようですね. その点では, 債券にレバレッジを掛けて保有するというのも合理的なのかもしれません.

ただし, 債券の過去リターンをそのまま期待リターンにすることにも問題はあります. 過去の高いリターンは利回りの低下を反映していますので, 期待リターンはむしろ下がっていると考えるのが自然ですよね.

今回はありふれた計算でしたが, 分析対象を変えて色々と試してみると面白い投資アイディアが浮かぶかもしれません. Rのコードについては, 以下にまとめています.

スポンサーリンク

Rのコード

まずは, 基準価額のデータを読み込みます.

   DATA_DATE DOMESTIC_BOND DOMESTIC_EQUITY FOREIGN_BOND FOREIGN_EQUITY
1     201712         10049           11949        10791          11625
2     201801         10031           12074        10524          11755
3     201802         10068           11626        10252          11224
4     201803         10083           11387        10320          10748
5     201804         10074           11792        10444          11229

続いて, 基準価額のデータを対数リターンに変換します.

fund_data[,2:5] <- apply(fund_data[,2:5], 2, log)
fund_data <- apply(fund_data[,2:5], 2, diff) %>% data.frame

   DOMESTIC_BOND DOMESTIC_EQUITY  FOREIGN_BOND FOREIGN_EQUITY
1  -1.792829e-03    0.0104067875 -0.0250540902    0.011120731
2   3.681779e-03   -0.0378104111 -0.0261855547   -0.046224339
3   1.488760e-03   -0.0207716155  0.0066109516   -0.043334652
4  -8.929901e-04    0.0349489816  0.0119438908    0.043780027
5   2.082404e-03   -0.0165024479 -0.0262904990    0.004886076

期待リターンと,

mean_ret <- colMeans(fund_data)
print(round(mean_ret, 5))

DOMESTIC_BOND DOMESTIC_EQUITY    FOREIGN_BOND  FOREIGN_EQUITY 
      0.00037         0.00166         0.00170         0.00621 

分散共分散行列です.

cov_mat <- cov(fund_data) * 12
print(round(cov_mat,4))

                DOMESTIC_BOND DOMESTIC_EQUITY FOREIGN_BOND FOREIGN_EQUITY
DOMESTIC_BOND          0.0004         -0.0011       0.0000        -0.0003
DOMESTIC_EQUITY       -0.0011          0.0300       0.0021         0.0298
FOREIGN_BOND           0.0000          0.0021       0.0019         0.0019
FOREIGN_EQUITY        -0.0003          0.0298       0.0019         0.0401

4資産の組み合わせから成るポートフォリオのウェイト, 期待リターン, リスク, シャープレシオについて, それぞれ枠を5,000個分用意しておきます.

num_port <- 5000

all_wts <- matrix(nrow = num_port, ncol = 4)

port_returns <- vector('numeric', length = num_port)

port_risk <- vector('numeric', length = num_port)

sharpe_ratio <- vector('numeric', length = num_port)

4資産のウェイトの合計が1となるようにランダムにウェイトを与え, ポートフォリオの期待リターン, リスク, シャープレシオを計算する作業を5,000回繰り返します.

for (i in seq_along(port_returns)) {
  
  wts <- runif(4)
  wts <- wts/sum(wts)
  
  all_wts[i,] <- wts
  
  port_ret <- sum(wts * mean_ret)
  port_ret <- ((port_ret + 1)^12) - 1
  
  port_returns[i] <- port_ret
  
  port_sd <- sqrt(t(wts) %*% (cov_mat  %*% wts))
  port_risk[i] <- port_sd
  
  sr <- port_ret/port_sd
  sharpe_ratio[i] <- sr
  
}

4資産のウェイト, ポートフォリオのリターン, リスク, シャープレシオの情報を結合します.

portfolio_values <- tibble(DOMESTIC_BOND = all_wts[,1],
				   DOMESTIC_EQUITY = all_wts[,2],
				   FOREIGN_BOND = all_wts[,3],
				   FOREIGN_EQUITY = all_wts[,4],
				   Return = port_returns,
             		           Risk = port_risk,
            	                   SharpeRatio = sharpe_ratio)

A tibble: 6 x 7
  DOMESTIC_BOND DOMESTIC_EQUITY FOREIGN_BOND FOREIGN_EQUITY Return   Risk
          <dbl>           <dbl>        <dbl>          <dbl>  <dbl>  <dbl>
1        0.0394        0.0136          0.720         0.227  0.0325 0.0623
2        0.132         0.327           0.254         0.287  0.0342 0.113 
3        0.0899        0.336           0.263         0.312  0.0362 0.119 
4        0.106         0.404           0.419         0.0711 0.0226 0.0887
5        0.236         0.237           0.233         0.294  0.0329 0.0987

最小分散ポートフォリオのウェイトとグラフです.

min_var <- portfolio_values[which.min(portfolio_values$Risk),]

p <- min_var %>%
  gather(DOMESTIC_BOND:FOREIGN_EQUITY, key = Asset,
         value = Weights) %>%
  mutate(Asset = as.factor(Asset)) %>%
  ggplot(aes(x = fct_reorder(Asset,Weights), y = Weights, fill = Asset)) +
  geom_bar(stat = 'identity') +
  theme_minimal() +
  labs(x = 'Assets', y = 'Weights', title = "Minimum Variance Portfolio Weights") +
  scale_y_continuous(labels = scales::percent) 

ggplotly(p)

接点ポートフォリオのウェイトとグラフです.

max_sr <- portfolio_values[which.max(portfolio_values$SharpeRatio),]

p <- max_sr %>%
  gather(DOMESTIC_BOND:FOREIGN_EQUITY, key = Asset,
         value = Weights) %>%
  mutate(Asset = as.factor(Asset)) %>%
  ggplot(aes(x = fct_reorder(Asset,Weights), y = Weights, fill = Asset)) +
  geom_bar(stat = 'identity') +
  theme_minimal() +
  labs(x = 'Assets', y = 'Weights', title = "Tangency Portfolio Weights") +
  scale_y_continuous(labels = scales::percent) 

ggplotly(p)

実現可能領域のグラフです.

p <- portfolio_values %>%
  ggplot(aes(x = Risk, y = Return, color = SharpeRatio)) +
  geom_point() +
  theme_classic() +
  scale_y_continuous(labels = scales::percent) +
  scale_x_continuous(labels = scales::percent) +
  labs(x = 'Annualized Risk',
       y = 'Annualized Returns',
       title = "Portfolio Optimization &amp; Efficient Frontier") +
  geom_point(aes(x = Risk,
                 y = Return), data = min_var, color = 'red') +
  geom_point(aes(x = Risk,
                 y = Return), data = max_sr, color = 'red')  

ggplotly(p)
応援クリックお願いします!

Betmob|投資家ブログまとめメディア


研究・リサーチ
スポンサーリンク
インデックス投資家のアタマノナカ

コメント