DATA

#Define the symbols we want to take 
symbols <- c("SPY", "QQQ", "EEM", "IWM", "EFA", "TLT", "IYR", "GLD")

#Create a portfolio variable named portfolioPrices with undefined value
portfolioPrices <- NULL

#Extract data from yahoo finance and feed the data in portfolioPrices
for (symbol in symbols){
  portfolioPrices <- cbind(portfolioPrices,
                           getSymbols.yahoo(symbol, from  = '2018-01-01', to = '2022-12-31', auto.assign = FALSE)[, 6])
}

#rename the data according to symbols
colnames(portfolioPrices) <- symbols
#Change data from daily to weekly
prices_weekly <- to.weekly(portfolioPrices, indexAt = "last", OHLC = FALSE)

#Change data from daily to monthly
prices_monthly <- to.monthly(portfolioPrices, indexAt = "last", OHLC = FALSE)

#Calculate daily return
asset_returns_day_xts <- na.omit(Return.calculate(portfolioPrices))

#Calculate weekly retun
asset_returns_wk_xts <- na.omit(Return.calculate(prices_weekly))

#Calculate monthly return
asset_returns_mon_xts <- na.omit(Return.calculate(prices_monthly))

head(asset_returns_day_xts)
##                     SPY           QQQ          EEM           IWM           EFA
## 2018-01-03  0.006325273  9.716766e-03  0.009581402  0.0010398241  0.0048003988
## 2018-01-04  0.004214646  1.749540e-03  0.004951427  0.0026612984  0.0109595857
## 2018-01-05  0.006664274  1.004307e-02  0.008622480  0.0020715514  0.0055594899
## 2018-01-08  0.001828810  3.890712e-03  0.000000000  0.0015506098 -0.0002763004
## 2018-01-09  0.002263371  6.150099e-05 -0.001628333 -0.0013544725  0.0011058732
## 2018-01-10 -0.001529853 -2.337672e-03 -0.006320156  0.0001289817 -0.0019333535
##                      TLT          IYR           GLD
## 2018-01-03  0.0047808494 -0.001612659 -0.0026368504
## 2018-01-04 -0.0001579994 -0.015658225  0.0051273786
## 2018-01-05 -0.0028560018  0.001010036 -0.0010361649
## 2018-01-08 -0.0006363493  0.005675368 -0.0001596128
## 2018-01-09 -0.0133724542 -0.011537594 -0.0046284751
## 2018-01-10 -0.0012100966 -0.012179500  0.0024051585
head(asset_returns_wk_xts)
##                     SPY         QQQ          EEM          IWM          EFA
## 2018-01-12  0.016458072  0.01587214  0.007734559  0.021771671  0.015895050
## 2018-01-19  0.008959618  0.01124657  0.018784049  0.002781799  0.008571218
## 2018-01-26  0.022003244  0.02759433  0.032514000  0.006305049  0.015108794
## 2018-02-02 -0.038837006 -0.03697416 -0.058179781 -0.036152665 -0.035880296
## 2018-02-09 -0.050644693 -0.05169783 -0.053618996 -0.045894926 -0.054583238
## 2018-02-16  0.044397794  0.05675839  0.067212780  0.044763993  0.041259696
##                     TLT          IYR          GLD
## 2018-01-12 -0.009466238 -0.029385746  0.013005643
## 2018-01-19 -0.011724976  0.006496791 -0.004253315
## 2018-01-26  0.004306736  0.016911750  0.013051805
## 2018-02-02 -0.030431383 -0.029325626 -0.013117887
## 2018-02-09 -0.013714564 -0.041590639 -0.012817492
## 2018-02-16  0.006528729  0.024290652  0.025567064
head(asset_returns_mon_xts)
##                     SPY         QQQ          EEM          IWM          EFA
## 2018-02-28 -0.036360846 -0.01292810 -0.058984954 -0.038436938 -0.048347869
## 2018-03-29 -0.027410207 -0.04078836  0.005414521  0.012175270 -0.008396242
## 2018-04-30  0.005168179  0.00505834 -0.028169096  0.009813641  0.015212459
## 2018-05-31  0.024309240  0.05672928 -0.026214955  0.061635707 -0.018942686
## 2018-06-29  0.005750860  0.01145062 -0.045456687  0.006143769 -0.015840835
## 2018-07-31  0.037046175  0.02796394  0.035310431  0.016490402  0.028520013
##                     TLT          IYR          GLD
## 2018-02-28 -0.030414707 -0.066572865 -0.020759902
## 2018-03-29  0.028596981  0.037718868  0.006320007
## 2018-04-30 -0.020881499  0.002252384 -0.009539745
## 2018-05-31  0.020043985  0.033712624 -0.011959209
## 2018-06-29  0.006457875  0.040594716 -0.036149448
## 2018-07-31 -0.014368740  0.008314390 -0.022418910

Question1 The global minimum variance portfolio in terms of weekly asset returns

#Find the covariance matrix 
cov_w <- cov(asset_returns_wk_xts)

#Create the 8x1 matrix with value = 1
one <- rep(1,8)
one_81 <- matrix(one,ncol=1) #8x1

#According to the formula to calculate GMVP, we denote a_w as the numerator and b_w as the denominator
a_w <- inv(cov_w)%*%one_81 # 8x8 x 8x1 = 8x1
b_w <- t(one_81)%*%inv(cov_w)%*%one_81 # 1x8 x 8x8 x 8x1 = 1x1

#Calculate GMVP
mvp_w <- a_w/as.vector(b_w)

#Format the table
colnames(mvp_w) <- "Weight"
mvp_w <- data.frame(mvp_w) %>% 
         kbl(format = "html", caption = "GMVP (weekly return)") %>%
         row_spec(row = 0, bold = TRUE, color = "black", background = "#FF9999") %>%
         kable_styling(bootstrap_options = "striped", full_width = F, position = "center")
mvp_w
GMVP (weekly return)
Weight
SPY 0.9920217
QQQ -0.4595039
EEM 0.1668411
IWM -0.0741901
EFA -0.1213652
TLT 0.4855628
IYR -0.2326821
GLD 0.2433156
#Find the covariance matrix 
cov_m <- cov(asset_returns_mon_xts)

#According to the formula to calculate GMVP, we denote a_w as the numerator and b_w as the denominator
a_m <- inv(cov_m)%*%one_81 # 8x8 x 8x1 = 8x1
b_m <- t(one_81)%*%inv(cov_m)%*%one_81 # 1x8 x 8x8 x 8x1 = 1x1

#Calculate GMVP
mvp_m <- a_m/as.vector(b_m)

#Format the table
colnames(mvp_m) <- "Weight"
mvp_m <- data.frame(mvp_m) %>% 
         kbl(format = "html", caption = "GMVP (monthly return)") %>%
         row_spec(row = 0, bold = TRUE, color = "black", background ="#FF9999") %>%
         kable_styling(bootstrap_options = "striped", full_width = F, position = "center")
mvp_m
GMVP (monthly return)
Weight
SPY 1.1924447
QQQ -0.7673211
EEM 0.0189746
IWM 0.1903908
EFA -0.1510369
TLT 0.5703820
IYR -0.3098996
GLD 0.2560654

Question2 Portfolio with annual return equal 0.045 with weekly data

#Calculate the mean return according to symbol
mean_w <-colMeans(asset_returns_wk_xts) #1x8 

#We use Lagrangian function to solve the problem. Finally, we have the function A*x=b0, with x is the portfolio weight, A and b0 is denoted as:
A_w <-rbind(2*cov_w,mean_w,t(one_81)) 
A_w <- cbind(A_w, rbind(t(tail(A_w, 2)), matrix(0, 2, 2))) #8x8 
b0_w <- c(rep(0, ncol(asset_returns_wk_xts)), 0.045/52, 1) #1x8
#0.045/52 is the weekly return

#Calculate the portfolio weight
x_w <- solve(A_w,b0_w)
port_w <- as.matrix(x_w[1:8])

#Format the table
colnames(port_w) <- "Weight"
port_w <- data.frame(port_w) %>% 
         kbl(format = "html", caption = "Portfolio with minimum risk and annual return at 4.5% (weekly return)") %>%
         row_spec(row = 0, bold = TRUE, color = "black", background = "#FF9999") %>%
         kable_styling(bootstrap_options = "striped", full_width = F, position = "center")
port_w
Portfolio with minimum risk and annual return at 4.5% (weekly return)
Weight
SPY 1.0759032
QQQ -0.4015925
EEM 0.0884017
IWM -0.0962362
EFA -0.1668217
TLT 0.4265158
IYR -0.2435871
GLD 0.3174168

Find Annual return equal 0.045 with monthly data

#Calculate the mean return according to symbol
mean_m <-colMeans(asset_returns_mon_xts) #1x8 

#We use Lagrangian function to solve the problem. Finally, we have the function A*x=b0, with x is the portfolio weight, A and b0 is denoted as:
A_m <-rbind(2*cov_m,mean_m,t(one_81))
A_m <- cbind(A_m, rbind(t(tail(A_m, 2)), matrix(0, 2, 2))) #8x8 
b0_m <- c(rep(0, ncol(asset_returns_mon_xts)), 0.045/12, 1) #1x8 
#0.045/12 is the monthly return

#Calculate the portfolio weight
x_m <- solve(A_m,b0_m)
port_m <- as.matrix(x_m[1:8])

#Format the table
colnames(port_m) <- "Weight"
port_m <- data.frame(port_m) %>% 
         kbl(format = "html", caption = "Portfolio with minimum risk and annual return at 4.5% (monthly return)") %>%
         row_spec(row = 0, bold = TRUE, color = "black", background = "#FF9999") %>%
         kable_styling(bootstrap_options = "striped", full_width = F, position = "center")
port_m
Portfolio with minimum risk and annual return at 4.5% (monthly return)
Weight
SPY 1.3335636
QQQ -0.7064488
EEM -0.0449025
IWM 0.1495403
EFA -0.2471782
TLT 0.4885663
IYR -0.3156004
GLD 0.3424595

Question3 Find Tangency Portfolio with weekly data

#The tangency portfolio is the portfolio that has largest sharpe ratio, by using Lagrangian function we have the formula following:
nume_t_w <- inv(cov_w)%*%mean_w # 8x8 x 8x1 = 8x1
deno_t_w <- t(one_81)%*%nume_t_w # 1x8 x 8x1

#Calculate the tangency portfolio
tangency_w <- nume_t_w/as.vector(deno_t_w)

#Format the table
colnames(tangency_w) <- "Weight"
tangency_w <- data.frame(tangency_w) %>% 
         kbl(format = "html", caption = "Tangency Portfolio with weekly data") %>%
         row_spec(row = 0, bold = TRUE, color = "black", background = "#FF9999") %>%
         kable_styling(bootstrap_options = "striped", full_width = F, position = "center")
tangency_w
Tangency Portfolio with weekly data
Weight
SPY 2.8905966
QQQ 0.8512640
EEM -1.6085584
IWM -0.5731829
EFA -1.1502298
TLT -0.8509067
IYR -0.4795051
GLD 1.9205223

Find Tangency Portfolio with monthly data

#The tangency portfolio is the portfolio that has largest sharpe ratio, by using Lagrangian function we have the formula following:
nume_t_m <- inv(cov_m)%*%mean_m # 8x8 x 8x1 = 8x1
deno_t_m <- t(one_81)%*%nume_t_m # 1x8 x 8x1

#Calculate the tangency portfolio
tangency_m <- nume_t_m/as.vector(deno_t_m)

#Format the table
colnames(tangency_m) <- "Weight"
tangency_m <- data.frame(tangency_m) %>% 
         kbl(format = "html", caption = "Tangency Portfolio with weekly data") %>%
         row_spec(row = 0, bold = TRUE, color = "black", background = "#FF9999") %>%
         kable_styling(bootstrap_options = "striped", full_width = F, position = "center")
tangency_m
Tangency Portfolio with weekly data
Weight
SPY 4.2186811
QQQ 0.5380599
EEM -1.3508424
IWM -0.6856308
EFA -2.2127461
TLT -1.1841224
IYR -0.4321495
GLD 2.1087502

Question4 Find covariance matrix

berndt <- read_excel("berndt.xlsx")
ber_port <- berndt %>% select(, -MARKET, -RKFREE)
ber_market <- berndt %>% select(MARKET, RKFREE) %>% mutate(Market = MARKET - RKFREE) 
ber_market <- ber_market%>% select(Market)
#According to the formula in the class, we define Y= BX while Y is the portfolio_return matrix (120x15 - 15 assets in 120 months), B is the matrix that consists of a in the first column and B in the second column:
one_120 <- rep(1,120)
X <- as.matrix(cbind(one_120, ber_market)) # 120x2
Y <- as.matrix(ber_port) # 120x15

#We calculate the b_hat:
b_hat = solve(t(X)%*%X)%*%t(X) %*% Y #2x15 : first row- alpha, second row - beta

#The e_hat is equal the difference between actual return and return derived from the formula:
E_hat = Y - X %*% b_hat #120x15
head(E_hat,6) 
##           CITCRP         CONED      CONTIL      DATGEN         DEC       DELTA
## [1,] -0.08906182 -0.0924325479 -0.08644938 -0.03294113 -0.07166573 -0.01200381
## [2,] -0.02947098 -0.0213220221  0.03962148 -0.10233449 -0.08098502 -0.04367536
## [3,]  0.02222799  0.0001459493 -0.02322229  0.01692842 -0.04144488  0.04005781
## [4,]  0.08137923 -0.0280423719  0.14407347  0.11922277  0.10229784  0.11357564
## [5,] -0.04312626 -0.0373788404  0.02232575 -0.01165793 -0.02788962 -0.06925976
## [6,] -0.00126376  0.0159743906 -0.05395791 -0.02491578 -0.03617703  0.01394154
##            GENMIL       GERBER         IBM        MOBIL       PANAM
## [1,] -0.100413553 -0.028965238 -0.01280576 -0.021675972  0.06312884
## [2,]  0.001973487  0.144900665 -0.05166925 -0.031704502 -0.07498803
## [3,] -0.049582534 -0.075756917 -0.08963000  0.006102306  0.15303258
## [4,]  0.015865982 -0.044052752  0.09732727  0.024616945  0.04828272
## [5,]  0.031860393 -0.004401685 -0.05238371 -0.066068798  0.03852208
## [6,] -0.007140637  0.014969963 -0.01116196 -0.055338490  0.01944396
##              PSNH       TANDY      TEXACO         WEYER
## [1,]  0.008151819 -0.04037246 -0.03121181 -0.0790751380
## [2,] -0.020345243 -0.02681935 -0.02066688 -0.1429243732
## [3,]  0.022349580  0.05968252 -0.01983395  0.0436777086
## [4,] -0.014444627 -0.02327918 -0.04296475  0.0927777034
## [5,]  0.011764204  0.09376762 -0.07426696 -0.0853085904
## [6,]  0.037351739 -0.03333676 -0.03363874 -0.0002054953
# Excluding constant term and keep only beta in b_hat
b_hat = as.matrix(b_hat[-1,])

#Calculate the covariance of ei and put them in diagonal matrix
diagD_hat = diag(t(E_hat) %*% E_hat)/(120-2) 
diag(diagD_hat) 
##              [,1]        [,2]       [,3]       [,4]        [,5]        [,6]
##  [1,] 0.004526617 0.000000000 0.00000000 0.00000000 0.000000000 0.000000000
##  [2,] 0.000000000 0.002511069 0.00000000 0.00000000 0.000000000 0.000000000
##  [3,] 0.000000000 0.000000000 0.02039461 0.00000000 0.000000000 0.000000000
##  [4,] 0.000000000 0.000000000 0.00000000 0.01140139 0.000000000 0.000000000
##  [5,] 0.000000000 0.000000000 0.00000000 0.00000000 0.006537662 0.000000000
##  [6,] 0.000000000 0.000000000 0.00000000 0.00000000 0.000000000 0.008161795
##  [7,] 0.000000000 0.000000000 0.00000000 0.00000000 0.000000000 0.000000000
##  [8,] 0.000000000 0.000000000 0.00000000 0.00000000 0.000000000 0.000000000
##  [9,] 0.000000000 0.000000000 0.00000000 0.00000000 0.000000000 0.000000000
## [10,] 0.000000000 0.000000000 0.00000000 0.00000000 0.000000000 0.000000000
## [11,] 0.000000000 0.000000000 0.00000000 0.00000000 0.000000000 0.000000000
## [12,] 0.000000000 0.000000000 0.00000000 0.00000000 0.000000000 0.000000000
## [13,] 0.000000000 0.000000000 0.00000000 0.00000000 0.000000000 0.000000000
## [14,] 0.000000000 0.000000000 0.00000000 0.00000000 0.000000000 0.000000000
## [15,] 0.000000000 0.000000000 0.00000000 0.00000000 0.000000000 0.000000000
##             [,7]        [,8]        [,9]       [,10]      [,11]      [,12]
##  [1,] 0.00000000 0.000000000 0.000000000 0.000000000 0.00000000 0.00000000
##  [2,] 0.00000000 0.000000000 0.000000000 0.000000000 0.00000000 0.00000000
##  [3,] 0.00000000 0.000000000 0.000000000 0.000000000 0.00000000 0.00000000
##  [4,] 0.00000000 0.000000000 0.000000000 0.000000000 0.00000000 0.00000000
##  [5,] 0.00000000 0.000000000 0.000000000 0.000000000 0.00000000 0.00000000
##  [6,] 0.00000000 0.000000000 0.000000000 0.000000000 0.00000000 0.00000000
##  [7,] 0.00393017 0.000000000 0.000000000 0.000000000 0.00000000 0.00000000
##  [8,] 0.00000000 0.005930261 0.000000000 0.000000000 0.00000000 0.00000000
##  [9,] 0.00000000 0.000000000 0.002540858 0.000000000 0.00000000 0.00000000
## [10,] 0.00000000 0.000000000 0.000000000 0.004107716 0.00000000 0.00000000
## [11,] 0.00000000 0.000000000 0.000000000 0.000000000 0.01498815 0.00000000
## [12,] 0.00000000 0.000000000 0.000000000 0.000000000 0.00000000 0.01187757
## [13,] 0.00000000 0.000000000 0.000000000 0.000000000 0.00000000 0.00000000
## [14,] 0.00000000 0.000000000 0.000000000 0.000000000 0.00000000 0.00000000
## [15,] 0.00000000 0.000000000 0.000000000 0.000000000 0.00000000 0.00000000
##            [,13]      [,14]       [,15]
##  [1,] 0.00000000 0.00000000 0.000000000
##  [2,] 0.00000000 0.00000000 0.000000000
##  [3,] 0.00000000 0.00000000 0.000000000
##  [4,] 0.00000000 0.00000000 0.000000000
##  [5,] 0.00000000 0.00000000 0.000000000
##  [6,] 0.00000000 0.00000000 0.000000000
##  [7,] 0.00000000 0.00000000 0.000000000
##  [8,] 0.00000000 0.00000000 0.000000000
##  [9,] 0.00000000 0.00000000 0.000000000
## [10,] 0.00000000 0.00000000 0.000000000
## [11,] 0.00000000 0.00000000 0.000000000
## [12,] 0.00000000 0.00000000 0.000000000
## [13,] 0.01121942 0.00000000 0.000000000
## [14,] 0.00000000 0.00464578 0.000000000
## [15,] 0.00000000 0.00000000 0.004133323
# Covariance matrix by single factor model 
cov_sfm <- as.numeric(var(ber_market))*b_hat%*%t(b_hat) + diag(diagD_hat)  #15x15

The Global Minimum Variance Portfolio

#Create the 15x1 matrix with value = 1
one_15 <- rep(1,15)
one_15_1 <- matrix(one_15,ncol=1)

#According to the formula to calculate GMVP, we denote a_sfm as the numerator and b_sfm as the denominator
a_sfm <- inv(cov_sfm)%*%one_15_1 # 15x15 x 15x1 = 15x1
b_sfm <- t(one_15_1)%*%inv(cov_sfm)%*%one_15_1 # 1x1 5x 15x15 x 15x1 = 1x1

#Calculate the GMVP
mvp_sfm <- a_sfm/as.vector(b_sfm)

#Format the table
colnames(mvp_sfm) <- "Weight"
mvp_sfm <- data.frame(mvp_sfm) %>% 
         kbl(format = "html", caption = "GMVP from single index model") %>%
         row_spec(row = 0, bold = TRUE, color = "black", background = "#FF9999") %>%
         kable_styling(bootstrap_options = "striped", full_width = F, position = "center")
mvp_sfm
GMVP from single index model
Weight
CITCRP 0.0443133
CONED 0.3755073
CONTIL 0.0057706
DATGEN -0.0236873
DEC -0.0050185
DELTA 0.0526752
GENMIL 0.1816517
GERBER 0.0428599
IBM 0.1859635
MOBIL 0.0338142
PANAM 0.0075571
PSNH 0.0662851
TANDY -0.0262830
TEXACO 0.0581522
WEYER 0.0004386