1. Import Data

Load librarties

library(fBasics)
library(kableExtra)
library(dplyr)
library(tidyquant)
library(lubridate)
library(timetk)
library(purrr)
library(quantmod)

Get data from Yahoo

symbols <- c("SPY","QQQ", "EEM", "IWM", "EFA", "TLT", "IYR", "GLD") 
portfolioPrices <- NULL
for (symbol in symbols) {
  portfolioPrices <- cbind(portfolioPrices, 
                           getSymbols.yahoo(symbol,
                                            from = '2010-01-01',
                                            to = Sys.Date(),
                                            auto.assign = FALSE)[,6])
}

colnames(portfolioPrices) <- symbols

head(portfolioPrices)
##                 SPY      QQQ      EEM      IWM      EFA      TLT      IYR
## 2010-01-04 86.86005 40.73329 31.82711 52.51540 37.52378 61.13184 28.10298
## 2010-01-05 87.09000 40.73329 32.05812 52.33482 37.55685 61.52667 28.17046
## 2010-01-06 87.15130 40.48758 32.12519 52.28558 37.71560 60.70301 28.15820
## 2010-01-07 87.51922 40.51390 31.93890 52.67137 37.57009 60.80507 28.40971
## 2010-01-08 87.81046 40.84736 32.19226 52.95863 37.86775 60.77786 28.21954
## 2010-01-11 87.93309 40.68064 32.12519 52.74522 38.17862 60.44437 28.35450
##               GLD
## 2010-01-04 109.80
## 2010-01-05 109.70
## 2010-01-06 111.51
## 2010-01-07 110.82
## 2010-01-08 111.37
## 2010-01-11 112.85

2. Calculate weekly and monthly returns using discrete returns

#Change data from daily to weekly
weekly_prices <- to.weekly(portfolioPrices, indexAt = 'last', OHLC = FALSE)

#Calculate weekly returns
weekly_returns <- na.omit(Return.calculate(weekly_prices), method = "discrete")

head(weekly_returns)
##                     SPY          QQQ         EEM         IWM          EFA
## 2010-01-15 -0.008117387 -0.015037882 -0.02893515 -0.01301893 -0.003493974
## 2010-01-22 -0.038982784 -0.036858813 -0.05578075 -0.03062199 -0.055740630
## 2010-01-29 -0.016665246 -0.031024042 -0.03357769 -0.02624317 -0.025802703
## 2010-02-05 -0.006797334  0.004440629 -0.02821288 -0.01397445 -0.019054781
## 2010-02-12  0.012937816  0.018147539  0.03333322  0.02952613  0.005244716
## 2010-02-19  0.028693427  0.024451565  0.02445362  0.03343139  0.022995087
##                      TLT          IYR          GLD
## 2010-01-15  2.004757e-02 -0.006304694 -0.004579349
## 2010-01-22  1.010075e-02 -0.041784835 -0.033285246
## 2010-01-29  3.369615e-03 -0.008447871 -0.011290465
## 2010-02-05 -5.451863e-05  0.003223667 -0.012080019
## 2010-02-12 -1.945990e-02 -0.007573861  0.022544905
## 2010-02-19 -8.205810e-03  0.050184807  0.022701796
#Change data from daily to monthly
monthly_prices <- to.monthly(portfolioPrices, indexAt = 'last', OHLC = FALSE)

#Calculate monthly returns
monthly_returns <- na.omit(Return.calculate(monthly_prices), method = "discrete")

head(monthly_returns)
##                    SPY         QQQ          EEM         IWM          EFA
## 2010-02-26  0.03119473  0.04603862  0.017764219  0.04475119  0.002667557
## 2010-03-31  0.06087938  0.07710944  0.081108647  0.08230674  0.063854445
## 2010-04-30  0.01547034  0.02242521 -0.001661697  0.05678439 -0.028045889
## 2010-05-28 -0.07945450 -0.07392379 -0.093935803 -0.07536653 -0.111928183
## 2010-06-30 -0.05174109 -0.05975656 -0.013986722 -0.07743358 -0.020619233
## 2010-07-30  0.06830083  0.07258273  0.109324714  0.06730927  0.116103873
##                     TLT         IYR          GLD
## 2010-02-26 -0.003423867  0.05457097  0.032748219
## 2010-03-31 -0.020573940  0.09748445 -0.004386396
## 2010-04-30  0.033218293  0.06388157  0.058834363
## 2010-05-28  0.051083483 -0.05683563  0.030513147
## 2010-06-30  0.057979109 -0.04670116  0.023553189
## 2010-07-30 -0.009464356  0.09404835 -0.050871157

3. Download Fama French 3 factors data and change to digit numbers

#Import data
library(readr)
F_F_Research_Data_Factors <- read_csv("C:/Users/Admin/OneDrive - 亞洲大學[Asia University]/3rd Year/2nd Sem/1. Investment Portfolio Analysis/F-F_Research_Data_Factors.CSV")
FF3 <- F_F_Research_Data_Factors %>% select(-RF)
FF3 <- FF3 %>% 
  mutate_at(vars(-1), ~ ./100)

head(FF3)
## # A tibble: 6 × 4
##     Time `Mkt-RF`     SMB     HML
##    <dbl>    <dbl>   <dbl>   <dbl>
## 1 192607   0.0296 -0.0256 -0.0243
## 2 192608   0.0264 -0.0117  0.0382
## 3 192609   0.0036 -0.014   0.0013
## 4 192610  -0.0324 -0.0009  0.007 
## 5 192611   0.0253 -0.001  -0.0051
## 6 192612   0.0262 -0.0003 -0.0005

4. Merge monthly return data in question 2 and 3

FF3_subset <- FF3 %>% 
  filter(Time >= 201002 & Time <= 202402)

monthly_returns_subset <- monthly_returns["2010-02-26/2024-02-29"]
monthly_returns_subset_df <- as_tibble(index(monthly_returns_subset)) %>%
  rename(time = value) %>%
  bind_cols(as_tibble(coredata(monthly_returns_subset)))

merged_monthlyreturns <- bind_cols(monthly_returns_subset_df,  FF3_subset[, c("Mkt-RF", "SMB", "HML")])

merged_monthlyreturns_xts <- xts(merged_monthlyreturns[, -1], order.by = merged_monthlyreturns$time)

head(merged_monthlyreturns_xts)
##                    SPY         QQQ          EEM         IWM          EFA
## 2010-02-26  0.03119473  0.04603862  0.017764219  0.04475119  0.002667557
## 2010-03-31  0.06087938  0.07710944  0.081108647  0.08230674  0.063854445
## 2010-04-30  0.01547034  0.02242521 -0.001661697  0.05678439 -0.028045889
## 2010-05-28 -0.07945450 -0.07392379 -0.093935803 -0.07536653 -0.111928183
## 2010-06-30 -0.05174109 -0.05975656 -0.013986722 -0.07743358 -0.020619233
## 2010-07-30  0.06830083  0.07258273  0.109324714  0.06730927  0.116103873
##                     TLT         IYR          GLD  Mkt-RF     SMB     HML
## 2010-02-26 -0.003423867  0.05457097  0.032748219  0.0340  0.0119  0.0323
## 2010-03-31 -0.020573940  0.09748445 -0.004386396  0.0631  0.0148  0.0221
## 2010-04-30  0.033218293  0.06388157  0.058834363  0.0200  0.0487  0.0289
## 2010-05-28  0.051083483 -0.05683563  0.030513147 -0.0789  0.0009 -0.0244
## 2010-06-30  0.057979109 -0.04670116  0.023553189 -0.0557 -0.0182 -0.0470
## 2010-07-30 -0.009464356  0.09404835 -0.050871157  0.0693  0.0020 -0.0031

5. Based on CAPM model, compute MVP monthly returns based on estimated covariance matrix for the 8-asset portfolio by using past 60-month returns from 2019/03 - 2024/02

monthly_returns_60 <- merged_monthlyreturns_xts["2019-03-29/2024-02-29"]
portfolio_8 <- monthly_returns_60[, 1:8]
rf <- monthly_returns_60[, 9]
#Find covariance matrix using CAMP
cov_ma_sim <- function(returns, rf){
  n <- nrow(returns)
  X <- as.matrix(cbind(rep(1, n), rf))
  Y <- as.matrix(returns)
  
  b_hat <- solve(t(X) %*% X) %*% t(X) %*% Y
  E_hat = Y - X %*% b_hat
  
  b_hat <- as.matrix(b_hat[-1, ])
  diagD_hat <- diag(t(E_hat) %*% E_hat) / (n - 2)
  diag(diagD_hat)
  
  cov_sfm <- as.numeric(var(rf)) * b_hat %*% t(b_hat) + diag(diagD_hat)
  return(cov_sfm)
}

cov_ma <- cov_ma_sim(portfolio_8, rf)

head(cov_ma)
##              SPY          QQQ          EEM          IWM          EFA
## SPY 0.0027966270 0.0030811089 0.0021462683 0.0033220117 0.0024368327
## QQQ 0.0030811089 0.0039946832 0.0023958712 0.0037083491 0.0027202271
## EEM 0.0021462683 0.0023958712 0.0030463237 0.0025831972 0.0018948818
## IWM 0.0033220117 0.0037083491 0.0025831972 0.0047665046 0.0029329136
## EFA 0.0024368327 0.0027202271 0.0018948818 0.0029329136 0.0027205586
## TLT 0.0004742554 0.0005294095 0.0003687811 0.0005708025 0.0004187072
##              TLT          IYR          GLD
## SPY 0.0004742554 0.0026231108 4.941832e-04
## QQQ 0.0005294095 0.0029281687 5.516549e-04
## EEM 0.0003687811 0.0020397318 3.842770e-04
## IWM 0.0005708025 0.0031571136 5.947871e-04
## EFA 0.0004187072 0.0023158731 4.363009e-04
## TLT 0.0022599781 0.0004507143 8.491271e-05
#Find MPV weights
MVP_sim <- function(cov_ma){
  x <- ncol(cov_ma)
  one_ma <- matrix(rep(1,x), ncol = 1)
  numerator <- inv(cov_ma) %*% one_ma
  denominator <- t(one_ma) %*% inv(cov_ma) %*% one_ma
  weights <- numerator/as.vector(denominator)
  colnames(weights) <- "Weight"
  return(weights)
}

capm_model<- MVP_sim(cov_ma)
capm_model
##          Weight
## SPY  0.26923978
## QQQ -0.15320021
## EEM  0.13888788
## IWM -0.20343762
## EFA  0.18519433
## TLT  0.31471311
## IYR  0.04714307
## GLD  0.40145967

6. Based on FF 3-factor model, compute MVP monthly returns covariance matrix for the 8-asset portfolio by using past 60-month returns from 2019/03 - 2024/02

#Find covariance matrix using Fama-French 3-factor
N <- nrow(portfolio_8)
ones <- rep(1, N)
portfolio_ma <- as.matrix(portfolio_8)
sigF3 <- as.matrix(var(cbind(monthly_returns_60$`Mkt-RF`,
                             monthly_returns_60$SMB,
                             monthly_returns_60$HML)))
X.3 <-  cbind(ones, monthly_returns_60$`Mkt-RF`, monthly_returns_60$SMB, monthly_returns_60$HML)
b_hat.3 <-  solve(t(X.3) %*% (X.3)) %*% t(X.3) %*% portfolio_ma
E_hat.3 <-  portfolio_ma - X.3 %*% b_hat.3
b_hat.3 <-  as.matrix(b_hat.3[-1, ])
diagD_hat.3 <-  diag(t(E_hat.3) %*% E_hat.3)/(N-4)
cov_3f.3 = t(b_hat.3) %*% sigF3 %*% b_hat.3 + diag(diagD_hat.3)
cov_3f.3
##              SPY          QQQ          EEM          IWM          EFA
## SPY 0.0027966375 0.0030819544 0.0021149594 0.0032150646 0.0024488147
## QQQ 0.0030819544 0.0039971152 0.0022310968 0.0034372722 0.0025685597
## EEM 0.0021149594 0.0022310968 0.0030889215 0.0028566205 0.0019560003
## IWM 0.0032150646 0.0034372722 0.0028566205 0.0047567735 0.0030050405
## EFA 0.0024488147 0.0025685597 0.0019560003 0.0030050405 0.0027367510
## TLT 0.0004774897 0.0009287771 0.0001633524 0.0002278039 0.0002333281
## IYR 0.0026276838 0.0028521353 0.0020722054 0.0031995815 0.0023538265
## GLD 0.0005383281 0.0007015082 0.0002522824 0.0002771607 0.0003887510
##              TLT          IYR          GLD
## SPY 0.0004774897 0.0026276838 0.0005383281
## QQQ 0.0009287771 0.0028521353 0.0007015082
## EEM 0.0001633524 0.0020722054 0.0002522824
## IWM 0.0002278039 0.0031995815 0.0002771607
## EFA 0.0002333281 0.0023538265 0.0003887510
## TLT 0.0023114617 0.0003576503 0.0002731635
## IYR 0.0003576503 0.0035976986 0.0004432168
## GLD 0.0002731635 0.0004432168 0.0018340873
#Find MVP weights
ff3_model <- MVP_sim(cov_3f.3)
ff3_model
##          Weight
## SPY  0.20731603
## QQQ -0.36537733
## EEM  0.18359726
## IWM -0.04233677
## EFA  0.22474296
## TLT  0.35918050
## IYR  0.05991173
## GLD  0.37296563

7. You can invest in the 8-portfolio in 2024/03 based on the optimal weights of MVP from question 5 and 6. What are the realized portfolio returns in the March of 2024 using the weights from question 5 and 6?

march_return <- monthly_returns['2024-03-28']
capm_return <- march_return %*% capm_model
capm_return <- as.data.frame(capm_return)
colnames(capm_return) <- "Return"
capm_return <- capm_return %>% mutate(Return = scales::percent(Return, accuracy = 0.001))
capm_return %>% kbl(format = "html", caption = "Portfolio Return in March using CAMP Model")
Portfolio Return in March using CAMP Model
Return
4.794%
ff3_return <- march_return %*% ff3_model
ff3_return <- as.data.frame(ff3_return)
colnames(ff3_return) <- "Return"
ff3_return <- ff3_return %>% mutate(Return = scales::percent(Return, accuracy = 0.001))
ff3_return %>% kbl(format = "html", caption = "Portfolio Return in March using Fama-French Model")
Portfolio Return in March using Fama-French Model
Return
4.949%