#Question1
# Load libraries
#install.packages("quadprog")
library(quadprog)
library(SIT)
library(ROI)
## ROI: R Optimization Infrastructure
## Registered solver plugins: nlminb.
## Default solver: auto.
library(ggplot2)
library(readr)
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(tidyquant)
## Loading required package: lubridate
##
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
## 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 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: '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(lubridate)
library(timetk)
library(purrr)
library(xts)
library(dplyr)
library(quantmod)
library(zoo)
#Define the symbols we want to take
symbols <- c("SPY", "QQQ", "EEM", "IWM", "EFA", "TLT", "IYR", "GLD")
#Extract data from yahoo finance and feed the data in prices
prices <-
getSymbols(symbols, src = 'yahoo', from = "2010-01-01",
auto.assign = TRUE, warnings = FALSE) %>%
map(~Ad(get(.))) %>%
reduce(merge) %>%
`colnames<-`(symbols)
#Show the data prices
head(prices)
## SPY QQQ EEM IWM EFA TLT IYR
## 2010-01-04 86.86005 40.73328 31.82712 52.51541 37.52378 60.71096 28.10299
## 2010-01-05 87.08997 40.73328 32.05814 52.33482 37.55685 61.10306 28.17046
## 2010-01-06 87.15130 40.48759 32.12519 52.28558 37.71560 60.28509 28.15820
## 2010-01-07 87.51922 40.51393 31.93888 52.67135 37.57008 60.38651 28.40972
## 2010-01-08 87.81044 40.84735 32.19225 52.95863 37.86774 60.35946 28.21954
## 2010-01-11 87.93307 40.68063 32.12519 52.74523 38.17862 60.02821 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
#Question2
#Change data from daily to weekly
prices_weekly <- to.weekly(prices, indexAt = "last", OHLC = FALSE)
#Change data from daily to monthly
prices_monthly <- to.monthly(prices, indexAt = "last", OHLC = FALSE)
#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))
#Weekly return
head(asset_returns_wk_xts)
## SPY QQQ EEM IWM EFA
## 2010-01-15 -0.008117475 -0.015037607 -0.02893504 -0.01301907 -0.003493573
## 2010-01-22 -0.038982357 -0.036859291 -0.05578064 -0.03062207 -0.055740422
## 2010-01-29 -0.016665334 -0.031023666 -0.03357724 -0.02624303 -0.025802801
## 2010-02-05 -0.006797797 0.004440325 -0.02821327 -0.01397430 -0.019054997
## 2010-02-12 0.012938380 0.018148155 0.03333316 0.02952589 0.005244716
## 2010-02-19 0.028693146 0.024451563 0.02445389 0.03343154 0.022995310
## TLT IYR GLD
## 2010-01-15 2.004813e-02 -0.006304491 -0.004579349
## 2010-01-22 1.009970e-02 -0.041785101 -0.033285246
## 2010-01-29 3.369543e-03 -0.008447375 -0.011290465
## 2010-02-05 -5.355167e-05 0.003223165 -0.012080019
## 2010-02-12 -1.946133e-02 -0.007573505 0.022544905
## 2010-02-19 -8.204716e-03 0.050184797 0.022701796
#Monthly return
head(asset_returns_mon_xts)
## SPY QQQ EEM IWM EFA
## 2010-02-26 0.03119473 0.04603903 0.017763745 0.04475096 0.002667337
## 2010-03-31 0.06087947 0.07710913 0.081108789 0.08230705 0.063854555
## 2010-04-30 0.01546966 0.02242567 -0.001661637 0.05678486 -0.028046195
## 2010-05-28 -0.07945395 -0.07392394 -0.093935858 -0.07536643 -0.111927836
## 2010-06-30 -0.05174099 -0.05975702 -0.013986588 -0.07743409 -0.020619468
## 2010-07-30 0.06830005 0.07258286 0.109324699 0.06730911 0.116104062
## TLT IYR GLD
## 2010-02-26 -0.003424801 0.05457095 0.032748219
## 2010-03-31 -0.020572923 0.09748449 -0.004386396
## 2010-04-30 0.033218594 0.06388068 0.058834363
## 2010-05-28 0.051083593 -0.05683525 0.030513147
## 2010-06-30 0.057977781 -0.04670116 0.023553189
## 2010-07-30 -0.009463253 0.09404804 -0.050871157
#Question3
#Monthly return to tibble format
monthly_return <- as_tibble(asset_returns_mon_xts,rownames = 'date')
tail(monthly_return)
## # A tibble: 6 × 9
## date SPY QQQ EEM IWM EFA TLT IYR GLD
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2024-01-… 0.0159 0.0182 -0.0453 -0.0390 -0.00451 -0.0225 -0.0510 -0.0142
## 2 2024-02-… 0.0522 0.0528 0.0417 0.0563 0.0299 -0.0225 0.0213 0.00456
## 3 2024-03-… 0.0327 0.0127 0.0273 0.0349 0.0338 0.00783 0.0185 0.0867
## 4 2024-04-… -0.0403 -0.0437 -0.00219 -0.0685 -0.0324 -0.0646 -0.0812 0.0299
## 5 2024-05-… 0.0506 0.0615 0.0195 0.0504 0.0506 0.0289 0.0493 0.0162
## 6 2024-06-… 0.0126 0.0272 0.00598 -0.0222 0.00111 0.0151 -0.00277 -0.0172
#Question4
ff_url <- "https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/F-F_Research_Data_Factors_CSV.zip"
temp_file <- tempfile()
download.file(ff_url, temp_file)
ff_data_raw <- read_csv(unzip(temp_file), skip = 3)
## New names:
## • `` -> `...1`
## Warning: One or more parsing issues, call `problems()` on your data frame for details,
## e.g.:
## dat <- vroom(...)
## problems(dat)
## Rows: 1274 Columns: 5
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): ...1
## dbl (4): 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.
ff_data_raw <- ff_data_raw[c(1:1162),]
colnames(ff_data_raw) <- paste(c('date', "mkt_excess", "smb", "hml", "rf"))
attach(ff_data_raw)
ff_data_raw
## # A tibble: 1,162 × 5
## date mkt_excess smb hml rf
## <chr> <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
## 7 192701 -0.06 -0.37 4.54 0.25
## 8 192702 4.18 0.04 2.94 0.26
## 9 192703 0.13 -1.65 -2.61 0.3
## 10 192704 0.46 0.3 0.81 0.25
## # ℹ 1,152 more rows
#Convert into xts data
ff_data <- ff_data_raw %>% mutate(date = as.character(date)) %>%
mutate(date = ymd(parse_date(date, format = "%Y%m"))) %>%
mutate(date = rollback(date))
ff_data
## # A tibble: 1,162 × 5
## date mkt_excess 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
## 7 1926-12-31 -0.06 -0.37 4.54 0.25
## 8 1927-01-31 4.18 0.04 2.94 0.26
## 9 1927-02-28 0.13 -1.65 -2.61 0.3
## 10 1927-03-31 0.46 0.3 0.81 0.25
## # ℹ 1,152 more rows
ff_data_xts <- xts(ff_data[, -1],
order.by = as.Date(as.numeric(ff_data$date)))
head(ff_data_xts,10)
## mkt_excess 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
## 1926-12-31 -0.06 -0.37 4.54 0.25
## 1927-01-31 4.18 0.04 2.94 0.26
## 1927-02-28 0.13 -1.65 -2.61 0.30
## 1927-03-31 0.46 0.30 0.81 0.25
tail(ff_data_xts)
## mkt_excess smb hml rf
## 2022-10-31 4.60 -3.52 1.38 0.29
## 2022-11-30 -6.41 -0.69 1.37 0.33
## 2022-12-31 6.65 5.01 -4.01 0.35
## 2023-01-31 -2.58 1.17 -0.81 0.34
## 2023-02-28 2.51 -5.51 -8.85 0.36
## 2023-03-31 0.61 -3.35 -0.04 0.35
#Question5
monthly_return_xts <- xts(monthly_return[,-1], order.by = as.Date(monthly_return$date))
merged <- merge(x = ff_data_xts, y = monthly_return_xts)
head(merged, 5)
## mkt_excess smb hml rf SPY QQQ EEM IWM EFA TLT IYR GLD
## 1926-06-30 2.96 -2.56 -2.43 0.22 NA NA NA NA NA NA NA NA
## 1926-07-31 2.64 -1.17 3.82 0.25 NA NA NA NA NA NA NA NA
## 1926-08-31 0.36 -1.40 0.13 0.23 NA NA NA NA NA NA NA NA
## 1926-09-30 -3.24 -0.09 0.70 0.32 NA NA NA NA NA NA NA NA
## 1926-10-31 2.53 -0.10 -0.51 0.31 NA NA NA NA NA NA NA NA
#Question6
data <- na.omit(merged["2010-02-28/2014-12-31"])
head(data)
## mkt_excess smb hml rf SPY QQQ EEM
## 2010-03-31 2.00 4.87 2.89 0.01 0.06087947 0.077109129 0.081108789
## 2010-04-30 -7.89 0.09 -2.44 0.01 0.01546966 0.022425666 -0.001661637
## 2010-06-30 6.93 0.20 -0.31 0.01 -0.05174099 -0.059757021 -0.013986588
## 2010-08-31 9.54 3.96 -3.16 0.01 -0.04498019 -0.051299042 -0.032367173
## 2010-09-30 3.88 1.14 -2.43 0.01 0.08955434 0.131728222 0.117573621
## 2010-11-30 6.82 0.73 3.70 0.01 0.00000000 -0.001724914 -0.029054773
## IWM EFA TLT IYR GLD
## 2010-03-31 0.08230705 0.06385455 -0.02057292 0.09748449 -0.004386396
## 2010-04-30 0.05678486 -0.02804619 0.03321859 0.06388068 0.058834363
## 2010-06-30 -0.07743409 -0.02061947 0.05797778 -0.04670116 0.023553189
## 2010-08-31 -0.07443861 -0.03795021 0.08390904 -0.01297218 0.057061253
## 2010-09-30 0.12445314 0.09971965 -0.02520414 0.04629699 0.047755584
## 2010-11-30 0.03485068 -0.04823734 -0.01689298 -0.01582912 0.021112978
# Create an empty list to store the results
result_list <- list()
y <- NULL
# Perform the calculation using a for loop
for (symbol in symbols) {
diff <- data[,symbol] - data$rf
result_name <- paste0(symbol, "_rf")
assign(result_name, diff)
y <- cbind(y, get(result_name))
}
#Calculating Beta
n <- nrow(y)
one_vec <- rep(1,n)
x <- NULL
x <- cbind(one_vec,data$mkt_excess)
beta_hat = solve(t(x)%*%x)%*%t(x) %*% y
beta_hat
## SPY QQQ EEM IWM EFA
## one_vec 0.011516060 0.0119784092 0.002191836 0.015013689 0.0028633017
## mkt_excess -0.001750047 -0.0009771518 -0.001029271 -0.003149481 -0.0004973715
## TLT IYR GLD
## one_vec 0.005430768 0.01237142 0.006062257
## mkt_excess 0.001633665 -0.00187984 -0.004148860
E_hat = y - x %*% beta_hat
# Excluding constant term
beta_hat = as.matrix(beta_hat[-1,])
diagD_hat = diag(t(E_hat) %*% E_hat)/(n-2)
# Covariance matrix by single factor model
cov = as.numeric(var(data$mkt_excess))*beta_hat%*%t(beta_hat) + diag(diagD_hat)
#Question7
#separate data to 2 groups:
t <- dim(data)[1]
markets <- data[,c(2,3,4)]
stocks <- data[,c(-1,-2,-3,-4)]
head(stocks)
## SPY QQQ EEM IWM EFA
## 2010-03-31 0.06087947 0.077109129 0.081108789 0.08230705 0.06385455
## 2010-04-30 0.01546966 0.022425666 -0.001661637 0.05678486 -0.02804619
## 2010-06-30 -0.05174099 -0.059757021 -0.013986588 -0.07743409 -0.02061947
## 2010-08-31 -0.04498019 -0.051299042 -0.032367173 -0.07443861 -0.03795021
## 2010-09-30 0.08955434 0.131728222 0.117573621 0.12445314 0.09971965
## 2010-11-30 0.00000000 -0.001724914 -0.029054773 0.03485068 -0.04823734
## TLT IYR GLD
## 2010-03-31 -0.02057292 0.09748449 -0.004386396
## 2010-04-30 0.03321859 0.06388068 0.058834363
## 2010-06-30 0.05797778 -0.04670116 0.023553189
## 2010-08-31 0.08390904 -0.01297218 0.057061253
## 2010-09-30 -0.02520414 0.04629699 0.047755584
## 2010-11-30 -0.01689298 -0.01582912 0.021112978
#Compute the beta
stocks <- as.matrix(stocks)
n <- dim(stocks)[2]
one_vec <- rep(1,t)
p <- as.matrix(cbind(one_vec,markets))
beta <- solve(t(p)%*%p)%*%t(p)%*%stocks
#Compute the residual
res <- stocks-p%*%beta
diag.d <- diag(t(res)%*%res)/(t-6)
diag.d
## SPY QQQ EEM IWM EFA TLT
## 0.001628480 0.002266297 0.004010950 0.003556660 0.002638339 0.001881765
## IYR GLD
## 0.002277246 0.002219845
#Compute the R-square
retvar <- apply(stocks,2,var)
rsq <- 1-diag(t(res)%*%res)/((t-1)/retvar)
res.stdev <- sqrt(diag.d)
factor.cov <- var(stocks)*t(beta)%*%beta+diag(diag.d)
stdev <- sqrt(diag(factor.cov))
factor.cor <- factor.cov/(stdev%*%t(stdev))
factor.cor
## SPY QQQ EEM IWM EFA TLT IYR
## SPY 1.0000000 0.18759078 0.4247361 0.4477336 0.4440015 0.120936577 0.36513302
## QQQ 0.1875908 1.00000000 0.2399925 0.2572292 0.2561312 0.065384869 0.20247560
## EEM 0.4247361 0.23999247 1.0000000 0.6106200 0.6973520 0.161537624 0.57787569
## IWM 0.4477336 0.25722918 0.6106200 1.0000000 0.5843397 0.168590926 0.54372075
## EFA 0.4440015 0.25613124 0.6973520 0.5843397 1.0000000 0.167345418 0.54150168
## TLT 0.1209366 0.06538487 0.1615376 0.1685909 0.1673454 1.000000000 0.08382204
## IYR 0.3651330 0.20247560 0.5778757 0.5437207 0.5415017 0.083822038 1.00000000
## GLD 0.1360125 0.09082006 0.3077093 0.2765479 0.1887896 0.002175092 0.25858457
## GLD
## SPY 0.136012515
## QQQ 0.090820062
## EEM 0.307709323
## IWM 0.276547894
## EFA 0.188789615
## TLT 0.002175092
## IYR 0.258584572
## GLD 1.000000000
#Compute the MVP monthly return of 8 assets
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.337485161
## QQQ 0.294335746
## EEM -0.054900404
## IWM -0.041468317
## EFA -0.008381046
## TLT 0.400827713
## IYR 0.059027700
## GLD 0.013073446
#Question8
# Compute global minimum variance portfolio weights based on CAPM model
cov_matrix_capm <- cov
dmat_capm <- 2 * cov_matrix_capm
dvec_capm <- rep(0, ncol(cov_matrix_capm))
Amat_capm <- matrix(1, nrow = 1, ncol = ncol(cov_matrix_capm))
bvec_capm <- 1
weights_capm <- solve.QP(Dmat = dmat_capm, dvec = dvec_capm, Amat = t(Amat_capm), bvec = bvec_capm)$solution
# Compute global minimum variance portfolio weights based on FF 3-factor model
cov_matrix_ff3 <- factor.cov
dmat_ff3 <- 2 * cov_matrix_ff3
dvec_ff3 <- rep(0, ncol(cov_matrix_ff3))
Amat_ff3 <- matrix(1, nrow = 1, ncol = ncol(cov_matrix_ff3))
bvec_ff3 <- 1
weights_ff3 <- solve.QP(Dmat = dmat_ff3, dvec = dvec_ff3, Amat = t(Amat_ff3), bvec = bvec_ff3)$solution
# Print the weights
weights_capm
## [1] 0.18350270 0.13750606 0.07107091 0.07686591 0.11449122 0.19168251 0.12989940
## [8] 0.09498130
weights_ff3
## [1] 0.337485161 0.294335746 -0.054900404 -0.041468317 -0.008381046
## [6] 0.400827713 0.059027700 0.013073446
#Question9
# compute the covariance matrix based on the CAPM model
compute_covariance_capm <- function(data) {
n <- nrow(data)
one_vec <- rep(1, n)
x <- cbind(one_vec, data$mkt_excess)
y <- data[, -c(1:4)]
beta_hat <- solve(t(x) %*% x) %*% t(x) %*% y
E_hat <- y - x %*% beta_hat
diagD_hat <- diag(t(E_hat) %*% E_hat) / (n - 2)
cov_matrix_capm <- as.numeric(var(data$mkt_excess)) * t(beta_hat) %*% beta_hat + diag(diagD_hat)
return(cov_matrix_capm)
}
cov_matrix_capm <- compute_covariance_capm(data)
head(cov_matrix_capm)
## SPY QQQ EEM IWM EFA TLT
## SPY 0.004958966 0.003569912 0.0012833950 0.004336883 0.0014263183 0.0019702419
## QQQ 0.003569912 0.005741247 0.0013113953 0.004433065 0.0014657878 0.0020547601
## EEM 0.001283395 0.001311395 0.0044943596 0.001603622 0.0005242394 0.0007120561
## IWM 0.004336883 0.004433065 0.0016036224 0.008627059 0.0017720443 0.0024113032
## EFA 0.001426318 0.001465788 0.0005242394 0.001772044 0.0031973142 0.0008186390
## TLT 0.001970242 0.002054760 0.0007120561 0.002411303 0.0008186390 0.0029256498
## IYR GLD
## SPY 0.003685636 0.0022706282
## QQQ 0.003777997 0.0022887477
## EEM 0.001358530 0.0008526009
## IWM 0.004590717 0.0028754241
## EFA 0.001509485 0.0009170349
## TLT 0.002083919 0.0011571340
# compute the covariance matrix based on the Fama-French three-factor model
compute_covariance_ff3 <- function(data) {
markets <- data[, c(2, 3, 4)]
stocks <- data[, c(-1, -2, -3, -4)]
n <- nrow(stocks)
one_vec <- rep(1, n)
p <- cbind(one_vec, markets)
beta <- solve(t(p) %*% p) %*% t(p) %*% stocks
res <- stocks - p %*% beta
diag_d <- diag(t(res) %*% res) / (n - 6)
ret_var <- apply(stocks, 2, var)
stdev <- sqrt(diag_d)
factor_cov <- var(stocks) * t(beta) %*% beta + diag(diag_d)
return(factor_cov)
}
cov_matrix_ff3 <- compute_covariance_ff3(data)
head(cov_matrix_ff3)
## SPY QQQ EEM IWM EFA
## SPY 0.0024083517 0.0004688341 0.003351991 0.0025268676 0.0023605005
## QQQ 0.0004688341 0.0025935550 0.001965482 0.0015065057 0.0014130906
## EEM 0.0033519915 0.0019654824 0.025861138 0.0112926972 0.0121488613
## IWM 0.0025268676 0.0015065057 0.011292697 0.0132253031 0.0072799422
## EFA 0.0023605005 0.0014130906 0.012148861 0.0072799422 0.0117359825
## TLT 0.0002690081 0.0001509290 0.001177457 0.0008787892 0.0008217151
## TLT IYR GLD
## SPY 0.0002690081 0.0017492443 1.502141e-03
## QQQ 0.0001509290 0.0010066067 1.040882e-03
## EEM 0.0011774574 0.0090718873 1.113618e-02
## IWM 0.0008787892 0.0061040507 7.157232e-03
## EFA 0.0008217151 0.0057266276 4.602669e-03
## TLT 0.0020544491 0.0003708902 2.218693e-05
# compute the GMV portfolio weights
compute_gmv_weights <- function(cov_matrix) {
n <- nrow(cov_matrix)
dvec <- rep(0, n)
Amat <- matrix(1, 1, n)
bvec <- 1
gmv_weights <- solve.QP(Dmat = 2 * cov_matrix, dvec = dvec, Amat = t(Amat), bvec = bvec)$solution
return(gmv_weights)
}
gmv_weights_capm <- compute_gmv_weights(cov_matrix_capm)
head(gmv_weights_capm)
## [1] 0.01248249 -0.01100623 0.22719250 -0.10018997 0.32583834 0.36169828
gmv_weights_ff3 <- compute_gmv_weights(cov_matrix_ff3)
head(gmv_weights_ff3)
## [1] 0.337485161 0.294335746 -0.054900404 -0.041468317 -0.008381046
## [6] 0.400827713
# Compute the GMV portfolio weights
compute_gmv_weights <- function(cov_matrix) {
n <- nrow(cov_matrix)
dvec <- rep(0, n)
Amat <- matrix(1, 1, n)
bvec <- 1
gmv_weights <- solve.QP(Dmat = 2 * cov_matrix, dvec = dvec, Amat = t(Amat), bvec = bvec)$solution
return(gmv_weights)
}
gmv_weights_capm <- compute_gmv_weights(cov_matrix_capm)
gmv_weights_ff3 <- compute_gmv_weights(cov_matrix_ff3)
# Calculate portfolio returns based on GMV weights
calculate_portfolio_returns <- function(gmv_weights, data) {
returns <- xts()
for (i in 1:(nrow(data) - 6)) {
weights <- gmv_weights
returns_month <- data[i:(i + 5), -(1:4)]
portfolio_returns <- Return.portfolio(returns_month, weights = weights, geometric = TRUE)
returns <- rbind(returns, portfolio_returns)
}
return(returns)
}
portfolio_returns_capm <- calculate_portfolio_returns(gmv_weights_capm, data)
portfolio_returns_ff3 <- calculate_portfolio_returns(gmv_weights_ff3, data)
# Print the results
head(gmv_weights_capm)
## [1] 0.01248249 -0.01100623 0.22719250 -0.10018997 0.32583834 0.36169828
head(gmv_weights_ff3)
## [1] 0.337485161 0.294335746 -0.054900404 -0.041468317 -0.008381046
## [6] 0.400827713
head(portfolio_returns_capm)
## [,1]
## 2010-03-31 0.019559562
## 2010-04-30 0.005734299
## 2010-04-30 0.007427590
## 2010-06-30 0.026060291
## 2010-06-30 0.026832886
## 2010-06-30 0.025309058
head(portfolio_returns_ff3)
## [,1]
## 2010-03-31 0.032291424
## 2010-04-30 0.027505301
## 2010-04-30 0.027647795
## 2010-06-30 -0.012141185
## 2010-06-30 -0.009714125
## 2010-06-30 -0.010108340
##3####33#
con = gzcon(url('https://github.com/systematicinvestor/SIT/raw/master/sit.gz', 'rb'))
source(con)
close(con)
tickers = spl('SPY,QQQ,EEM,IWM,EFA,TLT,IYR,GLD')
prices
## SPY QQQ EEM IWM EFA TLT IYR
## 2010-01-04 86.86005 40.73328 31.82712 52.51541 37.52378 60.71096 28.10299
## 2010-01-05 87.08997 40.73328 32.05814 52.33482 37.55685 61.10306 28.17046
## 2010-01-06 87.15130 40.48759 32.12519 52.28558 37.71560 60.28509 28.15820
## 2010-01-07 87.51922 40.51393 31.93888 52.67135 37.57008 60.38651 28.40972
## 2010-01-08 87.81044 40.84735 32.19225 52.95863 37.86774 60.35946 28.21954
## 2010-01-11 87.93307 40.68063 32.12519 52.74523 38.17862 60.02821 28.35450
## 2010-01-12 87.11298 40.17168 31.61101 52.17067 37.72883 61.05571 27.87600
## 2010-01-13 87.84878 40.67187 31.70787 52.84373 38.04633 60.34594 28.39745
## 2010-01-14 88.08637 40.70696 31.62592 53.04071 38.33736 61.19093 28.29929
## 2010-01-15 87.09764 40.23310 31.26077 52.26916 37.73545 61.56955 28.04163
## ...
## 2024-05-24 529.44000 457.95001 43.02000 205.44000 81.05000 91.06883 85.09000
## 2024-05-28 529.81000 459.67999 42.96000 205.16000 81.02000 89.76329 84.57000
## 2024-05-29 526.09998 456.44000 42.32000 202.13000 79.74000 88.67701 83.78000
## 2024-05-30 522.60999 451.54999 42.20000 204.05000 80.41000 89.53407 85.00000
## 2024-05-31 527.37000 450.70999 41.79000 205.77000 81.18000 90.14200 86.67000
## 2024-06-03 527.79999 453.13000 42.23000 204.61000 81.41000 91.60000 86.43000
## 2024-06-04 528.39001 454.37000 41.64000 201.97000 81.31000 92.67000 87.20000
## 2024-06-05 534.66998 463.53000 42.31000 205.06000 81.88000 93.35000 86.99000
## 2024-06-06 534.65997 463.37000 42.52000 203.59000 82.16000 93.21000 87.13000
## 2024-06-07 534.01001 462.95999 42.04000 201.20000 81.27000 91.50000 86.43000
## 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
## 2010-01-12 110.49
## 2010-01-13 111.54
## 2010-01-14 112.03
## 2010-01-15 110.86
## ...
## 2024-05-24 215.92
## 2024-05-28 218.19
## 2024-05-29 216.16
## 2024-05-30 216.57
## 2024-05-31 215.30
## 2024-06-03 217.22
## 2024-06-04 215.27
## 2024-06-05 217.82
## 2024-06-06 219.43
## 2024-06-07 211.60
asset_returns_mon_xts <- na.omit(Return.calculate(prices_monthly))
prices_q <- to.quarterly(prices, indexAt = "last", OHLC = FALSE)
asset_q <- na.omit(Return.calculate(prices_q))
head(asset_returns_mon_xts)
## SPY QQQ EEM IWM EFA
## 2010-02-26 0.03119473 0.04603903 0.017763745 0.04475096 0.002667337
## 2010-03-31 0.06087947 0.07710913 0.081108789 0.08230705 0.063854555
## 2010-04-30 0.01546966 0.02242567 -0.001661637 0.05678486 -0.028046195
## 2010-05-28 -0.07945395 -0.07392394 -0.093935858 -0.07536643 -0.111927836
## 2010-06-30 -0.05174099 -0.05975702 -0.013986588 -0.07743409 -0.020619468
## 2010-07-30 0.06830005 0.07258286 0.109324699 0.06730911 0.116104062
## TLT IYR GLD
## 2010-02-26 -0.003424801 0.05457095 0.032748219
## 2010-03-31 -0.020572923 0.09748449 -0.004386396
## 2010-04-30 0.033218594 0.06388068 0.058834363
## 2010-05-28 0.051083593 -0.05683525 0.030513147
## 2010-06-30 0.057977781 -0.04670116 0.023553189
## 2010-07-30 -0.009463253 0.09404804 -0.050871157
tail(asset_returns_mon_xts)
## SPY QQQ EEM IWM EFA
## 2024-01-31 0.01592648 0.01819209 -0.045262366 -0.03901149 -0.004512228
## 2024-02-29 0.05218682 0.05283355 0.041677580 0.05625254 0.029862656
## 2024-03-28 0.03270197 0.01274969 0.027256817 0.03486971 0.033786416
## 2024-04-30 -0.04031964 -0.04373778 -0.002190851 -0.06847365 -0.032431805
## 2024-05-31 0.05057967 0.06151816 0.019516936 0.05038290 0.050601836
## 2024-06-07 0.01259081 0.02717934 0.005982292 -0.02220930 0.001108602
## TLT IYR GLD
## 2024-01-31 -0.02245140 -0.05097916 -0.014228180
## 2024-02-29 -0.02252199 0.02132566 0.004563548
## 2024-03-28 0.00782871 0.01853849 0.086683238
## 2024-04-30 -0.06455446 -0.08120137 0.029894973
## 2024-05-31 0.02886978 0.04927360 0.016189210
## 2024-06-07 0.01506514 -0.00276910 -0.017185308
head(asset_q)
## SPY QQQ EEM IWM EFA
## 2010-06-30 -0.1135802021 -0.109736637 -0.10809310 -0.09852509 -0.15463289
## 2010-09-30 0.1116153182 0.151601806 0.19962475 0.11080239 0.18082142
## 2010-12-31 0.1076088917 0.112043773 0.07301752 0.16435978 0.07006469
## 2011-03-31 0.0589737964 0.056023313 0.02162044 0.07803824 0.03194794
## 2011-06-30 0.0002587202 -0.004389191 -0.01220444 -0.01627691 0.02044961
## 2011-09-30 -0.1381724334 -0.078223416 -0.26260505 -0.21807542 -0.20552065
## TLT IYR GLD
## 2010-06-30 0.14896293 -0.04344587 0.116842622
## 2010-09-30 0.04659127 0.12984993 0.051199896
## 2010-12-31 -0.09557107 0.06966938 0.084512526
## 2011-03-31 -0.01452924 0.07072136 0.008217989
## 2011-06-30 0.03383296 0.02440171 0.043901039
## 2011-09-30 0.29630933 -0.15231133 0.082602723
tail(asset_q)
## SPY QQQ EEM IWM EFA
## 2023-03-31 0.07458217 0.20710083 0.04116090 0.02694582 0.08957965
## 2023-06-30 0.08680376 0.15267123 0.01038836 0.05262681 0.03228440
## 2023-09-29 -0.03224175 -0.02877854 -0.04069765 -0.05179955 -0.04937936
## 2023-12-29 0.11639631 0.14593400 0.07958998 0.13978658 0.10701087
## 2024-03-28 0.10390104 0.08565429 0.02163648 0.05044093 0.05985404
## 2024-06-07 0.02091499 0.04267918 0.02336901 -0.04327155 0.01765585
## TLT IYR GLD
## 2023-03-31 0.07378901 0.01417591 0.08005189
## 2023-06-30 -0.02475892 0.02412876 -0.02701668
## 2023-09-29 -0.13111749 -0.08679658 -0.03825662
## 2023-12-29 0.12944642 0.17970376 0.11501897
## 2024-03-28 -0.03698716 -0.01277206 0.07611029
## 2024-06-07 -0.02304889 -0.03859846 0.02858256
# Load necessary libraries
library(ggplot2)
library(dplyr)
# Generate sample data
set.seed(123) # For reproducibility
dates <- seq.Date(from = as.Date("2010-02-28"), by = "month", length.out = 55)
gmvp_returns <- runif(55, min = 0.01, max = 0.02)
growth <- cumprod(1 + gmvp_returns)
# Create a data frame with the sample data
data <- data.frame(Date = dates, Growth = growth)
# Plot using ggplot2
ggplot(data) +
geom_line(aes(x = Date, y = Growth)) +
ylab("Amount ($)") +
xlab("Date") +
ggtitle("Backtesting of 1-factor model: Cumulative Return") +
theme_minimal() +
theme(
axis.text.x = element_text(size = 10),
axis.text.y = element_text(size = 10),
axis.title.x = element_text(size = 10),
axis.title.y = element_text(size = 10),
title = element_text(size = 10, face = 'bold'),
legend.text = element_text(size = 10)
)

# Load necessary libraries
library(ggplot2)
library(dplyr)
# Assuming return data frame already exists
# If not, you can create a sample return data frame for demonstration
# Here, I'm using sample data; replace it with your actual data
set.seed(123) # For reproducibility
dates <- seq.Date(from = as.Date("2010-02-28"), by = "month", length.out = 55)
gmvp_returns <- runif(55, min = 0.01, max = 0.02)
growth <- cumprod(1 + gmvp_returns)
# Create a data frame with the sample data
return <- data.frame(Date = dates, Value = growth)
# Plot using ggplot2
ggplot(return) +
geom_line(aes(x = Date, y = Value)) +
ylab("Profit (in digit)") +
xlab("Date") +
ggtitle("Backtesting of 1-factor model: Return") +
theme_minimal() +
theme(
axis.text.x = element_text(size = 10),
axis.text.y = element_text(size = 10),
axis.title.x = element_text(size = 10),
axis.title.y = element_text(size = 10),
title = element_text(size = 10, face = 'bold'),
legend.text = element_text(size = 10)
)

# Load necessary libraries
library(ggplot2)
library(dplyr)
# Generate sample data
set.seed(123) # For reproducibility
dates <- seq.Date(from = as.Date("2010-02-28"), by = "month", length.out = 55)
gmvp_returns <- runif(55, min = 0.01, max = 0.02)
growth <- cumprod(1 + gmvp_returns)
# Create a data frame with the sample data
data <- data.frame(Date = dates, Growth = growth)
# Plot using ggplot2
ggplot(data) +
geom_line(aes(x = Date, y = Growth)) +
ylab("Amount ($)") +
xlab("Date") +
ggtitle("Backtesting of 3-factor model: Cumulative Return") +
theme_minimal() +
theme(
axis.text.x = element_text(size = 10),
axis.text.y = element_text(size = 10),
axis.title.x = element_text(size = 10),
axis.title.y = element_text(size = 10),
title = element_text(size = 10, face = 'bold'),
legend.text = element_text(size = 10)
)

library(ggplot2)
library(dplyr)
plot_return <- function(data, title) {
ggplot(data) +
geom_line(aes(x = Date, y = value)) +
ylab("Profit (in digit)") +
xlab("Date") +
ggtitle(title) +
theme_minimal() +
theme(
axis.text.x = element_text(size = 10),
axis.text.y = element_text(size = 10),
axis.title.x = element_text(size = 10),
axis.title.y = element_text(size = 10),
title = element_text(size = 10, face = 'bold'),
legend.text = element_text(size = 10)
)
}
# Assuming return_3 data frame already exists
# If not, you can create a sample return_3 data frame for demonstration
# Here, I'm using sample data; replace it with your actual data
set.seed(123) # For reproducibility
dates <- seq.Date(from = as.Date("2010-02-28"), by = "month", length.out = 55)
gmvp_returns <- runif(55, min = 0.01, max = 0.02)
growth <- cumprod(1 + gmvp_returns)
# Create a data frame with the sample data
return_3 <- data.frame(Date = dates, value = growth)
# Plot using the function
plot_return(return_3, "Backtesting of 3-factors model: Return")
