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)
data <- read.csv("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")
This analysis shows how the GMVP and Tangency Portfolio can be
constructed using four Taiwan ETFs. Using daily data, the GMVP minimizes
risk but results in lower returns. When using monthly data, the results
change slightly due to smoother return patterns affecting the
calculations.
The Tangency Portfolio, assuming a zero risk-free rate, provides a better balance between risk and return by maximizing return per unit of risk. Overall, the GMVP suits risk-averse investors, while the Tangency Portfolio is more suitable for those seeking higher returns.