library(readxl)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(lubridate)
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
library(timetk)
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2
## ──
## ✔ ggplot2 3.4.1     ✔ purrr   1.0.1
## ✔ tibble  3.2.1     ✔ stringr 1.5.0
## ✔ tidyr   1.3.0     ✔ forcats 1.0.0
## ✔ readr   2.1.4     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ lubridate::as.difftime() masks base::as.difftime()
## ✖ lubridate::date()        masks base::date()
## ✖ dplyr::filter()          masks stats::filter()
## ✖ lubridate::intersect()   masks base::intersect()
## ✖ dplyr::lag()             masks stats::lag()
## ✖ lubridate::setdiff()     masks base::setdiff()
## ✖ lubridate::union()       masks base::union()
library(tidyquant)
## Loading required package: PerformanceAnalytics
## Loading required package: xts
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## 
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
## 
## 
## ################################### WARNING ###################################
## # We noticed you have dplyr installed. 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 enter or source() into this session won't     #
## # work correctly.                                                             #
## #                                                                             #
## # All package code is unaffected because it is protected by the R namespace   #
## # mechanism.                                                                  #
## #                                                                             #
## # Set `options(xts.warn_dplyr_breaks_lag = FALSE)` to suppress this warning.  #
## #                                                                             #
## # You can 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.                                #
## ################################### WARNING ###################################
## 
## Attaching package: 'xts'
## 
## The following objects are masked from 'package:dplyr':
## 
##     first, last
## 
## 
## Attaching package: 'PerformanceAnalytics'
## 
## The following object is masked from 'package:graphics':
## 
##     legend
## 
## Loading required package: quantmod
## Loading required package: TTR
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
library(fBasics)
## 
## Attaching package: 'fBasics'
## 
## The following object is masked from 'package:TTR':
## 
##     volatility
## 
## The following objects are masked from 'package:PerformanceAnalytics':
## 
##     kurtosis, skewness
library(kableExtra)
## 
## Attaching package: 'kableExtra'
## 
## The following object is masked from 'package:dplyr':
## 
##     group_rows

Input Data for Q1-Q3

Extract 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
Calculate weekly and monthly returns using log returns
#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.006325147  9.716765e-03  0.009581399  0.0010396124  0.0047999683
## 2018-01-04  0.004214771  1.749640e-03  0.004951515  0.0026614054  0.0109597694
## 2018-01-05  0.006664270  1.004288e-02  0.008622577  0.0020715522  0.0055595453
## 2018-01-08  0.001828567  3.890906e-03  0.000000000  0.0015506077 -0.0002764859
## 2018-01-09  0.002263250  6.159949e-05 -0.001628514 -0.0013545769  0.0011058819
## 2018-01-10 -0.001529673 -2.337767e-03 -0.006319895  0.0001290869 -0.0019333032
##                      TLT          IYR           GLD
## 2018-01-03  0.0047812648 -0.001612653 -0.0026368517
## 2018-01-04 -0.0001583371 -0.015657899  0.0051273754
## 2018-01-05 -0.0028555972  0.001009584 -0.0010361629
## 2018-01-08 -0.0006363559  0.005675596 -0.0001596106
## 2018-01-09 -0.0133724465 -0.011537595 -0.0046284814
## 2018-01-10 -0.0012102388 -0.012179717  0.0024051631
head(asset_returns_wk_xts)
##                     SPY         QQQ          EEM          IWM          EFA
## 2018-01-12  0.016457826  0.01587213  0.007734391  0.021771565  0.015894808
## 2018-01-19  0.008959503  0.01124706  0.018784296  0.002781900  0.008571451
## 2018-01-26  0.022003724  0.02759365  0.032513830  0.006305149  0.015108797
## 2018-02-02 -0.038837524 -0.03697389 -0.058179868 -0.036152861 -0.035880529
## 2018-02-09 -0.050644406 -0.05169793 -0.053618740 -0.045894829 -0.054583118
## 2018-02-16  0.044397733  0.05675829  0.067212582  0.044763994  0.041259627
##                     TLT         IYR          GLD
## 2018-01-12 -0.009466376 -0.02938564  0.013005641
## 2018-01-19 -0.011725115  0.00649680 -0.004253316
## 2018-01-26  0.004306600  0.01691186  0.013051804
## 2018-02-02 -0.030430841 -0.02932574 -0.013117888
## 2018-02-09 -0.013714915 -0.04159034 -0.012817486
## 2018-02-16  0.006528512  0.02429009  0.025567060
head(asset_returns_mon_xts)
##                     SPY          QQQ          EEM          IWM         EFA
## 2018-02-28 -0.036360380 -0.012927725 -0.058985033 -0.038436941 -0.04834782
## 2018-03-29 -0.027410870 -0.040788170  0.005414438  0.012175598 -0.00839612
## 2018-04-30  0.005168559  0.005058039 -0.028169006  0.009813424  0.01521240
## 2018-05-31  0.024308862  0.056729381 -0.026214859  0.061635924 -0.01894275
## 2018-06-29  0.005751106  0.011450441 -0.045456886  0.006143667 -0.01584084
## 2018-07-31  0.037046359  0.027964126  0.035310534  0.016490501  0.02852021
##                     TLT          IYR          GLD
## 2018-02-28 -0.030414361 -0.066573040 -0.020759906
## 2018-03-29  0.028596251  0.037719050  0.006320008
## 2018-04-30 -0.020881294  0.002252511 -0.009539749
## 2018-05-31  0.020044490  0.033712265 -0.011959211
## 2018-06-29  0.006457591  0.040594503 -0.036149440
## 2018-07-31 -0.014368398  0.008314927 -0.022418912

Question 1:

Try to find the GMVP for these eight assets using the derived asset_returns data. —- Note that you have to compute optimal weights and GMVP returns using weekly and monthly asset returns.

1.1. Find GMVP 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)
#Sum of weight
sum(mvp_w)
## [1] 1
#Format the table
colnames(mvp_w) <- "Weight"
mvp_w <- data.frame(mvp_w) %>% 
         kbl(format = "html", caption = "Global Minimum Variance Portfolio (weekly return)") %>%
         row_spec(row = 0, bold = TRUE, color = "black", background = "#F9EBEA") %>%
         kable_styling(bootstrap_options = "striped", full_width = F, position = "center")
mvp_w
Global Minimum Variance Portfolio (weekly return)
Weight
SPY 0.9920161
QQQ -0.4594994
EEM 0.1668419
IWM -0.0741905
EFA -0.1213648
TLT 0.4855622
IYR -0.2326813
GLD 0.2433158

1.2. Find GMVP in terms of monthly asset returns

#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)
#Sum of weight
sum(mvp_m)
## [1] 1
#Format the table
colnames(mvp_m) <- "Weight"
mvp_m <- data.frame(mvp_m) %>% 
         kbl(format = "html", caption = "Global Minimum Variance Portfolio (monthly return)") %>%
         row_spec(row = 0, bold = TRUE, color = "black", background = "#F9EBEA") %>%
         kable_styling(bootstrap_options = "striped", full_width = F, position = "center")
mvp_m
Global Minimum Variance Portfolio (monthly return)
Weight
SPY 1.1924604
QQQ -0.7673292
EEM 0.0189775
IWM 0.1903891
EFA -0.1510422
TLT 0.5703838
IYR -0.3099006
GLD 0.2560611

Question 2:

Given the portfolio return is specified as 0.045 annual rate. Try to find the optimal weights for the minimum variance portfolio. You should use weekly and monthly asset returns to derive the solutions.

2.1. Find 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])
#Sum of weight
sum(port_w)
## [1] 1
#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 = "#F9EBEA") %>%
         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.0758978
QQQ -0.4015881
EEM 0.0884025
IWM -0.0962366
EFA -0.1668216
TLT 0.4265153
IYR -0.2435862
GLD 0.3174169

2.2. Find Portfolio with 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])
#Sum of weight
sum(port_m)
## [1] 1
#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 = "#F9EBEA") %>%
         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.3335777
QQQ -0.7064553
EEM -0.0449000
IWM 0.1495389
EFA -0.2471838
TLT 0.4885673
IYR -0.3156009
GLD 0.3424562

Question 3:

Find the tangency portfolio based on Q2. Risk-free rate is assumed to be zero. You should compute the tangency portfolio weights and its returns based on weekly monthly returns.

3.1. 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)
#Sum of weight
sum(tangency_w)
## [1] 1
#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 = "#F9EBEA") %>%
         kable_styling(bootstrap_options = "striped", full_width = F, position = "center")
tangency_w
Tangency Portfolio with weekly data
Weight
SPY 2.8905973
QQQ 0.8512665
EEM -1.6085566
IWM -0.5731809
EFA -1.1502360
TLT -0.8509063
IYR -0.4795046
GLD 1.9205207

3.2. 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)
#Sum of weight
sum(tangency_m)
## [1] 1
#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 = "#F9EBEA") %>%
         kable_styling(bootstrap_options = "striped", full_width = F, position = "center")
tangency_m
Tangency Portfolio with weekly data
Weight
SPY 4.2186546
QQQ 0.5380816
EEM -1.3508473
IWM -0.6856247
EFA -2.2127539
TLT -1.1841342
IYR -0.4321397
GLD 2.1087637

Question 4:

The attached file “berndt.xslx” contains monthly returns of 15 stocks, market index returns (MARKET), and risk-free monthly rate (RKFREE) for 120 months. Compute GMVP (global minimum variance portfolio) weights and its return by using the covariance derived from single index model.

4.1. Load the data

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)

4.2. Find covariance matrix

We have the single index model: Ri = a + B*X + ei where Ri is the stock return a is the expected excess return B is the sensitivity of the stock to the market X is the market excess return (Rm-rf) ei is the firm specific surprise Our goal is to find covariance matrix of return. To achieve the goal, we will define the beta (B) and the covarience of ei

#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

4.3. Find GMVP

#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)
#Sum of weight
sum(mvp_sfm)
## [1] 1
#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 = "#F9EBEA") %>%
         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