Load necessary libraries
#install.packages(x)
x<-c("quantmod", "tidyquant", "lubridate", "timetk", "purrr","tidyverse", "tibble", "readr", "xts", "PerformanceAnalytics", "magrittr", "dplyr")
lapply(x, require, character.only = TRUE)
## Loading required package: quantmod
## Loading required package: xts
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
## Loading required package: TTR
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
## Loading required package: tidyquant
## Loading required package: lubridate
##
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
## Loading required package: PerformanceAnalytics
##
## Attaching package: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
##
## legend
## Loading required package: timetk
## Loading required package: purrr
## Loading required package: tidyverse
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ stringr 1.5.0
## ✔ forcats 1.0.0 ✔ tibble 3.2.1
## ✔ ggplot2 3.4.2 ✔ tidyr 1.3.0
## ✔ readr 2.1.5
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::first() masks xts::first()
## ✖ dplyr::lag() masks stats::lag()
## ✖ dplyr::last() masks xts::last()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
## Loading required package: magrittr
##
##
## Attaching package: 'magrittr'
##
##
## The following object is masked from 'package:tidyr':
##
## extract
##
##
## The following object is masked from 'package:purrr':
##
## set_names
## [[1]]
## [1] TRUE
##
## [[2]]
## [1] TRUE
##
## [[3]]
## [1] TRUE
##
## [[4]]
## [1] TRUE
##
## [[5]]
## [1] TRUE
##
## [[6]]
## [1] TRUE
##
## [[7]]
## [1] TRUE
##
## [[8]]
## [1] TRUE
##
## [[9]]
## [1] TRUE
##
## [[10]]
## [1] TRUE
##
## [[11]]
## [1] TRUE
##
## [[12]]
## [1] TRUE
tickers <- c("SPY", "QQQ", "EEM", "IWM", "EFA", "TLT", "IYR", "GLD")
data = new.env()
getSymbols(tickers, src = 'yahoo', auto.assign = TRUE)
## [1] "SPY" "QQQ" "EEM" "IWM" "EFA" "TLT" "IYR" "GLD"
etf_data <- merge(Ad(SPY), Ad(QQQ),Ad(EEM), Ad(IWM),Ad(EFA),Ad(TLT),Ad(IYR),Ad(GLD))
colnames(etf_data) <- c("SPY", "QQQ", "EEM", "IWM", "EFA", "TLT", "IYR", "GLD")
head(etf_data)
## SPY QQQ EEM IWM EFA TLT IYR GLD
## 2007-01-03 101.5366 37.48681 27.08176 61.77275 44.58430 52.96931 44.11396 62.28
## 2007-01-04 101.7520 38.19769 26.70778 61.93874 44.45692 53.29048 44.10344 61.65
## 2007-01-05 100.9405 38.01564 25.92689 60.64259 43.78976 53.05853 43.41967 60.17
## 2007-01-08 101.4073 38.04165 26.11506 60.40549 43.85043 53.15369 43.40916 60.48
## 2007-01-09 101.3211 38.23237 25.53176 60.97454 43.89288 53.15369 43.91935 60.85
## 2007-01-10 101.6587 38.68318 25.47295 61.44875 43.55930 52.91580 44.61891 60.59
etf_data.xts <- xts(etf_data)
tail(etf_data)
## SPY QQQ EEM IWM EFA TLT IYR GLD
## 2024-05-31 527.37 450.71 41.79 205.77 81.18 90.142 86.67 215.30
## 2024-06-03 527.80 453.13 42.23 204.61 81.41 91.600 86.43 217.22
## 2024-06-04 528.39 454.37 41.64 201.97 81.31 92.670 87.20 215.27
## 2024-06-05 534.67 463.53 42.31 205.06 81.88 93.350 86.99 217.82
## 2024-06-06 534.66 463.37 42.52 203.59 82.16 93.210 87.13 219.43
## 2024-06-07 534.01 462.96 42.04 201.20 81.27 91.500 86.43 211.60
WEEKLY - Only count the last day of the week. exclude na values
weekly_returns <- to.weekly(etf_data.xts, indexAt = "last", OHLC = FALSE)
etf_weekly_returns_log <- na.omit(Return.calculate(weekly_returns, method = "log"))
head(etf_weekly_returns_log)
## SPY QQQ EEM IWM EFA
## 2007-01-12 0.019029577 0.032752846 0.015036649 0.0289017080 0.0123883374
## 2007-01-19 -0.002936382 -0.025481921 0.006591342 -0.0155672319 0.0080392257
## 2007-01-26 -0.004842907 -0.013676681 0.004870716 0.0039785460 -0.0042160675
## 2007-02-02 0.018680196 0.013450422 0.018903425 0.0275406501 0.0179627522
## 2007-02-09 -0.006026066 -0.006360845 -0.010457567 0.0007474486 -0.0009374423
## 2007-02-16 0.012359340 0.018738163 0.033086651 0.0106511194 0.0230441461
## TLT IYR GLD
## 2007-01-12 -0.0132020364 0.0421051470 0.032698680
## 2007-01-19 -0.0005682573 0.0197801019 0.013262188
## 2007-01-26 -0.0123489856 0.0222955061 0.018401057
## 2007-02-02 0.0073938620 0.0242034729 0.001712739
## 2007-02-09 0.0049191868 0.0056365015 0.028222793
## 2007-02-16 0.0114599576 -0.0006485655 0.003623160
monthly_returns <- to.monthly(etf_data.xts, indexAt = "last", OHLC = FALSE)
etf_monthly_returns_log <- na.omit(Return.calculate(monthly_returns, method = "log"))
head(etf_monthly_returns_log)
## SPY QQQ EEM IWM EFA
## 2007-02-28 -0.01981286 -0.016933826 -0.03290651 -0.006575194 -0.001213080
## 2007-03-30 0.01152271 0.005234768 0.05197121 0.009754944 0.028582794
## 2007-04-30 0.04334242 0.054320806 0.03657594 0.016106413 0.036798322
## 2007-05-31 0.03335746 0.031061829 0.04940452 0.042791632 0.023348012
## 2007-06-29 -0.01472828 0.004781240 0.03612274 -0.014486914 -0.003213386
## 2007-07-31 -0.03181104 -0.001471669 0.00711632 -0.072532081 -0.023171218
## TLT IYR GLD
## 2007-02-28 0.033327736 -0.036432416 0.02513271
## 2007-03-30 -0.017149405 -0.025597000 -0.01119367
## 2007-04-30 0.009009019 0.002928296 0.02032741
## 2007-05-31 -0.023409905 0.001519735 -0.02337429
## 2007-06-29 -0.010186149 -0.091133257 -0.01956775
## 2007-07-31 0.032651998 -0.095052180 0.02337496
fama <- read_csv("F-F_Research_Data_Factors.CSV")
## Rows: 1172 Columns: 5
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## dbl (5): Date, Mkt-RF, SMB, HML, RF
##
## ℹ 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(fama)
## # A tibble: 6 × 5
## Date `Mkt-RF` SMB HML RF
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 192607 2.96 -2.56 -2.43 0.22
## 2 192608 2.64 -1.17 3.82 0.25
## 3 192609 0.36 -1.4 0.13 0.23
## 4 192610 -3.24 -0.09 0.7 0.32
## 5 192611 2.53 -0.1 -0.51 0.31
## 6 192612 2.62 -0.03 -0.05 0.28
Format the data frame
colnames(fama) <- paste(c("date","MKT-RF","SMB","HML","RF"))
fama.digit <- fama %>% mutate(date = as.character(date))%>%
mutate(date=ymd(parse_date(date,format="%Y%m"))) %>%
mutate(date=rollback(date))
head(fama.digit)
## # A tibble: 6 × 5
## date `MKT-RF` SMB HML RF
## <date> <dbl> <dbl> <dbl> <dbl>
## 1 1926-06-30 2.96 -2.56 -2.43 0.22
## 2 1926-07-31 2.64 -1.17 3.82 0.25
## 3 1926-08-31 0.36 -1.4 0.13 0.23
## 4 1926-09-30 -3.24 -0.09 0.7 0.32
## 5 1926-10-31 2.53 -0.1 -0.51 0.31
## 6 1926-11-30 2.62 -0.03 -0.05 0.28
fama.digit.xts <- xts(fama.digit[,-1],order.by=as.Date(fama.digit$date))
head(fama.digit.xts)
## MKT-RF SMB HML RF
## 1926-06-30 2.96 -2.56 -2.43 0.22
## 1926-07-31 2.64 -1.17 3.82 0.25
## 1926-08-31 0.36 -1.40 0.13 0.23
## 1926-09-30 -3.24 -0.09 0.70 0.32
## 1926-10-31 2.53 -0.10 -0.51 0.31
## 1926-11-30 2.62 -0.03 -0.05 0.28
etf_monthly_returns_tibble <- as_tibble(etf_monthly_returns_log, rownames = "date")
etf_monthly_returns_tibble <- etf_monthly_returns_tibble %>%
mutate(date = as.Date(date))
merge_data_tibble <- left_join(fama.digit, etf_monthly_returns_tibble, by = "date")
tail(merge_data_tibble)
## # A tibble: 6 × 13
## date `MKT-RF` SMB HML RF SPY QQQ EEM IWM EFA
## <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2023-08-31 -5.24 -2.51 1.52 0.43 -0.0164 -0.0149 -0.0686 -0.0522 -0.0401
## 2 2023-09-30 -3.19 -3.87 0.19 0.47 NA NA NA NA NA
## 3 2023-10-31 8.84 -0.02 1.64 0.44 -0.0219 -0.0209 -0.0335 -0.0716 -0.0294
## 4 2023-11-30 4.87 6.34 4.93 0.43 0.0874 0.103 0.0750 0.0880 0.0790
## 5 2023-12-31 0.71 -5.09 -2.38 0.47 NA NA NA NA NA
## 6 2024-01-31 5.06 -0.24 -3.48 0.42 0.0158 0.0180 -0.0463 -0.0398 -0.00452
## # ℹ 3 more variables: TLT <dbl>, IYR <dbl>, GLD <dbl>
calc_data <- merge_data_tibble[merge_data_tibble$date>="2010-02-01"&merge_data_tibble$date<="2015-01-01",]
head(calc_data)
## # A tibble: 6 × 13
## date `MKT-RF` SMB HML RF SPY QQQ EEM IWM EFA
## <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2010-02-28 6.31 1.48 2.21 0.01 NA NA NA NA NA
## 2 2010-03-31 2 4.87 2.89 0.01 0.0591 0.0743 0.0780 0.0791 0.0619
## 3 2010-04-30 -7.89 0.09 -2.44 0.01 0.0154 0.0222 -0.00166 0.0552 -0.0284
## 4 2010-05-31 -5.57 -1.82 -4.7 0.01 NA NA NA NA NA
## 5 2010-06-30 6.93 0.2 -0.31 0.01 -0.0531 -0.0616 -0.0141 -0.0806 -0.0208
## 6 2010-07-31 -4.77 -3 -1.9 0.01 NA NA NA NA NA
## # ℹ 3 more variables: TLT <dbl>, IYR <dbl>, GLD <dbl>
#replace NA values with 0
columns_to_fill <- c("SPY", "QQQ", "EEM", "IWM", "EFA", "TLT", "IYR", "GLD")
calc_data_fill <- calc_data %>%
mutate_at(vars(one_of(columns_to_fill)), ~replace(., is.na(.), 0))
head(calc_data_fill)
## # A tibble: 6 × 13
## date `MKT-RF` SMB HML RF SPY QQQ EEM IWM EFA
## <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2010-02-28 6.31 1.48 2.21 0.01 0 0 0 0 0
## 2 2010-03-31 2 4.87 2.89 0.01 0.0591 0.0743 0.0780 0.0791 0.0619
## 3 2010-04-30 -7.89 0.09 -2.44 0.01 0.0154 0.0222 -0.00166 0.0552 -0.0284
## 4 2010-05-31 -5.57 -1.82 -4.7 0.01 0 0 0 0 0
## 5 2010-06-30 6.93 0.2 -0.31 0.01 -0.0531 -0.0616 -0.0141 -0.0806 -0.0208
## 6 2010-07-31 -4.77 -3 -1.9 0.01 0 0 0 0 0
## # ℹ 3 more variables: TLT <dbl>, IYR <dbl>, GLD <dbl>
spy_rf <- calc_data_fill$SPY-calc_data_fill$RF
qqq_rf <- calc_data_fill$QQQ-calc_data_fill$RF
eem_rf <- calc_data_fill$EEM-calc_data_fill$RF
iwm_rf <- calc_data_fill$IWM-calc_data_fill$RF
efa_rf <- calc_data_fill$EFA-calc_data_fill$RF
tlt_rf <- calc_data_fill$TLT-calc_data_fill$RF
iyr_rf <- calc_data_fill$IYR-calc_data_fill$RF
gld_rf <- calc_data_fill$GLD-calc_data_fill$RF
y <- cbind(spy_rf,qqq_rf,eem_rf,iwm_rf,efa_rf,tlt_rf,iyr_rf,gld_rf)
n <- nrow(y)
one.vec <- rep(1,n)
x <- cbind(one.vec,calc_data_fill$`MKT-RF`)
x.mat <- as.matrix(x)
beta <- solve(t(x)%*%x)%*%t(x)%*%y
beta
## spy_rf qqq_rf eem_rf iwm_rf efa_rf
## one.vec 0.0058412542 0.0061279844 -0.0010377749 0.007427027 -0.0001841714
## -0.0009667541 -0.0003856413 -0.0007765374 -0.002014580 -0.0002073968
## tlt_rf iyr_rf gld_rf
## one.vec 0.002284839 0.006201665 0.001221924
## 0.001443861 -0.001060760 -0.002852133
#residual
e.hat <- y - x%*%beta
res.var <- diag(t(e.hat)%*%e.hat)/(n-2)
d <- diag(res.var);d
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 0.001066511 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000
## [2,] 0.000000000 0.001452147 0.000000000 0.000000000 0.000000000 0.000000000
## [3,] 0.000000000 0.000000000 0.002852139 0.000000000 0.000000000 0.000000000
## [4,] 0.000000000 0.000000000 0.000000000 0.002282146 0.000000000 0.000000000
## [5,] 0.000000000 0.000000000 0.000000000 0.000000000 0.001823551 0.000000000
## [6,] 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.001182795
## [7,] 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000
## [8,] 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000
## [,7] [,8]
## [1,] 0.000000000 0.000000000
## [2,] 0.000000000 0.000000000
## [3,] 0.000000000 0.000000000
## [4,] 0.000000000 0.000000000
## [5,] 0.000000000 0.000000000
## [6,] 0.000000000 0.000000000
## [7,] 0.001480561 0.000000000
## [8,] 0.000000000 0.001726186
# covariance matrix single factor model
cov.mat <- var(merge_data_tibble$`MKT-RF`)*t(beta)%*%beta + d
cov.mat
## spy_rf qqq_rf eem_rf iwm_rf efa_rf
## spy_rf 2.066707e-03 1.031955e-03 -1.515404e-04 0.0012933914 -2.497405e-05
## qqq_rf 1.031955e-03 2.527841e-03 -1.729059e-04 0.0013207497 -2.991951e-05
## eem_rf -1.515404e-04 -1.729059e-04 2.900073e-03 -0.0001752793 1.004851e-05
## iwm_rf 1.293391e-03 1.320750e-03 -1.752793e-04 0.0039718090 -2.710650e-05
## efa_rf -2.497405e-05 -2.991951e-05 1.004851e-05 -0.0000271065 1.825746e-03
## tlt_rf 3.409745e-04 3.836069e-04 -9.964514e-05 0.0004011868 -2.055052e-05
## iyr_rf 1.062857e-03 1.096005e-03 -1.601294e-04 0.0013751696 -2.631167e-05
## gld_rf 2.823238e-04 2.450307e-04 2.701172e-05 0.0004228806 1.045652e-05
## tlt_rf iyr_rf gld_rf
## spy_rf 3.409745e-04 1.062857e-03 2.823238e-04
## qqq_rf 3.836069e-04 1.096005e-03 2.450307e-04
## eem_rf -9.964514e-05 -1.601294e-04 2.701172e-05
## iwm_rf 4.011868e-04 1.375170e-03 4.228806e-04
## efa_rf -2.055052e-05 -2.631167e-05 1.045652e-05
## tlt_rf 1.391230e-03 3.605976e-04 -3.783913e-05
## iyr_rf 3.605976e-04 2.610037e-03 3.025392e-04
## gld_rf -3.783913e-05 3.025392e-04 2.000888e-03
# mvp montly returns of 8 assest CAMP
one.vec2 <- rep(1,8)
top <- solve(cov.mat)%*%one.vec2
bot <- t(one.vec2)%*%top
mvp_capm <- top/as.numeric(bot)
mvp_capm
## [,1]
## spy_rf 0.0864944324
## qqq_rf 0.0587455476
## eem_rf 0.1544821254
## iwm_rf -0.0004280025
## efa_rf 0.2220970846
## tlt_rf 0.2554130590
## iyr_rf 0.0492478399
## gld_rf 0.1739479137
t <- dim(calc_data_fill)[1]
markets <- calc_data_fill[,c(2,3,4)]
FM <- calc_data_fill[,c(-1,-2,-3,-4,-5)]
head(FM)
## # A tibble: 6 × 8
## SPY QQQ EEM IWM EFA TLT IYR GLD
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0 0 0 0 0 0 0 0
## 2 0.0591 0.0743 0.0780 0.0791 0.0619 -0.0208 0.0930 -0.00440
## 3 0.0154 0.0222 -0.00166 0.0552 -0.0284 0.0327 0.0619 0.0572
## 4 0 0 0 0 0 0 0 0
## 5 -0.0531 -0.0616 -0.0141 -0.0806 -0.0208 0.0564 -0.0478 0.0233
## 6 0 0 0 0 0 0 0 0
FM <- as.matrix(FM)
n <- dim(FM)[2]
one_vec <- rep(1,t)
p <- cbind(one_vec,markets)
p <- as.matrix(p)
b.hat <- solve(t(p)%*%p)%*%t(p)%*%FM
res <- FM-p%*%b.hat
diag.d <- diag(t(res)%*%res)/(t-6)
diag.d
## SPY QQQ EEM IWM EFA TLT
## 0.001091729 0.001505198 0.002919168 0.002404107 0.001886366 0.001203830
## IYR GLD
## 0.001583849 0.001847489
retvar <- apply(FM,2,var)
rsq <- 1-diag(t(res)%*%res)/((t-1)/retvar)
res.stdev <- sqrt(diag.d)
factor.cov <- var(FM)*t(b.hat)%*%b.hat+diag(diag.d)
stdev <- sqrt(diag(factor.cov))
factor.cor <- factor.cov/(stdev%*%t(stdev))
factor.cor
## SPY QQQ EEM IWM EFA
## SPY 1.000000e+00 1.174100e-04 3.004937e-05 1.259587e-04 6.049202e-05
## QQQ 1.174100e-04 1.000000e+00 2.448028e-05 1.178828e-04 5.612677e-05
## EEM 3.004937e-05 2.448028e-05 1.000000e+00 3.550663e-05 3.057381e-05
## IWM 1.259587e-04 1.178828e-04 3.550663e-05 1.000000e+00 5.905564e-05
## EFA 6.049202e-05 5.612677e-05 3.057381e-05 5.905564e-05 1.000000e+00
## TLT -2.159590e-05 -1.986205e-05 -1.355514e-06 -2.348847e-05 -2.360908e-06
## IYR 8.701328e-05 7.931306e-05 2.660532e-05 9.637960e-05 4.526161e-05
## GLD 7.979925e-06 7.635986e-06 8.033463e-06 1.393527e-05 3.309333e-06
## TLT IYR GLD
## SPY -2.159590e-05 8.701328e-05 7.979925e-06
## QQQ -1.986205e-05 7.931306e-05 7.635986e-06
## EEM -1.355514e-06 2.660532e-05 8.033463e-06
## IWM -2.348847e-05 9.637960e-05 1.393527e-05
## EFA -2.360908e-06 4.526161e-05 3.309333e-06
## TLT 1.000000e+00 -1.003194e-05 -1.971330e-07
## IYR -1.003194e-05 1.000000e+00 1.093377e-05
## GLD -1.971330e-07 1.093377e-05 1.000000e+00
sample.cov <- cov(FM)
sample.cor <- cor(FM)
sample.cov
## SPY QQQ EEM IWM EFA
## SPY 0.0010534862 0.0011369269 0.0013841547 0.0014349600 0.0012192996
## QQQ 0.0011369269 0.0014192102 0.0014370760 0.0015302653 0.0013036709
## EEM 0.0013841547 0.0014370760 0.0028280869 0.0019680514 0.0019616188
## IWM 0.0014349600 0.0015302653 0.0019680514 0.0023090518 0.0015865714
## EFA 0.0012192996 0.0013036709 0.0019616188 0.0015865714 0.0018202293
## TLT -0.0007750084 -0.0007801047 -0.0010893462 -0.0010817582 -0.0009381301
## IYR 0.0009281891 0.0009591728 0.0014798170 0.0013584468 0.0011670624
## GLD 0.0003481968 0.0004188970 0.0008232053 0.0006933685 0.0004230876
## TLT IYR GLD
## SPY -7.750084e-04 0.0009281891 3.481968e-04
## QQQ -7.801047e-04 0.0009591728 4.188970e-04
## EEM -1.089346e-03 0.0014798170 8.232053e-04
## IWM -1.081758e-03 0.0013584468 6.933685e-04
## EFA -9.381301e-04 0.0011670624 4.230876e-04
## TLT 1.165485e-03 -0.0003951234 -1.640529e-05
## IYR -3.951234e-04 0.0014917589 5.297311e-04
## GLD -1.640529e-05 0.0005297311 1.873559e-03
one <- rep(1,8)
top.mat <- solve(factor.cov)%*%one
bot.mat <- t(one)%*%top.mat
MVP_FF3 <- top.mat/as.numeric(bot.mat)
MVP_FF3
## [,1]
## SPY 0.18797574
## QQQ 0.13633160
## EEM 0.07031311
## IWM 0.08533945
## EFA 0.10880251
## TLT 0.17055065
## IYR 0.12956859
## GLD 0.11111837
Compute Global Minimum Variance Portfloio Weights
# Inverse of covariance matrix
inv_cov_mat_capm <- solve(cov.mat)
one_vec <- rep(1, ncol(inv_cov_mat_capm))
gmv_weights_capm <- inv_cov_mat_capm %*% one_vec / sum(inv_cov_mat_capm %*% one_vec)
gmv_weights_capm
## [,1]
## spy_rf 0.0864944324
## qqq_rf 0.0587455476
## eem_rf 0.1544821254
## iwm_rf -0.0004280025
## efa_rf 0.2220970846
## tlt_rf 0.2554130590
## iyr_rf 0.0492478399
## gld_rf 0.1739479137
# Inverse of covariance matrix
inv_cov_mat_ff3 <- solve(factor.cov)
gmv_weights_ff3 <- inv_cov_mat_ff3 %*% one_vec / sum(inv_cov_mat_ff3 %*% one_vec)
gmv_weights_ff3
## [,1]
## SPY 0.18797574
## QQQ 0.13633160
## EEM 0.07031311
## IWM 0.08533945
## EFA 0.10880251
## TLT 0.17055065
## IYR 0.12956859
## GLD 0.11111837