library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ ggplot2   3.4.2     ✔ tibble    3.2.1
## ✔ lubridate 1.9.2     ✔ tidyr     1.3.0
## ✔ purrr     1.0.2     
## ── 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
data <- read.csv("myetf4.csv")
colnames(data)[1] <- "Date"
data$Date <- as.Date(data$Date, format="%Y/%m/%d")
selected_ETFs <- c("tw0050", "tw0056", "tw006205", "tw00646")
data_filtered <- data %>% select(Date, all_of(selected_ETFs))
data_filtered <- data_filtered %>% filter(Date >= "2015-12-14" & Date <= "2018-12-28")
returns <- data_filtered %>% 
  select(-Date) %>%
  mutate_all(~ log(. / lag(.))) %>%
  na.omit()
cov_matrix <- cov(returns)
ones <- rep(1, ncol(returns))
inv_cov_matrix <- solve(cov_matrix)
w_gmvp <- inv_cov_matrix %*% ones / sum(inv_cov_matrix %*% ones)
gmvp_return <- colMeans(returns) %*% w_gmvp
gmvp_risk <- sqrt(t(w_gmvp) %*% cov_matrix %*% w_gmvp)
cat("GMVP Weights:\n")
## GMVP Weights:
print(w_gmvp)
##                [,1]
## tw0050   -0.2241314
## tw0056    0.7298726
## tw006205  0.1080760
## tw00646   0.3861827
cat("\nGMVP Return:", gmvp_return)
## 
## GMVP Return: 0.0002263853
cat("\nGMVP Risk (Std Dev):", gmvp_risk)
## 
## GMVP Risk (Std Dev): 0.005921611
returns_monthly <- returns %>%
  mutate(Date = data_filtered$Date[-1]) %>%  # Add Date column (excluding first NA row)
  mutate(YearMonth = format(Date, "%Y-%m")) %>%
  group_by(YearMonth) %>%
  summarize(across(-Date, ~ prod(1 + ., na.rm = TRUE) - 1)) %>%
  ungroup()
head(returns_monthly)
## # A tibble: 6 × 5
##   YearMonth  tw0050   tw0056 tw006205  tw00646
##   <chr>       <dbl>    <dbl>    <dbl>    <dbl>
## 1 2015-12    0.0224  0.0332   0.0295   0.0226 
## 2 2016-01   -0.0215 -0.0148  -0.181   -0.0405 
## 3 2016-02    0.0281  0.0433  -0.0302  -0.00424
## 4 2016-03    0.0549 -0.00296  0.0797   0.0256 
## 5 2016-04   -0.0482 -0.0375  -0.0264   0.00944
## 6 2016-05    0.0241  0.0160   0.00288  0.0218
cov_matrix_monthly <- cov(returns_monthly[,-1], use="complete.obs")
gmvp_weights_monthly <- solve(cov_matrix_monthly) %*% ones / sum(solve(cov_matrix_monthly) %*% ones)
gmvp_return_monthly <- colMeans(returns_monthly[,-1]) %*% gmvp_weights_monthly
gmvp_sd_monthly <- sqrt(t(gmvp_weights_monthly) %*% cov_matrix_monthly %*% gmvp_weights_monthly)
cat("Monthly GMVP Weights:", gmvp_weights_monthly, "\n")
## Monthly GMVP Weights: 0.01064151 0.4706479 -0.009441197 0.5281518
cat("Monthly GMVP Return:", gmvp_return_monthly, "\n")
## Monthly GMVP Return: 0.005928447
cat("Monthly GMVP Standard Deviation:", gmvp_sd_monthly, "\n")
## Monthly GMVP Standard Deviation: 0.02511828
tangency_weights <- solve(cov_matrix_monthly) %*% colMeans(returns_monthly[,-1])
tangency_weights <- tangency_weights / sum(tangency_weights)
tangency_return <- colMeans(returns_monthly[,-1]) %*% tangency_weights
tangency_sd <- sqrt(t(tangency_weights) %*% cov_matrix_monthly %*% tangency_weights)
cat("Tangency Portfolio Weights:", tangency_weights, "\n")
## Tangency Portfolio Weights: 1.065822 0.09573927 -0.8225181 0.6609571
cat("Tangency Portfolio Return:", tangency_return, "\n")
## Tangency Portfolio Return: 0.01723056
cat("Tangency Portfolio Standard Deviation:", tangency_sd, "\n")
## Tangency Portfolio Standard Deviation: 0.04282222