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