Load Data

data <- read_csv("myetf4.csv")
## Rows: 751 Columns: 5
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): Index
## dbl (4): tw0050, tw0056, tw006205, tw00646
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(data)
## # A tibble: 6 × 5
##   Index      tw0050 tw0056 tw006205 tw00646
##   <chr>       <dbl>  <dbl>    <dbl>   <dbl>
## 1 2015/12/14   53.3   18.2     31.1    19.6
## 2 2015/12/15   53.3   18.4     31.6    19.6
## 3 2015/12/16   54.1   18.6     31.6    19.9
## 4 2015/12/17   54.8   18.8     32.2    20.0
## 5 2015/12/18   54.5   19.0     32.2    19.8
## 6 2015/12/21   54.4   19.0     33      19.6

Assume first column = Date, others = ETF prices.

data <- data %>%
  rename(Date = 1) %>%
  mutate(Date = as.Date(Date))

Compute Daily Returns

returns_daily <- data %>%
  arrange(Date) %>%
  mutate(across(-Date, ~ (. / lag(.) - 1))) %>%
  drop_na()

head(returns_daily)
## # A tibble: 6 × 5
##   Date          tw0050   tw0056  tw006205  tw00646
##   <date>         <dbl>    <dbl>     <dbl>    <dbl>
## 1 2015-12-15  0.000751  0.00712  0.0171    0.00102
## 2 2015-12-16  0.0152    0.00979  0.000317  0.0132 
## 3 2015-12-17  0.0116    0.0135   0.0199    0.00804
## 4 2015-12-18 -0.00493   0.00744 -0.00155  -0.00998
## 5 2015-12-21 -0.00165   0.00369  0.0255   -0.0106 
## 6 2015-12-22  0.00239  -0.00368  0.00303   0.00407

Q1: GMVP using Daily Returns

Mean and Covariance

R <- as.matrix(returns_daily[, -1])

mu <- colMeans(R)
Sigma <- cov(R)

Compute GMVP Weights

Formula:
w = Σ⁻¹ 1 / (1’ Σ⁻¹ 1)

one <- rep(1, ncol(R))

Sigma_inv <- solve(Sigma)

w_gmvp <- Sigma_inv %*% one / as.numeric(t(one) %*% Sigma_inv %*% one)

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

Portfolio Return and Risk

ret_gmvp <- sum(w_gmvp * mu)
sd_gmvp  <- sqrt(t(w_gmvp) %*% Sigma %*% w_gmvp)

ret_gmvp
## [1] 0.0002536645
sd_gmvp
##             [,1]
## [1,] 0.005904941

Q2: GMVP using Monthly Returns

Convert to Monthly Prices

data_monthly <- data %>%
  mutate(YearMonth = floor_date(Date, "month")) %>%
  group_by(YearMonth) %>%
  summarise(across(-Date, last)) %>%
  ungroup() %>%
  rename(Date = YearMonth)

Monthly Returns

returns_monthly <- data_monthly %>%
  arrange(Date) %>%
  mutate(across(-Date, ~ (. / lag(.) - 1))) %>%
  drop_na()

head(returns_monthly)
## # A tibble: 6 × 5
##   Date        tw0050   tw0056 tw006205  tw00646
##   <date>       <dbl>    <dbl>    <dbl>    <dbl>
## 1 2016-01-01 -0.0198 -0.0138  -0.173   -0.0389 
## 2 2016-02-01  0.0286  0.0435  -0.0276  -0.00363
## 3 2016-03-01  0.0555 -0.00258  0.0828   0.0260 
## 4 2016-04-01 -0.0472 -0.0372  -0.0248   0.00964
## 5 2016-05-01  0.0252  0.0166   0.00442  0.0221 
## 6 2016-06-01  0.0364  0.0296  -0.0256  -0.0261

GMVP (Monthly)

R_m <- as.matrix(returns_monthly[, -1])

mu_m <- colMeans(R_m)
Sigma_m <- cov(R_m)

one <- rep(1, ncol(R_m))

Sigma_inv_m <- solve(Sigma_m)

w_gmvp_m <- Sigma_inv_m %*% one / as.numeric(t(one) %*% Sigma_inv_m %*% one)

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

Monthly GMVP Return and Risk

ret_gmvp_m <- sum(w_gmvp_m * mu_m)
sd_gmvp_m  <- sqrt(t(w_gmvp_m) %*% Sigma_m %*% w_gmvp_m)

ret_gmvp_m
## [1] 0.005733667
sd_gmvp_m
##            [,1]
## [1,] 0.02490441

Q3: Tangency Portfolio (rf = 0)

Formula:
w = Σ⁻¹ μ / (1’ Σ⁻¹ μ)

one <- rep(1, ncol(R_m))

w_tan <- solve(Sigma_m) %*% mu_m / as.numeric(t(one) %*% solve(Sigma_m) %*% mu_m)

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

Tangency Portfolio Return and Risk

ret_tan <- sum(w_tan * mu_m)
sd_tan  <- sqrt(t(w_tan) %*% Sigma_m %*% w_tan)

ret_tan
## [1] 0.01809002
sd_tan
##            [,1]
## [1,] 0.04423638

Final Results Summary

results <- tibble(
  Portfolio = c("GMVP Daily", "GMVP Monthly", "Tangency"),
  Return = c(ret_gmvp, ret_gmvp_m, ret_tan),
  Risk_SD = c(sd_gmvp, sd_gmvp_m, sd_tan)
)

results
## # A tibble: 3 × 3
##   Portfolio      Return Risk_SD
##   <chr>           <dbl>   <dbl>
## 1 GMVP Daily   0.000254 0.00590
## 2 GMVP Monthly 0.00573  0.0249 
## 3 Tangency     0.0181   0.0442

Interpretation

Higher return portfolios come with higher volatility, showing the classic risk-return tradeoff in financial markets.