library(xts)
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
library(PerformanceAnalytics)
##
## Attaching package: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
##
## legend
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.5.2
data <- read.csv("/Users/faizhaikal/Downloads/myetf4.csv", stringsAsFactors = FALSE)
colnames(data)[1] <- "Date"
data$Date <- as.Date(data$Date)
data[,-1] <- lapply(data[,-1], function(x) as.numeric(as.character(x)))
data <- na.omit(data)
data_xts <- xts(data[,-1], order.by = data$Date)
ret_daily <- na.omit(diff(log(data_xts)))
ret_daily <- ret_daily["2015-12-14/2018-12-28"]
price_monthly <- to.monthly(data_xts, indexAt = "lastof", OHLC = FALSE)
ret_monthly <- na.omit(diff(log(price_monthly)))
cov_mat <- cov(ret_monthly) + diag(1e-6, ncol(ret_monthly))
mean_ret <- colMeans(ret_monthly)
one_vec <- rep(1, ncol(ret_monthly))
inv_cov <- solve(cov_mat)
w_gmvp <- inv_cov %*% one_vec / as.numeric(t(one_vec) %*% inv_cov %*% one_vec)
ret_gmvp <- sum(w_gmvp * mean_ret)
sd_gmvp <- sqrt(t(w_gmvp) %*% cov_mat %*% w_gmvp)
w_tan <- inv_cov %*% mean_ret / as.numeric(t(one_vec) %*% inv_cov %*% mean_ret)
ret_tan <- sum(w_tan * mean_ret)
sd_tan <- sqrt(t(w_tan) %*% cov_mat %*% w_tan)
portfolio_returns <- c()
portfolio_risk <- c()
set.seed(123)
for(i in 1:5000){
w <- runif(ncol(ret_monthly))
w <- w / sum(w)
port_return <- sum(w * mean_ret)
port_risk <- sqrt(t(w) %*% cov_mat %*% w)
portfolio_returns <- c(portfolio_returns, port_return)
portfolio_risk <- c(portfolio_risk, port_risk)
}
df <- data.frame(Risk = portfolio_risk, Return = portfolio_returns)
ggplot(df, aes(x = Risk, y = Return)) +
geom_point(alpha = 0.3) +
# GMVP
geom_point(aes(x = sd_gmvp, y = ret_gmvp), size = 4) +
# Tangency
geom_point(aes(x = sd_tan, y = ret_tan), size = 4) +
ggtitle("Efficient Frontier with GMVP and Tangency Portfolio") +
xlab("Risk (Standard Deviation)") +
ylab("Expected Return") +
theme_minimal()
## Warning in geom_point(aes(x = sd_gmvp, y = ret_gmvp), size = 4): All aesthetics have length 1, but the data has 5000 rows.
## ℹ Please consider using `annotate()` or provide this layer with data containing
## a single row.
## Warning in geom_point(aes(x = sd_tan, y = ret_tan), size = 4): All aesthetics have length 1, but the data has 5000 rows.
## ℹ Please consider using `annotate()` or provide this layer with data containing
## a single row.
results <- data.frame(
Portfolio = c("GMVP", "Tangency"),
Return = c(ret_gmvp, ret_tan),
Risk = c(sd_gmvp, sd_tan)
)
print(results)
## Portfolio Return Risk
## 1 GMVP 0.005306363 0.02507979
## 2 Tangency 0.018702323 0.04708399
ret_gmvp_series <- xts(ret_monthly %*% w_gmvp, order.by = index(ret_monthly))
ret_tan_series <- xts(ret_monthly %*% w_tan, order.by = index(ret_monthly))
combined <- merge(ret_gmvp_series, ret_tan_series)
colnames(combined) <- c("GMVP", "Tangency")
charts.PerformanceSummary(combined, main = "Cumulative Returns Comparison")
The results show that both the GMVP and the Tangency Portfolio can be
formed using four Taiwan ETFs. Based on daily data, the GMVP achieves
the lowest level of risk, but it also comes with relatively lower
returns. When monthly data is used instead, the outcomes differ slightly
because the returns are smoother, which influences the calculations. The
Tangency Portfolio, assuming a zero risk-free rate, offers a more
optimal trade-off between risk and return by maximizing returns for each
unit of risk taken. In general, the GMVP is more appropriate for
risk-averse investors, while the Tangency Portfolio is better suited for
investors who are aiming for higher returns.