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))
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
R <- as.matrix(returns_daily[, -1])
mu <- colMeans(R)
Sigma <- cov(R)
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
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
data_monthly <- data %>%
mutate(YearMonth = floor_date(Date, "month")) %>%
group_by(YearMonth) %>%
summarise(across(-Date, last)) %>%
ungroup() %>%
rename(Date = YearMonth)
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
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
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
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
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
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
Higher return portfolios come with higher volatility, showing the classic risk-return tradeoff in financial markets.