rm(list = ls())
library(readr)
library(xts)
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
library(dplyr)
##
## ######################### Warning from 'xts' package ##########################
## # #
## # The dplyr lag() function breaks how base R's lag() function is supposed to #
## # work, which breaks lag(my_xts). Calls to lag(my_xts) that you type or #
## # source() into this session won't work correctly. #
## # #
## # Use stats::lag() to make sure you're not using dplyr::lag(), or you can add #
## # conflictRules('dplyr', exclude = 'lag') to your .Rprofile to stop #
## # dplyr from breaking base R's lag() function. #
## # #
## # Code in packages is not affected. It's protected by R's namespace mechanism #
## # Set `options(xts.warn_dplyr_breaks_lag = FALSE)` to suppress this warning. #
## # #
## ###############################################################################
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:xts':
##
## first, last
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(pracma)
library(ggplot2)
options(repos = list(CRAN="http://cran.rstudio.com/"))
#data
etf4 <- read_csv("myetf4(1) (1).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(etf4)
## # 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
# Q1. Try to find the MVP for 4 Taiwan ETFs: "0050","0056","006205","00646". Using 2015/12/14-2018/12/28 daily returns as the insample data. You have to compute optimal weights for 4 ETFs based on daily returns of the period. Also given the weights from Q1, compute realized returns of MVP.
etf4$Index <- as.Date(etf4$Index, format="%Y/%m/%d")
etf4 <- etf4 %>% filter(between(Index,as.Date('2015-12-14'), as.Date('2018-12-28')))
head(etf4)
## # A tibble: 6 × 5
## Index tw0050 tw0056 tw006205 tw00646
## <date> <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
cov <- cov(etf4[,2:5])
one <- rep(1,4)
one_41<- matrix(one,ncol=1)
nume <- inv(cov)%*%one_41
deno <- t(one_41)%*%nume
mvp_daily <- nume / as.vector(deno)
as_tibble(mvp_daily)
## Warning: The `x` argument of `as_tibble.matrix()` must have unique column names if
## `.name_repair` is omitted as of tibble 2.0.0.
## ℹ Using compatibility `.name_repair`.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## # A tibble: 4 × 1
## V1
## <dbl>
## 1 -0.281
## 2 1.08
## 3 0.136
## 4 0.0648
colnames(mvp_daily) = "Weight"
mvp_daily
## Weight
## tw0050 -0.28080456
## tw0056 1.07989097
## tw006205 0.13606491
## tw00646 0.06484868
mean_return <- colMeans(etf4[,2:5])
mean <- t(as.matrix(mean_return))
realized_return <- mean%*%mvp_daily
as_tibble(realized_return)
## # A tibble: 1 × 1
## Weight
## <dbl>
## 1 9.89
colnames(realized_return) = "Daily Realized Return"
realized_return
## Daily Realized Return
## [1,] 9.892485
# Q2. By Q1, use monthly returns to recalculate the answers to Q1
month_etf4 <- to.monthly(etf4)
colnames(month_etf4) = c("tw0050","tw0056","tw006205","tw00646")
head(month_etf4)
## tw0050 tw0056 tw006205 tw00646
## Dec 2015 53.29 19.02 31.06 20.06
## Jan 2016 53.42 18.60 25.40 19.28
## Feb 2016 53.42 19.41 25.46 19.21
## Mar 2016 55.49 19.70 25.41 19.71
## Apr 2016 57.32 19.23 26.98 19.90
## May 2016 54.50 18.95 26.02 20.34
cov_mon <- cov(month_etf4[1:4]) #4x4
nume_mon <- inv(cov_mon)%*%one_41
deno_mon <- t(one_41)%*%nume_mon
mvp_mon <- nume_mon / as.vector(deno_mon)
as_tibble(mvp_mon)
## # A tibble: 4 × 1
## V1
## <dbl>
## 1 -0.269
## 2 1.01
## 3 0.127
## 4 0.128
colnames(mvp_mon) = "Weight"
mvp_mon
## Weight
## tw0050 -0.2689932
## tw0056 1.0143129
## tw006205 0.1268862
## tw00646 0.1277941
mean_return_mon <- colMeans(month_etf4[,1:4])
mean_mon <- t(as.matrix(mean_return_mon))
realized_return_mon <- mean_mon%*%mvp_mon
as_tibble(realized_return_mon)
## # A tibble: 1 × 1
## Weight
## <dbl>
## 1 10.7
colnames(realized_return_mon) = "Monthly Realized Return"
realized_return_mon
## Monthly Realized Return
## [1,] 10.74154
# Q3. Find the tangency portfolio based on Q2. Risk-free rate is assumed to be zero.
nume_t <- inv(cov_mon)%*%mean_return_mon # 4x4 x 4x1 = 4x1
deno_t <- t(one_41)%*%nume_t # 1x4 x 4x1
port_t <- nume_t/as.vector(deno_t)
as_tibble(port_t)
## # A tibble: 4 × 1
## V1
## <dbl>
## 1 -0.236
## 2 0.883
## 3 0.192
## 4 0.161
colnames(port_t)= "Weight"
port_t
## Weight
## tw0050 -0.2359199
## tw0056 0.8827621
## tw006205 0.1923066
## tw00646 0.1608512