Introduction

This report evaluates four leading Taiwan ETFs—0050, 0056, 006205, and 00646—to highlight their role in portfolio construction. Using modern portfolio theory, we derive the Global Minimum Variance Portfolio (GMVP) to minimize risk, measure portfolio return and volatility to assess performance, and identify the Tangency Portfolio that maximizes risk‑adjusted returns. The analysis provides a concise view of diversification and optimal allocation strategies in the Taiwan ETF market.


Load data

data <- read_csv("myetf4.csv")
data$Index <- as.Date(data$Index, format = "%m/%d/%Y")
prices <- xts(data[, -1], order.by = data$Index)
head(prices)
##            tw0050 tw0056 tw006205 tw00646
## 2015-12-14  53.29  18.25    31.06   19.61
## 2015-12-15  53.33  18.38    31.59   19.63
## 2015-12-16  54.14  18.56    31.60   19.89
## 2015-12-17  54.77  18.81    32.23   20.05
## 2015-12-18  54.50  18.95    32.18   19.85
## 2015-12-21  54.41  19.02    33.00   19.64

Q1. GMVP using Daily Returns

Compute Daily Returns

returns_daily <- na.omit(Return.calculate(prices, method = "simple"))
head(returns_daily)
##                   tw0050       tw0056      tw006205      tw00646
## 2015-12-15  0.0007506099  0.007123288  0.0170637476  0.001019888
## 2015-12-16  0.0151884493  0.009793254  0.0003165559  0.013245033
## 2015-12-17  0.0116364980  0.013469828  0.0199367089  0.008044243
## 2015-12-18 -0.0049297060  0.007442850 -0.0015513497 -0.009975062
## 2015-12-21 -0.0016513761  0.003693931  0.0254816656 -0.010579345
## 2015-12-22  0.0023892667 -0.003680336  0.0030303030  0.004073320

Compute GMVP Weights

The GMVP is computed using: \[ w_{GMVP} = \frac{\Sigma^{-1} \mathbf{1}}{\mathbf{1}^\top \Sigma^{-1} \mathbf{1}} \]

cov_mat_daily <- cov(returns_daily)
inv_cov_daily <- solve(cov_mat_daily)

one_vec <- rep(1, ncol(returns_daily))

weights_gmvp_daily <- (inv_cov_daily %*% one_vec) / 
                      as.numeric(t(one_vec) %*% inv_cov_daily %*% one_vec)

weights_gmvp_daily
##                [,1]
## tw0050   -0.2193579
## tw0056    0.7283718
## tw006205  0.1076234
## tw00646   0.3833627

Portfolio Return and Risk

mean_returns_daily <- colMeans(returns_daily)

# Expected return
portfolio_return_daily <- sum(weights_gmvp_daily * mean_returns_daily)

# Standard deviation
portfolio_sd_daily <- sqrt(t(weights_gmvp_daily) %*% cov_mat_daily %*% weights_gmvp_daily)

portfolio_return_daily
## [1] 0.0002536645
portfolio_sd_daily
##             [,1]
## [1,] 0.005904941

Interpretation

  • The GMVP minimizes variance regardless of expected return.
  • Negative weights indicate short selling.
  • Daily data often produces unstable weights due to high noise.

Q2. GMVP using Monthly Returns

Convert to Monthly Returns

monthly_prices <- to.monthly(prices, indexAt = "lastof", OHLC = FALSE)
returns_monthly <- na.omit(Return.calculate(monthly_prices, method = "simple"))

head(returns_monthly)
##                 tw0050       tw0056     tw006205      tw00646
## 2016-01-31 -0.01981651 -0.013785790 -0.173070915 -0.038883350
## 2016-02-29  0.02864096  0.043548387 -0.027578391 -0.003630705
## 2016-03-31  0.05550500 -0.002575992  0.082750583  0.026028110
## 2016-04-30 -0.04724138 -0.037190083 -0.024757804  0.009639777
## 2016-05-31  0.02515382  0.016630901  0.004415011  0.022110553
## 2016-06-30  0.03636364  0.029551451 -0.025641026 -0.026057030

Compute GMVP Weights (Monthly)

cov_mat_monthly <- cov(returns_monthly)
inv_cov_monthly <- solve(cov_mat_monthly)

one_vec <- rep(1, ncol(returns_monthly))

weights_gmvp_monthly <- (inv_cov_monthly %*% one_vec) / 
                        as.numeric(t(one_vec) %*% inv_cov_monthly %*% one_vec)

weights_gmvp_monthly
##                 [,1]
## tw0050   0.003183861
## tw0056   0.474049044
## tw006205 0.001203750
## tw00646  0.521563345

Portfolio Performance

mean_returns_monthly <- colMeans(returns_monthly)

portfolio_return_monthly <- sum(weights_gmvp_monthly * mean_returns_monthly)

portfolio_sd_monthly <- sqrt(t(weights_gmvp_monthly) %*% cov_mat_monthly %*% weights_gmvp_monthly)

portfolio_return_monthly
## [1] 0.005733667
portfolio_sd_monthly
##            [,1]
## [1,] 0.02490441

Interpretation

  • Monthly data reduces noise and produces more stable weights.
  • The portfolio is more realistic compared to daily GMVP.

Q3. Tangency Portfolio (Risk-Free Rate = 0)

Formula: \[ w_{TAN} = \frac{\Sigma^{-1} (\mu - r_f \mathbf{1})}{\mathbf{1}^\top \Sigma^{-1} (\mu - r_f \mathbf{1})} \]

Compute Tangency Portfolio

mu <- mean_returns_monthly

weights_tangency <- (inv_cov_monthly %*% mu) / 
                     as.numeric(t(one_vec) %*% inv_cov_monthly %*% mu)

weights_tangency
##                [,1]
## tw0050    1.3050535
## tw0056   -0.1576807
## tw006205 -0.8475320
## tw00646   0.7001591

Portfolio Performance

tangency_return <- sum(weights_tangency * mu)

tangency_sd <- sqrt(t(weights_tangency) %*% cov_mat_monthly %*% weights_tangency)

tangency_return
## [1] 0.01809002
tangency_sd
##            [,1]
## [1,] 0.04423638

Interpretation

  • The tangency portfolio maximizes the Sharpe Ratio.

  • Since \(R_f = 0\), it maximizes: \[ \frac{E(R_p)}{\sigma_p} \]

  • It often includes: Leverage (weights > 1), Short selling (negative weights)

  • In the context of CAPM, this portfolio corresponds to the theoretical market portfolio, which all investors should hold in combination with a risk-free asset. In practice, diversified index ETFs are often used as proxies for this optimal portfolio, making it highly relevant for real-world investment strategies.


Efficient Frontier (Monthly Data)

Generate Random Portfolios

set.seed(123)

n_portfolios <- 5000
n_assets <- ncol(returns_monthly)

weights_matrix <- matrix(NA, nrow = n_portfolios, ncol = n_assets)
returns_vec <- numeric(n_portfolios)
risk_vec <- numeric(n_portfolios)

for (i in 1:n_portfolios) {
  
  # Random weights
  w <- runif(n_assets)
  w <- w / sum(w)
  
  weights_matrix[i, ] <- w
  
  # Portfolio return
  returns_vec[i] <- sum(w * mean_returns_monthly)
  
  # Portfolio risk
  risk_vec[i] <- sqrt(t(w) %*% cov_mat_monthly %*% w)
}

Compute Efficient Frontier

library(quadprog)

target_returns <- seq(min(returns_vec), max(returns_vec), length.out = 100)

efficient_risk <- numeric(length(target_returns))

Dmat <- 2 * cov_mat_monthly
dvec <- rep(0, n_assets)

Amat <- cbind(rep(1, n_assets), mean_returns_monthly)
bvec <- c(1, 0)

for (i in 1:length(target_returns)) {
  
  bvec[2] <- target_returns[i]
  
  result <- solve.QP(Dmat, dvec, Amat, bvec, meq = 2)
  
  w <- result$solution
  
  efficient_risk[i] <- sqrt(t(w) %*% cov_mat_monthly %*% w)
}

Plot Efficient Frontier

Interpretation

The efficient frontier shows the set of optimal portfolios that dominate all others in terms of risk and return. CAPM simplifies this framework by identifying a single optimal portfolio—the tangency portfolio—and combining it with the risk-free asset to form the Capital Market Line. This highlights that rational investors should focus on efficient portfolios and avoid suboptimal combinations, supporting the use of diversified, passive investment approaches.


Final Conclusion

This analysis highlights the trade-off between risk minimization and return optimization in portfolio construction. While the GMVP provides the lowest risk, the tangency portfolio offers a more attractive balance between risk and return. The efficient frontier further reinforces that only a limited set of portfolios is truly optimal. In practice, these results support the use of diversified portfolios and index-based investing, which approximate the optimal solutions predicted by financial theory while remaining simple and cost-effective.