library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.4     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(quantmod)
## Loading required package: xts
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## 
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
## 
## 
## ######################### Warning from 'xts' package ##########################
## #                                                                             #
## # The dplyr lag() function breaks how base R's lag() function is supposed to  #
## # work, which breaks lag(my_xts). Calls to lag(my_xts) that you type or       #
## # source() into this session won't work correctly.                            #
## #                                                                             #
## # Use stats::lag() to make sure you're not using dplyr::lag(), or you can add #
## # conflictRules('dplyr', exclude = 'lag') to your .Rprofile to stop           #
## # dplyr from breaking base R's lag() function.                                #
## #                                                                             #
## # Code in packages is not affected. It's protected by R's namespace mechanism #
## # Set `options(xts.warn_dplyr_breaks_lag = FALSE)` to suppress this warning.  #
## #                                                                             #
## ###############################################################################
## 
## Attaching package: 'xts'
## 
## The following objects are masked from 'package:dplyr':
## 
##     first, last
## 
## Loading required package: TTR
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
library(PerformanceAnalytics)
## 
## Attaching package: 'PerformanceAnalytics'
## 
## The following object is masked from 'package:graphics':
## 
##     legend
library(xts)        
library(corpcor)
df <- read.csv("myetf4.csv")
head(df)
##        Index tw0050 tw0056 tw006205 tw00646
## 1 2015/12/14  53.29  18.25    31.06   19.61
## 2 2015/12/15  53.33  18.38    31.59   19.63
## 3 2015/12/16  54.14  18.56    31.60   19.89
## 4 2015/12/17  54.77  18.81    32.23   20.05
## 5 2015/12/18  54.50  18.95    32.18   19.85
## 6 2015/12/21  54.41  19.02    33.00   19.64
df$Index <- as.Date(df$Index)
df <- df %>% column_to_rownames("Index")
df_xts <- as.xts(df)
returns <- na.omit(Return.calculate(df_xts, method = "log"))
cov_matrix <- cov(returns)
print(cov_matrix)
##                tw0050       tw0056     tw006205      tw00646
## tw0050   7.893835e-05 4.604249e-05 4.513506e-05 3.696405e-05
## tw0056   4.604249e-05 4.562541e-05 2.695112e-05 2.374923e-05
## tw006205 4.513506e-05 2.695112e-05 1.310338e-04 2.938807e-05
## tw00646  3.696405e-05 2.374923e-05 2.938807e-05 5.914357e-05
ones <- rep(1, ncol(cov_matrix))
inv_cov_matrix <- pseudoinverse(cov_matrix)
gmvp_weights <- inv_cov_matrix %*% ones / sum(ones %*% inv_cov_matrix %*% ones)
gmvp_return <- sum(colMeans(returns) * gmvp_weights)
gmvp_std <- sqrt(t(gmvp_weights) %*% cov_matrix %*% gmvp_weights)
gmvp_weights
##            [,1]
## [1,] -0.2241314
## [2,]  0.7298726
## [3,]  0.1080760
## [4,]  0.3861827
gmvp_return
## [1] 0.0002263853
gmvp_std
##             [,1]
## [1,] 0.005921611
monthly_returns <- na.omit(to.monthly(df_xts, indexAt = "lastof", OHLC = FALSE) %>% Return.calculate(method = "log"))
monthly_cov_matrix <- cov(monthly_returns)
inv_monthly_cov_matrix <- pseudoinverse(monthly_cov_matrix)
gmvp_weights_monthly <- inv_monthly_cov_matrix %*% ones / sum(ones %*% inv_monthly_cov_matrix %*% ones)
gmvp_return_monthly <- sum(colMeans(monthly_returns) * gmvp_weights_monthly)
gmvp_std_monthly <- sqrt(t(gmvp_weights_monthly) %*% monthly_cov_matrix %*% gmvp_weights_monthly)
gmvp_weights_monthly
##              [,1]
## [1,] -0.028540599
## [2,]  0.520686730
## [3,] -0.001782652
## [4,]  0.509636521
gmvp_return_monthly
## [1] 0.005304254
gmvp_std_monthly
##            [,1]
## [1,] 0.02506921
excess_returns <- colMeans(monthly_returns)
tangency_weights <- inv_monthly_cov_matrix %*% excess_returns / sum(ones %*% inv_monthly_cov_matrix %*% excess_returns)
tangency_weights <- tangency_weights / sum(tangency_weights)
tangency_return <- sum(colMeans(monthly_returns) * tangency_weights)
tangency_std <- sqrt(t(tangency_weights) %*% monthly_cov_matrix %*% tangency_weights)
tangency_weights
##            [,1]
## [1,]  1.2789695
## [2,] -0.0873706
## [3,] -0.8967581
## [4,]  0.7051592
tangency_return
## [1] 0.01871875
tangency_std
##            [,1]
## [1,] 0.04709414
cat("Global Minimum Variance Portfolio (GMVP):")
## Global Minimum Variance Portfolio (GMVP):
print(gmvp_weights)
##            [,1]
## [1,] -0.2241314
## [2,]  0.7298726
## [3,]  0.1080760
## [4,]  0.3861827
cat("GMVP Return:", gmvp_return, "\n")
## GMVP Return: 0.0002263853
cat("GMVP Standard Deviation:", gmvp_std, "\n\n")
## GMVP Standard Deviation: 0.005921611
cat("Tangency Portfolio:")
## Tangency Portfolio:
print(tangency_weights)
##            [,1]
## [1,]  1.2789695
## [2,] -0.0873706
## [3,] -0.8967581
## [4,]  0.7051592
cat("Tangency Portfolio Return:", tangency_return, "\n")
## Tangency Portfolio Return: 0.01871875
cat("Tangency Portfolio Standard Deviation:", tangency_std, "\n")
## Tangency Portfolio Standard Deviation: 0.04709414