# https://palomar.home.ece.ust.hk/MAFS6010R_lectures/Rsession_factor_models.html#final_comparison_of_covariance_matrix_estimations_via_different_factor_models
# https://systematicinvestor.wordpress.com/2012/03/19/backtesting-asset-allocation-portfolios/
rm(list = ls())
library(lubridate)
##
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
library(timetk)
library(purrr)
library(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
library(lpSolve)
#devtools::install_github('joshuaulrich/xts', force = T)
#devtools::install_github('joshuaulrich/quantmod', force = T)
#devtools::install_github('systematicinvestor/SIT.date', force = T)curl::curl_download('https://github.com/systematicinvestor/SIT/raw/master/SIT.tar.gz', 'SIT.tar.gz',mode = 'wb',quiet=T)
install.packages('SIT.tar.gz', repos = NULL, type='source')
## Installing package into '/home/rstudio-user/R/x86_64-pc-linux-gnu-library/4.0'
## (as 'lib' is unspecified)
library(SIT)
## Loading required package: SIT.date
##
## Attaching package: 'SIT'
## The following object is masked from 'package:TTR':
##
## DVI
## The following object is masked from 'package:purrr':
##
## cross
## The following object is masked from 'package:base':
##
## close
library(PerformanceAnalytics)
##
## Attaching package: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
##
## legend
library(xts)
library(tidyr)
5 Credit Services in USA
#Import data
tickers = spl('AXP,CIT,EFX,V,WU')
datas <- new.env()
getSymbols(tickers, src = 'yahoo', from = '2005-01-01', env = datas, auto.assign = T)
## [1] "AXP" "CIT" "EFX" "V" "WU"
for(i in ls(datas)) datas[[i]] = adjustOHLC(datas[[i]], use.Adjusted=T)
names(datas)
## [1] "AXP" ".getSymbols" "CIT" "EFX" "WU"
## [6] "V"
datas$EEM
## NULL
head(datas$EEM)
## NULL
#
bt.prep(datas, align='remove.na')
names(datas)
## [1] "prices" "AXP" "dates" "weight"
## [5] ".getSymbols" "symbolnames" "CIT" "execution.price"
## [9] "EFX" "WU" "V"
#
head(datas$SPY)
## NULL
head(datas$prices)
## AXP CIT EFX V WU
## 2009-12-10 33.82547 24.26659 26.03877 18.96895 13.31280
## 2009-12-11 34.24587 24.81068 26.17718 18.74312 13.36184
## 2009-12-14 34.70831 23.85643 26.46266 19.53349 13.45993
## 2009-12-15 34.43926 21.93117 26.29829 19.84918 13.29178
## 2009-12-16 34.69991 21.93954 26.34154 20.05426 13.47395
## 2009-12-17 34.01045 21.79724 26.09066 20.05426 13.37555
#
prices_monthly <- to.monthly(datas$prices, indexAt = "last", OHLC = FALSE) # indexAt = 'endof'
head(prices_monthly)
## AXP CIT EFX V WU
## 2009-12-31 34.06930 23.11144 26.72217 20.15334 13.24903
## 2010-01-29 31.80258 26.63549 27.68241 18.90212 13.03114
## 2010-02-26 32.25015 30.49437 27.94172 19.68055 11.09123
## 2010-03-31 34.99451 32.61215 31.00786 21.00752 11.96482
## 2010-04-30 39.11651 33.98494 29.10236 20.82289 12.87488
## 2010-05-28 33.81559 30.79571 26.23564 16.74688 11.25935
monthly.ret <- na.omit(Return.calculate(prices_monthly, method = "discrete"))
head(monthly.ret)
## AXP CIT EFX V WU
## 2010-01-29 -0.0665325713 0.15248077 0.035933940 -0.062085184 -0.01644573
## 2010-02-26 0.0140732293 0.14487735 0.009367321 0.041182208 -0.14886700
## 2010-03-31 0.0850962376 0.06944837 0.109733593 0.067425199 0.07876337
## 2010-04-30 0.1177898157 0.04209425 -0.061452157 -0.008788474 0.07606142
## 2010-05-28 -0.1355160333 -0.09384228 -0.098504857 -0.195746739 -0.12547924
## 2010-06-30 0.0002269663 -0.07964125 -0.072396943 -0.023598846 -0.06235511
#
# download Fama-French factors from website
url <- "http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/F-F_Research_Data_Factors_daily_CSV.zip"
temp <- tempfile()
download.file(url, temp, method = "libcurl", mode = "wb")
unzip(temp, "F-F_Research_Data_Factors_daily.CSV")
unlink(temp)
#
mydata <- read.csv("F-F_Research_Data_Factors_daily.CSV", skip = 4)
mydata <- mydata[-nrow(mydata), ] # remove last row
fama_lib <- xts(x = mydata[, c(2,3,4)], order.by = as.Date(paste(mydata[, 1]), "%Y%m%d"))
str(fama_lib)
## An 'xts' object on 1926-07-01/2021-04-30 containing:
## Data: num [1:24978, 1:3] 0.1 0.45 0.17 0.09 0.21 -0.71 0.62 0.04 0.48 0.04 ...
## - attr(*, "dimnames")=List of 2
## ..$ : NULL
## ..$ : chr [1:3] "Mkt.RF" "SMB" "HML"
## Indexed by objects of class: [Date] TZ: UTC
## xts Attributes:
## NULL
head(fama_lib)
## Mkt.RF SMB HML
## 1926-07-01 0.10 -0.24 -0.28
## 1926-07-02 0.45 -0.32 -0.08
## 1926-07-06 0.17 0.27 -0.35
## 1926-07-07 0.09 -0.59 0.03
## 1926-07-08 0.21 -0.36 0.15
## 1926-07-09 -0.71 0.44 0.56
#
dates <- '2005-01::2021-03'
X <- monthly.ret[dates]
head(X)
## AXP CIT EFX V WU
## 2010-01-29 -0.0665325713 0.15248077 0.035933940 -0.062085184 -0.01644573
## 2010-02-26 0.0140732293 0.14487735 0.009367321 0.041182208 -0.14886700
## 2010-03-31 0.0850962376 0.06944837 0.109733593 0.067425199 0.07876337
## 2010-04-30 0.1177898157 0.04209425 -0.061452157 -0.008788474 0.07606142
## 2010-05-28 -0.1355160333 -0.09384228 -0.098504857 -0.195746739 -0.12547924
## 2010-06-30 0.0002269663 -0.07964125 -0.072396943 -0.023598846 -0.06235511
dim(X)
## [1] 135 5
#
fama_lib_month <- to.monthly(fama_lib, indexAt = "last", OHLC = FALSE) # indexAt = 'endof'
head(fama_lib_month)
## Mkt.RF SMB HML
## 1926-07-31 0.46 -0.12 -0.17
## 1926-08-31 0.58 -0.52 -0.04
## 1926-09-30 0.30 -0.22 0.06
## 1926-10-30 -0.25 0.20 0.25
## 1926-11-30 0.26 0.03 -0.50
## 1926-12-31 0.33 0.30 0.67
f <- fama_lib_month[dates]/100
head(f)
## Mkt.RF SMB HML
## 2005-01-31 0.0097 0.0076 0.0014
## 2005-02-28 -0.0061 0.0027 0.0007
## 2005-03-31 0.0000 -0.0006 0.0065
## 2005-04-29 0.0104 -0.0040 -0.0003
## 2005-05-31 -0.0049 0.0046 0.0033
## 2005-06-30 -0.0063 0.0021 0.0025
dim(f)
## [1] 195 3
#======================================================================
# Use Professor Palomar's package to compute estimated coefficients
# Based on CAPM model, compute covariance matrix for the 5-asset portfolio by using past 60-month returns from 2010/01 - 2014/12.
#======================================================================
#devtools::install_github("dppalomar/covFactorModel")
library(covFactorModel)
#
insample_range <- '2010-01::2014-12'
one_factor_model <- factorModel(X[insample_range], type = "M", econ_fact = f$Mkt.RF[insample_range])
names(one_factor_model)
## [1] "alpha" "beta" "factors" "residual"
cbind(alpha = one_factor_model$alpha, beta = one_factor_model$beta)
## alpha Mkt.RF
## AXP 0.016807357 0.12085846
## CIT 0.011965836 -0.08184649
## EFX 0.018907744 0.38720919
## V 0.021244283 0.96969532
## WU 0.004473712 0.13725370
#======================================================================
# we can do the fitting using a more compact matrix notation
F_ <- cbind(ones = 1, f$Mkt.RF[insample_range])
Gamma <- t(X[insample_range]) %*% F_ %*% solve(t(F_) %*% F_) # better: Gamma <- t(solve(t(F_) %*% F_, t(F_) %*% X))
colnames(Gamma) <- c("alpha", "beta")
alpha <- Gamma[, 1] # or alpha <- Gamma[, "alpha"]
beta <- Gamma[, 2] # or beta <- Gamma[, "beta"]
print(Gamma)
## alpha beta
## AXP 0.016807357 0.12085846
## CIT 0.011965836 -0.08184649
## EFX 0.018907744 0.38720919
## V 0.021244283 0.96969532
## WU 0.004473712 0.13725370
# compute Sigma
X <- X[insample_range]
f <- f$Mkt.RF[insample_range]
T <- dim(X)[1]
E <- xts(t(t(X) - Gamma %*% t(F_)), index(X)) # residuals
Psi <- (1/(T-2)) * t(E) %*% E
Sigma <- as.numeric(var(f)) * beta %o% beta + diag(diag(Psi))
Sigma # This is covariance matrix computed from single factor model
## AXP CIT EFX V WU
## AXP 3.272649e-03 -1.080449e-06 5.111517e-06 1.280087e-05 1.811875e-06
## CIT -1.080449e-06 5.417279e-03 -3.461568e-06 -8.668870e-06 -1.227019e-06
## EFX 5.111517e-06 -3.461568e-06 2.711577e-03 4.101173e-05 5.804928e-06
## V 1.280087e-05 -8.668870e-06 4.101173e-05 3.131891e-03 1.453739e-05
## WU 1.811875e-06 -1.227019e-06 5.804928e-06 1.453739e-05 6.325509e-03
#=======================================================================
# We can also use lm() to compute estimated coefficients
fit = lm(formula = X~f)
sigF = as.numeric(var(f))
beta_ = as.matrix(fit$coefficients)
beta_ = as.matrix(beta_[-1,])
beta_
## [,1]
## AXP 0.12085846
## CIT -0.08184649
## EFX 0.38720919
## V 0.96969532
## WU 0.13725370
sigeps = crossprod(fit$residuals)/(T-2)
# sigeps = as.matrix(var(fit$residuals)) # you can use this way too
sigeps = diag(diag(sigeps))
sigeps
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0.003271053 0.000000000 0.0000000 0.000000000 0.000000000
## [2,] 0.000000000 0.005416547 0.0000000 0.000000000 0.000000000
## [3,] 0.000000000 0.000000000 0.0026952 0.000000000 0.000000000
## [4,] 0.000000000 0.000000000 0.0000000 0.003029184 0.000000000
## [5,] 0.000000000 0.000000000 0.0000000 0.000000000 0.006323451
cov_1f = sigF*beta_%*%t(beta_)+sigeps
cov_1f # This is covariance matrix computed from single factor model (from lm())
## AXP CIT EFX V WU
## AXP 3.272649e-03 -1.080449e-06 5.111517e-06 1.280087e-05 1.811875e-06
## CIT -1.080449e-06 5.417279e-03 -3.461568e-06 -8.668870e-06 -1.227019e-06
## EFX 5.111517e-06 -3.461568e-06 2.711577e-03 4.101173e-05 5.804928e-06
## V 1.280087e-05 -8.668870e-06 4.101173e-05 3.131891e-03 1.453739e-05
## WU 1.811875e-06 -1.227019e-06 5.804928e-06 1.453739e-05 6.325509e-03
#=======================================================================
# Backtesting portfolio using SIT package
#=======================================================================
dates <- '2005-01::2021-03'
X <- monthly.ret[dates]
head(X)
## AXP CIT EFX V WU
## 2010-01-29 -0.0665325713 0.15248077 0.035933940 -0.062085184 -0.01644573
## 2010-02-26 0.0140732293 0.14487735 0.009367321 0.041182208 -0.14886700
## 2010-03-31 0.0850962376 0.06944837 0.109733593 0.067425199 0.07876337
## 2010-04-30 0.1177898157 0.04209425 -0.061452157 -0.008788474 0.07606142
## 2010-05-28 -0.1355160333 -0.09384228 -0.098504857 -0.195746739 -0.12547924
## 2010-06-30 0.0002269663 -0.07964125 -0.072396943 -0.023598846 -0.06235511
dim(X)
## [1] 135 5
tail(X)
## AXP CIT EFX V WU
## 2020-10-30 -0.08607397 0.66290224 -0.12938166 -0.091313594 -0.09286041
## 2020-11-30 0.29975889 0.15025707 0.22459795 0.159357927 0.16049374
## 2020-12-31 0.01956324 0.07196179 0.15542241 0.039838357 -0.01790802
## 2021-01-29 -0.03508679 0.02785518 -0.08157019 -0.116490609 0.01504098
## 2021-02-26 0.16342680 0.23992292 -0.08397974 0.100748883 0.04265827
## 2021-03-31 0.04883288 0.13583241 0.11891523 -0.003107492 0.07202445
#
prices_monthly <- to.monthly(datas$prices, indexAt = "last", OHLC = FALSE) # indexAt = 'endof'
head(prices_monthly)
## AXP CIT EFX V WU
## 2009-12-31 34.06930 23.11144 26.72217 20.15334 13.24903
## 2010-01-29 31.80258 26.63549 27.68241 18.90212 13.03114
## 2010-02-26 32.25015 30.49437 27.94172 19.68055 11.09123
## 2010-03-31 34.99451 32.61215 31.00786 21.00752 11.96482
## 2010-04-30 39.11651 33.98494 29.10236 20.82289 12.87488
## 2010-05-28 33.81559 30.79571 26.23564 16.74688 11.25935
prices_monthly <- prices_monthly[dates]
head(prices_monthly)
## AXP CIT EFX V WU
## 2009-12-31 34.06930 23.11144 26.72217 20.15334 13.24903
## 2010-01-29 31.80258 26.63549 27.68241 18.90212 13.03114
## 2010-02-26 32.25015 30.49437 27.94172 19.68055 11.09123
## 2010-03-31 34.99451 32.61215 31.00786 21.00752 11.96482
## 2010-04-30 39.11651 33.98494 29.10236 20.82289 12.87488
## 2010-05-28 33.81559 30.79571 26.23564 16.74688 11.25935
tail(prices_monthly)
## AXP CIT EFX V WU
## 2020-10-30 90.64872 28.66063 135.7666 180.8926 18.88968
## 2020-11-30 117.82148 32.96709 166.2595 209.7193 21.92135
## 2020-12-31 120.12645 35.33946 192.1000 218.0742 21.52878
## 2021-01-29 115.91160 36.32385 176.4303 192.6706 21.85260
## 2021-02-26 134.85466 45.03877 161.6138 212.0819 22.78479
## 2021-03-31 141.44000 51.15650 180.8321 211.4229 24.42585
#*****************************************************************
# Code Strategies
#******************************************************************
# We need to create environment variable required by SIT
# data_m <- new.env()
#
# data_m$EEM <- prices_monthly$EEM
# colnames(data_m$EEM) <- 'Close'
# head(data_m$EEM)
# Change column names to Close which will be consistent with the requirement of SIT package
# data_m$SPY <- prices_monthly$SPY %>% `colnames<-` (c("Close"))
# data_m$QQQ <- prices_monthly$QQQ %>% `colnames<-` (c("Close"))
# data_m$EEM <- prices_monthly$EEM %>% `colnames<-` (c("Close"))
# data_m$IWM <- prices_monthly$IWM %>% `colnames<-` (c("Close"))
# data_m$EFA <- prices_monthly$EFA %>% `colnames<-` (c("Close"))
# data_m$TLT <- prices_monthly$TLT %>% `colnames<-` (c("Close"))
# data_m$IYR <- prices_monthly$IYR %>% `colnames<-` (c("Close"))
# data_m$GLD <- prices_monthly$GLD %>% `colnames<-` (c("Close"))
# names(data_m)
# head(data_m$EEM)
# Using loop to save time in naming
data_m <- list()
#i = 1
for ( i in 1:length(tickers)){
data_m[[tickers[i]]] <- prices_monthly[,i] %>% `colnames<-` (c("Close"))
}
# data_env <- new.env()
# list2env(data_m, envir = data_env)
# convert from list to environment variable because SIT package requires
# the input data to be environmental variable which can be processed using bt.prep()
data_m <- list2env(data_m)
names(data_m)
## [1] "WU" "V" "EFX" "CIT" "AXP"
# Check if the column name is 'Close'
head(data_m$EEM)
## NULL
#
bt.prep(data_m, align='remove.na', dates = dates)
names(data_m)
## [1] "prices" "execution.price" "weight" "dates"
## [5] "symbolnames" "WU" "V" "EFX"
## [9] "CIT" "AXP"
#===============================================================
# Equal weighting portfolio
# Equal Weight 1/N Benchmark
#===============================================================
models <- list()
prices <- data_m$prices
# data_m$weight[] = NA
N <- length(tickers)
data_m$weight = ntop(prices, N)
head(data_m$weight)
## AXP CIT EFX V WU
## 2009-12-31 0.2 0.2 0.2 0.2 0.2
## 2010-01-29 0.2 0.2 0.2 0.2 0.2
## 2010-02-26 0.2 0.2 0.2 0.2 0.2
## 2010-03-31 0.2 0.2 0.2 0.2 0.2
## 2010-04-30 0.2 0.2 0.2 0.2 0.2
## 2010-05-28 0.2 0.2 0.2 0.2 0.2
data_m$weight[1:59, ] <- NA
models$equal.weight = bt.run.share(data_m)
## Latest weights :
## AXP CIT EFX V WU
## 2021-03-31 16.35 11.01 22.13 34.72 15.79
##
## Performance summary :
## CAGR Best Worst
## 6.8 19.3 -19.9
# head(models$equal.weight$ret, 62)
# Slightly difference between bt.run.share() and bt.run()
capital = 100000
data_m$weight[] = (capital / prices) * data_m$weight
models$equal.weight.share = bt.run(data_m, type='share')
## Latest weights :
## AXP CIT EFX V WU
## 2021-03-31 20 20 20 20 20
##
## Performance summary :
## CAGR Best Worst
## 7.6 19.9 -24.8
# head(models$equal.weight.share$ret, 62)
# head(equal.weight$ret)
#================================================================
# MVP portfolio
#*****************************************************************
# Create Constraints
#*****************************************************************
constraints = new.constraints(N, lb = -Inf, ub = +Inf)
# SUM x.i = 1
constraints = add.constraints(rep(1, N), 1, type = '=', constraints)
#
ret = prices / mlag(prices) - 1
weight = coredata(ret)
weight[] = NA
#
# head(data_m$weight)
# compute covariance matrix based on historical 60 months returns
# i = 60
# To make covariance matrix estimate more stable, use the Ledoit-Wolf covariance shrinkage estimator from tawny package
# 1. ia$cov = tawny::cov.shrink(hist) or
# 2. ia$cov = cor(coredata(hist), use='complete.obs', method='spearman') * (s0 %*% t(s0)) or
# 3. ia$cov = cor(coredata(hist), use='complete.obs', method='kendall') * (s0 %*% t(s0)
# i = 60
for( i in 60:dim(weight)[1]) {
hist = ret[ (i- 60 + 1):i, ]
# create historical input assumptions
ia = create.historical.ia(hist, 12) # 12 is annulized factor for monthly returns
s0 = apply(na.omit(coredata(hist)), 2, sd)
ia$cov = cor(coredata(hist), use='complete.obs',method='pearson') * (s0 %*% t(s0))
weight[i,] = min.risk.portfolio(ia, constraints) # use SIT's function min.risk.portfolio()
}
## Loading required package: kernlab
##
## Attaching package: 'kernlab'
## The following object is masked from 'package:SIT':
##
## cross
## The following object is masked from 'package:purrr':
##
## cross
dim(weight)
## [1] 136 5
# 195 8
head(weight, 70)
## AXP CIT EFX V WU
## [1,] NA NA NA NA NA
## [2,] NA NA NA NA NA
## [3,] NA NA NA NA NA
## [4,] NA NA NA NA NA
## [5,] NA NA NA NA NA
## [6,] NA NA NA NA NA
## [7,] NA NA NA NA NA
## [8,] NA NA NA NA NA
## [9,] NA NA NA NA NA
## [10,] NA NA NA NA NA
## [11,] NA NA NA NA NA
## [12,] NA NA NA NA NA
## [13,] NA NA NA NA NA
## [14,] NA NA NA NA NA
## [15,] NA NA NA NA NA
## [16,] NA NA NA NA NA
## [17,] NA NA NA NA NA
## [18,] NA NA NA NA NA
## [19,] NA NA NA NA NA
## [20,] NA NA NA NA NA
## [21,] NA NA NA NA NA
## [22,] NA NA NA NA NA
## [23,] NA NA NA NA NA
## [24,] NA NA NA NA NA
## [25,] NA NA NA NA NA
## [26,] NA NA NA NA NA
## [27,] NA NA NA NA NA
## [28,] NA NA NA NA NA
## [29,] NA NA NA NA NA
## [30,] NA NA NA NA NA
## [31,] NA NA NA NA NA
## [32,] NA NA NA NA NA
## [33,] NA NA NA NA NA
## [34,] NA NA NA NA NA
## [35,] NA NA NA NA NA
## [36,] NA NA NA NA NA
## [37,] NA NA NA NA NA
## [38,] NA NA NA NA NA
## [39,] NA NA NA NA NA
## [40,] NA NA NA NA NA
## [41,] NA NA NA NA NA
## [42,] NA NA NA NA NA
## [43,] NA NA NA NA NA
## [44,] NA NA NA NA NA
## [45,] NA NA NA NA NA
## [46,] NA NA NA NA NA
## [47,] NA NA NA NA NA
## [48,] NA NA NA NA NA
## [49,] NA NA NA NA NA
## [50,] NA NA NA NA NA
## [51,] NA NA NA NA NA
## [52,] NA NA NA NA NA
## [53,] NA NA NA NA NA
## [54,] NA NA NA NA NA
## [55,] NA NA NA NA NA
## [56,] NA NA NA NA NA
## [57,] NA NA NA NA NA
## [58,] NA NA NA NA NA
## [59,] NA NA NA NA NA
## [60,] 0.1736106 0.059873006 0.4248806 0.2674951 0.07414069
## [61,] 0.1738296 0.059154950 0.4256130 0.2678023 0.07360016
## [62,] 0.1526054 0.029719914 0.4453575 0.2877056 0.08461152
## [63,] 0.1937821 0.032511268 0.4284116 0.2844726 0.06082250
## [64,] 0.1918677 0.021607029 0.4490965 0.2602499 0.07717874
## [65,] 0.1716463 0.019729115 0.4627220 0.2702979 0.07560465
## [66,] 0.1446470 -0.026955948 0.4149326 0.3895143 0.07786202
## [67,] 0.1165741 0.002779974 0.4287493 0.3842177 0.06767894
## [68,] 0.1910198 -0.001956280 0.4482710 0.2927450 0.06992053
## [69,] 0.2772466 -0.056848356 0.4532497 0.2681181 0.05823397
## [70,] 0.2650579 -0.057946862 0.4500397 0.2670508 0.07579839
tail(weight)
## AXP CIT EFX V WU
## [131,] -0.09608713 0.03318857 -0.07768133 0.7412319 0.3993480
## [132,] -0.24161637 0.05802012 -0.12005845 0.8681708 0.4354839
## [133,] -0.24457500 0.06087603 -0.12090505 0.8685630 0.4360410
## [134,] -0.21318118 0.06302270 -0.11748719 0.7901915 0.4774542
## [135,] -0.26366508 0.05792796 -0.07493431 0.7853584 0.4953130
## [136,] -0.24980958 0.05491734 -0.07162575 0.7741723 0.4923457
# Assign minimum variance weights to data_m$weight
capital = 100000
data_m$weight <- data_m$prices
data_m$weight[] <- NA
data_m$weight[] <- weight
data_m$weight[] = (capital / prices) * data_m$weight
models$mvp.hist.cov = bt.run(data_m, type='share')
## Latest weights :
## AXP CIT EFX V WU
## 2021-03-31 -26.37 5.79 -7.49 78.54 49.53
##
## Performance summary :
## CAGR Best Worst
## 6 14.1 -25.5
#=================================================================
# CAPM model (single factor model)
#*****************************************************************
# Create Constraints
#*****************************************************************
constraints = new.constraints(N, lb = -Inf, ub = +Inf)
# SUM x.i = 1
constraints = add.constraints(rep(1, N), 1, type = '=', constraints)
#
ret = prices / mlag(prices) - 1
weight_1 = coredata(ret)
weight_1[] = NA
#
# head(data_m$weight)
# compute covariance matrix based on historical 60 months returns
# i = 60
f <- fama_lib_month[dates]/100
for( i in 60:dim(weight_1)[1]) {
hist = ret[ (i- 60 + 1):i, ]
Xi <- hist
fi <- f$Mkt.RF[(i - 60 + 1):i, ]
fiti = lm(formula = Xi ~ fi)
sigF = as.numeric(var(fi))
beta_ = as.matrix(fiti$coefficients)
beta_ = as.matrix(beta_[-1,])
sigeps = crossprod(fiti$residuals)/(T-2)
# sigeps = as.matrix(var(fit$residuals)) # you can use this way too
sigeps = diag(diag(sigeps))
cov_1f = sigF*beta_%*%t(beta_)+sigeps
# cov_1f
ia$cov = cov_1f
weight_1[i, ] = min.risk.portfolio(ia, constraints)
}
dim(weight_1)
## [1] 136 5
# 195 8
head(weight_1, 70)
## AXP CIT EFX V WU
## [1,] NA NA NA NA NA
## [2,] NA NA NA NA NA
## [3,] NA NA NA NA NA
## [4,] NA NA NA NA NA
## [5,] NA NA NA NA NA
## [6,] NA NA NA NA NA
## [7,] NA NA NA NA NA
## [8,] NA NA NA NA NA
## [9,] NA NA NA NA NA
## [10,] NA NA NA NA NA
## [11,] NA NA NA NA NA
## [12,] NA NA NA NA NA
## [13,] NA NA NA NA NA
## [14,] NA NA NA NA NA
## [15,] NA NA NA NA NA
## [16,] NA NA NA NA NA
## [17,] NA NA NA NA NA
## [18,] NA NA NA NA NA
## [19,] NA NA NA NA NA
## [20,] NA NA NA NA NA
## [21,] NA NA NA NA NA
## [22,] NA NA NA NA NA
## [23,] NA NA NA NA NA
## [24,] NA NA NA NA NA
## [25,] NA NA NA NA NA
## [26,] NA NA NA NA NA
## [27,] NA NA NA NA NA
## [28,] NA NA NA NA NA
## [29,] NA NA NA NA NA
## [30,] NA NA NA NA NA
## [31,] NA NA NA NA NA
## [32,] NA NA NA NA NA
## [33,] NA NA NA NA NA
## [34,] NA NA NA NA NA
## [35,] NA NA NA NA NA
## [36,] NA NA NA NA NA
## [37,] NA NA NA NA NA
## [38,] NA NA NA NA NA
## [39,] NA NA NA NA NA
## [40,] NA NA NA NA NA
## [41,] NA NA NA NA NA
## [42,] NA NA NA NA NA
## [43,] NA NA NA NA NA
## [44,] NA NA NA NA NA
## [45,] NA NA NA NA NA
## [46,] NA NA NA NA NA
## [47,] NA NA NA NA NA
## [48,] NA NA NA NA NA
## [49,] NA NA NA NA NA
## [50,] NA NA NA NA NA
## [51,] NA NA NA NA NA
## [52,] NA NA NA NA NA
## [53,] NA NA NA NA NA
## [54,] NA NA NA NA NA
## [55,] NA NA NA NA NA
## [56,] NA NA NA NA NA
## [57,] NA NA NA NA NA
## [58,] NA NA NA NA NA
## [59,] NA NA NA NA NA
## [60,] 0.2267588 0.1397253 0.2780747 0.2378608 0.11758039
## [61,] 0.2268346 0.1392522 0.2785739 0.2381457 0.11719361
## [62,] 0.2122614 0.1447678 0.2792257 0.2463924 0.11735277
## [63,] 0.2134362 0.1536996 0.2681911 0.2452820 0.11939110
## [64,] 0.2124237 0.1526921 0.2769904 0.2394656 0.11842828
## [65,] 0.2184923 0.1493418 0.2818420 0.2341458 0.11617817
## [66,] 0.2154971 0.1339997 0.2692085 0.2765079 0.10478686
## [67,] 0.2118094 0.1356342 0.2771225 0.2725028 0.10293116
## [68,] 0.2233263 0.1350599 0.2890457 0.2500243 0.10254383
## [69,] 0.2387502 0.1287443 0.2891489 0.2454133 0.09794334
## [70,] 0.2376034 0.1299242 0.2866625 0.2444721 0.10133773
tail(weight_1)
## AXP CIT EFX V WU
## [131,] 0.1965798 0.04556283 0.1435287 0.3495973 0.2647313
## [132,] 0.1744289 0.05226084 0.1469375 0.3554550 0.2709178
## [133,] 0.1747856 0.05199667 0.1397882 0.3574815 0.2759481
## [134,] 0.2057173 0.05450894 0.1367237 0.3262764 0.2767737
## [135,] 0.1978111 0.05377082 0.1378753 0.3276153 0.2829275
## [136,] 0.2015658 0.05322949 0.1362282 0.3281289 0.2808477
# Assign minimum variance weights to data_m$weight
capital = 100000
data_m$weight <- data_m$prices
data_m$weight[] <- NA
data_m$weight[] <- weight_1
data_m$weight[] = (capital / prices) * data_m$weight
models$mvp.capm.cov = bt.run(data_m, type='share')
## Latest weights :
## AXP CIT EFX V WU
## 2021-03-31 19.78 5.38 13.79 32.76 28.29
##
## Performance summary :
## CAGR Best Worst
## 7.4 19.6 -20.5
models$mvp.capm.cov$cagr
## [1] 0.0737516
models$mvp.hist.cov$cagr
## [1] 0.05963121
#=================================================================
# FF 3 factor model
#*****************************************************************
# Create Constraints
#*****************************************************************
constraints = new.constraints(N, lb = -Inf, ub = +Inf)
# SUM x.i = 1
constraints = add.constraints(rep(1, N), 1, type = '=', constraints)
#
ret = prices / mlag(prices) - 1
weight_3 = coredata(ret)
weight_3[] = NA
#
# head(data_m$weight)
# compute covariance matrix based on historical 60 months returns
# i = 60
f <- fama_lib_month[dates]/100
for( i in 60:dim(weight_1)[1]) {
hist = ret[ (i- 60 + 1):i, ]
Xi <- hist
fi <- f[(i - 60 + 1):i, ]
fiti = lm(formula = Xi ~ fi)
sigF = as.matrix(var(fi))
beta_ = as.matrix(fiti$coefficients)
beta_ = as.matrix(beta_[-1,])
sigeps = crossprod(fiti$residuals)/(T-4) # note (T - 4)
# sigeps = as.matrix(var(fit$residuals)) # you can use this way too
sigeps = diag(diag(sigeps))
cov_3f = t(beta_)%*% sigF %*% beta_ + sigeps
# cov_1f
ia$cov = cov_3f
weight_3[i, ] = min.risk.portfolio(ia, constraints)
}
dim(weight_3)
## [1] 136 5
# 195 8
head(weight_3, 70)
## AXP CIT EFX V WU
## [1,] NA NA NA NA NA
## [2,] NA NA NA NA NA
## [3,] NA NA NA NA NA
## [4,] NA NA NA NA NA
## [5,] NA NA NA NA NA
## [6,] NA NA NA NA NA
## [7,] NA NA NA NA NA
## [8,] NA NA NA NA NA
## [9,] NA NA NA NA NA
## [10,] NA NA NA NA NA
## [11,] NA NA NA NA NA
## [12,] NA NA NA NA NA
## [13,] NA NA NA NA NA
## [14,] NA NA NA NA NA
## [15,] NA NA NA NA NA
## [16,] NA NA NA NA NA
## [17,] NA NA NA NA NA
## [18,] NA NA NA NA NA
## [19,] NA NA NA NA NA
## [20,] NA NA NA NA NA
## [21,] NA NA NA NA NA
## [22,] NA NA NA NA NA
## [23,] NA NA NA NA NA
## [24,] NA NA NA NA NA
## [25,] NA NA NA NA NA
## [26,] NA NA NA NA NA
## [27,] NA NA NA NA NA
## [28,] NA NA NA NA NA
## [29,] NA NA NA NA NA
## [30,] NA NA NA NA NA
## [31,] NA NA NA NA NA
## [32,] NA NA NA NA NA
## [33,] NA NA NA NA NA
## [34,] NA NA NA NA NA
## [35,] NA NA NA NA NA
## [36,] NA NA NA NA NA
## [37,] NA NA NA NA NA
## [38,] NA NA NA NA NA
## [39,] NA NA NA NA NA
## [40,] NA NA NA NA NA
## [41,] NA NA NA NA NA
## [42,] NA NA NA NA NA
## [43,] NA NA NA NA NA
## [44,] NA NA NA NA NA
## [45,] NA NA NA NA NA
## [46,] NA NA NA NA NA
## [47,] NA NA NA NA NA
## [48,] NA NA NA NA NA
## [49,] NA NA NA NA NA
## [50,] NA NA NA NA NA
## [51,] NA NA NA NA NA
## [52,] NA NA NA NA NA
## [53,] NA NA NA NA NA
## [54,] NA NA NA NA NA
## [55,] NA NA NA NA NA
## [56,] NA NA NA NA NA
## [57,] NA NA NA NA NA
## [58,] NA NA NA NA NA
## [59,] NA NA NA NA NA
## [60,] 0.2268474 0.1345365 0.2845171 0.2394584 0.11464066
## [61,] 0.2268753 0.1337620 0.2853501 0.2398765 0.11413613
## [62,] 0.2103763 0.1398293 0.2874491 0.2482942 0.11405107
## [63,] 0.2105597 0.1500175 0.2761357 0.2473076 0.11597953
## [64,] 0.2071415 0.1477333 0.2865434 0.2413339 0.11724785
## [65,] 0.2153305 0.1449013 0.2890256 0.2347371 0.11600544
## [66,] 0.2095910 0.1283711 0.2795525 0.2784572 0.10402826
## [67,] 0.2059771 0.1294575 0.2884884 0.2751013 0.10097571
## [68,] 0.2183147 0.1291350 0.3028389 0.2490450 0.10066639
## [69,] 0.2355544 0.1221977 0.3014564 0.2441741 0.09661736
## [70,] 0.2334938 0.1221313 0.3011809 0.2437870 0.09940704
tail(weight_3)
## AXP CIT EFX V WU
## [131,] 0.1949617 0.04995576 0.1386755 0.3504222 0.2659848
## [132,] 0.1738424 0.05668030 0.1431061 0.3551733 0.2711979
## [133,] 0.1740234 0.05646848 0.1362283 0.3575157 0.2757642
## [134,] 0.2042013 0.06201688 0.1304179 0.3241251 0.2792388
## [135,] 0.1959575 0.06001338 0.1337282 0.3252141 0.2850868
## [136,] 0.1992377 0.05980865 0.1324103 0.3256792 0.2828642
# Assign minimum variance weights to data_m$weight
capital = 100000
data_m$weight <- data_m$prices
data_m$weight[] <- NA
data_m$weight[] <- weight_3
data_m$weight[] = (capital / prices) * data_m$weight
models$mvp.ff3.cov = bt.run(data_m, type='share')
## Latest weights :
## AXP CIT EFX V WU
## 2021-03-31 19.6 6 13.37 32.52 28.51
##
## Performance summary :
## CAGR Best Worst
## 7.4 19.6 -20.6
#============================================================
# Principal Component Analysis (PCA)
#=============================================================
library(covFactorModel)
X_i <-X[1:60,]
factor_pca <- factorModel(X_i, type = "S", K = 3, max_iter = 10)
cbind(alpha = factor_pca$alpha, beta = factor_pca$beta)
## alpha factor1 factor2 factor3
## AXP 0.016732626 -0.03724781 -0.000884161 -0.02310065
## CIT 0.012016445 -0.05820076 -0.035763338 0.02288724
## EFX 0.018668319 -0.02408505 -0.011065154 -0.01171002
## V 0.020644689 -0.03045785 -0.007760490 -0.03044779
## WU 0.004388844 -0.06683948 0.039157384 0.01103845
#
# Statistical 3-factor model
K <- 3
X_trn <- X_i
T_trn <- dim(X_i)[1]
alpha <- colMeans(X_trn)
X_trn_ <- X_trn - matrix(alpha, T_trn, N, byrow = TRUE)
Sigma_prev <- matrix(0, N, N)
Sigma <- (1/(T_trn-1)) * t(X_trn_) %*% X_trn_
eigSigma <- eigen(Sigma)
while (norm(Sigma - Sigma_prev, "F")/norm(Sigma, "F") > 1e-3) {
B <- eigSigma$vectors[, 1:K] %*% diag(sqrt(eigSigma$values[1:K]), K, K)
Psi <- diag(diag(Sigma - B %*% t(B)))
Sigma_prev <- Sigma
Sigma <- B %*% t(B) + Psi
eigSigma <- eigen(Sigma - Psi)
}
# B: factor loadings
B
## [,1] [,2] [,3]
## [1,] -0.04182299 0.013416021 -0.0224280442
## [2,] -0.05720970 0.009805273 0.0429559985
## [3,] -0.02859771 0.024966469 0.0004055309
## [4,] -0.03413242 0.026554585 -0.0230637764
## [5,] -0.06505482 -0.042155380 -0.0114344636
# fiti = lm(formula = X_i ~ t(B))
Sigma_PCA3 <- Sigma
Sigma_PCA3
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0.003217207 0.001560810 0.0015218970 0.002301052 0.0024116822
## [2,] 0.001560810 0.005325473 0.0018982895 0.001222353 0.0028172433
## [3,] 0.001521897 0.001898289 0.0026658952 0.001629730 0.0008033108
## [4,] 0.002301052 0.001222353 0.0016297300 0.003080549 0.0013647815
## [5,] 0.002411682 0.002817243 0.0008033108 0.001364781 0.0062183316
diag(Sigma_PCA3)
## [1] 0.003217207 0.005325473 0.002665895 0.003080549 0.006218332
# error
norm(Sigma_PCA3 - cov(X_i), "F")
## [1] 0.00127828
#---------------------------------------------------------------
# By Eric Zivot
# use R princomp() function for principal component analysis
#---------------------------------------------------------------
pc.fit = princomp(X_i)
class(pc.fit)
## [1] "princomp"
names(pc.fit)
## [1] "sdev" "loadings" "center" "scale" "n.obs" "scores" "call"
pc.fit
## Call:
## princomp(x = X_i)
##
## Standard deviations:
## Comp.1 Comp.2 Comp.3 Comp.4 Comp.5
## 0.10511807 0.05766557 0.05441415 0.04026810 0.03475800
##
## 5 variables and 60 observations.
summary(pc.fit)
## Importance of components:
## Comp.1 Comp.2 Comp.3 Comp.4 Comp.5
## Standard deviation 0.1051181 0.05766557 0.05441415 0.04026810 0.0347580
## Proportion of Variance 0.5479516 0.16490001 0.14682876 0.08040993 0.0599097
## Cumulative Proportion 0.5479516 0.71285161 0.85968037 0.94009030 1.0000000
#eigenvalues & eigenvectors
eig.value <- eigen(cov(X_i))$values
pc.fit
## Call:
## princomp(x = X_i)
##
## Standard deviations:
## Comp.1 Comp.2 Comp.3 Comp.4 Comp.5
## 0.10511807 0.05766557 0.05441415 0.04026810 0.03475800
##
## 5 variables and 60 observations.
eig.vec <- eigen(cov(X_i))$vectors
#
B_hat <- eig.vec[, 1:3]%*%diag(sqrt(eig.value[1:3]), 3, 3)
B_hat
## [,1] [,2] [,3]
## [1,] -0.04182299 0.013416021 -0.0224280442
## [2,] -0.05720970 0.009805273 0.0429559985
## [3,] -0.02859771 0.024966469 0.0004055309
## [4,] -0.03413242 0.026554585 -0.0230637764
## [5,] -0.06505482 -0.042155380 -0.0114344636
#
#
plot(pc.fit)
loadings(pc.fit)
##
## Loadings:
## Comp.1 Comp.2 Comp.3 Comp.4 Comp.5
## AXP 0.395 0.231 0.409 0.209 0.762
## CIT 0.540 0.169 -0.783 0.259
## EFX 0.270 0.429 -0.861
## V 0.322 0.457 0.420 0.346 -0.625
## WU 0.614 -0.725 0.208 -0.165 -0.165
##
## Comp.1 Comp.2 Comp.3 Comp.4 Comp.5
## SS loadings 1.0 1.0 1.0 1.0 1.0
## Proportion Var 0.2 0.2 0.2 0.2 0.2
## Cumulative Var 0.2 0.4 0.6 0.8 1.0
pc.fit$loadings[, 1:3]
## Comp.1 Comp.2 Comp.3
## AXP 0.3945373 0.2307053 0.408723827
## CIT 0.5396879 0.1686139 -0.782820825
## EFX 0.2697766 0.4293297 -0.007390308
## V 0.3219883 0.4566393 0.420309273
## WU 0.6136949 -0.7249145 0.208379191
# pc factors are in the scores component. Note these scores are based on
# centered data
head(pc.fit$scores[, 1:3])
## Comp.1 Comp.2 Comp.3
## 2010-01-29 0.008189417 -0.01078726 -0.18323209
## 2010-02-26 -0.019294482 0.13827109 -0.12832772
## 2010-03-31 0.143240626 0.03199934 0.01747032
## 2010-04-30 0.068996788 -0.07140896 0.02091511
## 2010-05-28 -0.298183908 -0.10794932 -0.09650642
## 2010-06-30 -0.135752250 -0.03017940 0.03317428
pc.fit$scores[, 1:3]
## Comp.1 Comp.2 Comp.3
## 2010-01-29 0.008189417 -0.010787261 -0.1832320907
## 2010-02-26 -0.019294482 0.138271087 -0.1283277216
## 2010-03-31 0.143240626 0.031999340 0.0174703185
## 2010-04-30 0.068996788 -0.071408961 0.0209151075
## 2010-05-28 -0.298183908 -0.107949317 -0.0965064206
## 2010-06-30 -0.135752250 -0.030179398 0.0331742764
## 2010-07-30 0.159175706 0.023798921 0.0192047991
## 2010-08-31 -0.120108648 -0.070321090 -0.0884626853
## 2010-09-30 0.175586467 -0.023288929 -0.0141023041
## 2010-10-29 0.033029570 0.041989491 -0.0379859699
## 2010-11-30 -0.060966173 -0.030539021 0.0582272354
## 2010-12-31 0.101677971 -0.039387051 -0.1694317227
## 2011-01-31 0.040161313 -0.083348003 0.0053855311
## 2011-02-28 -0.006588653 -0.071562176 0.1043096474
## 2011-03-31 -0.028480156 0.064183845 0.0140622696
## 2011-04-29 0.031664546 -0.003131279 0.0623785269
## 2011-05-31 0.012426989 0.045587112 -0.0105952653
## 2011-06-30 -0.048754991 -0.020112937 0.0092591169
## 2011-07-29 -0.112149073 -0.019849875 0.0599467519
## 2011-08-31 -0.196802082 0.054505710 0.0738861197
## 2011-09-30 -0.195235296 -0.044683333 0.0241567637
## 2011-10-31 0.258784044 0.033601774 -0.0027558128
## 2011-11-30 -0.033711481 0.010330197 0.0114342168
## 2011-12-30 0.040004877 -0.017042988 -0.0073828337
## 2012-01-31 0.076564609 -0.023694804 -0.0470820664
## 2012-02-29 0.051693168 0.173901213 0.0110064971
## 2012-03-30 0.043392551 0.023345353 0.0295430764
## 2012-04-30 -0.004087038 -0.021529467 0.1022483824
## 2012-05-31 -0.197020705 -0.007612335 -0.0091397205
## 2012-06-29 0.064708426 0.019793747 0.0147748819
## 2012-07-31 0.020860929 -0.020281501 -0.0025915886
## 2012-08-31 -0.005352992 -0.029768829 -0.0289580372
## 2012-09-28 0.030614999 -0.018739216 -0.0227627770
## 2012-10-31 -0.216142737 0.233305344 -0.0180602286
## 2012-11-30 -0.002528713 0.034682708 0.0282307034
## 2012-12-31 0.081018351 -0.041505320 -0.0054234292
## 2013-01-31 0.099125874 0.024583448 -0.0447119115
## 2013-02-28 -0.033205942 -0.020316394 0.0257124961
## 2013-03-28 0.111852024 -0.001376150 0.0440252331
## 2013-04-30 -0.027851644 0.014322108 0.0104981665
## 2013-05-31 0.143767007 -0.031690936 0.0180538317
## 2013-06-28 0.005829391 -0.061131635 0.0006901823
## 2013-07-31 0.048835128 -0.028951930 -0.0728792837
## 2013-08-30 -0.097130224 -0.048692692 0.0078866948
## 2013-09-30 0.080659652 -0.008070169 0.0539234661
## 2013-10-31 -0.022932709 0.109285384 0.0315799839
## 2013-11-29 0.030184296 0.050381527 -0.0155235666
## 2013-12-31 0.076439312 0.022121293 0.0393936525
## 2014-01-31 -0.181620298 0.016747903 0.0160367413
## 2014-02-28 0.097756503 -0.032994821 0.0249360306
## 2014-03-31 -0.060311922 -0.044270685 -0.0395551004
## 2014-04-30 -0.130736975 -0.035551204 0.0453088010
## 2014-05-30 0.042726338 0.012791715 0.0143114151
## 2014-06-30 0.052566525 -0.063382861 -0.0058034734
## 2014-07-31 0.002745927 -0.007693564 -0.0909484661
## 2014-08-29 -0.018238218 0.001111672 0.0198102936
## 2014-09-30 -0.117420480 0.002027059 0.0029853398
## 2014-10-31 0.100633887 0.022024613 0.0221572957
## 2014-11-28 0.079703203 -0.027304925 0.0535697699
## 2014-12-31 -0.044008626 0.013458497 0.0117288596
# time series plot of principal component factors
# library(PerformanceAnalytics)
# chart.TimeSeries(pc.fit$scores[, 1, drop=FALSE], colorset="blue")
# compare with direct eigen-value analysis
# notice the sign change on the first set of loadings
eigen.fit = eigen(var(X_i))
names(eigen.fit)
## [1] "values" "vectors"
names(eigen.fit$values) = rownames(eigen.fit$vectors) = colnames(X_i)
cbind(pc.fit$loadings[,1:3], eigen.fit$vectors[, 1:3])
## Comp.1 Comp.2 Comp.3
## AXP 0.3945373 0.2307053 0.408723827 -0.3945373 0.2307053 -0.408723827
## CIT 0.5396879 0.1686139 -0.782820825 -0.5396879 0.1686139 0.782820825
## EFX 0.2697766 0.4293297 -0.007390308 -0.2697766 0.4293297 0.007390308
## V 0.3219883 0.4566393 0.420309273 -0.3219883 0.4566393 -0.420309273
## WU 0.6136949 -0.7249145 0.208379191 -0.6136949 -0.7249145 -0.208379191
# compute uncentered pc factors from eigenvectors and return data
pc.factors.uc = X_i %*% eigen.fit$vectors
colnames(pc.factors.uc) = paste(colnames(pc.fit$scores),".uc",sep="")
# compare centered and uncentered scores. Note sign change on first factor
# We can treat centered scores as unobservable factor values (F)
cbind(pc.fit$scores[,1,drop=F], -pc.factors.uc[, 1, drop=F])
## Comp.1 Comp.1.uc
## 2010-01-29 0.008189417 0.0356532261
## 2010-02-26 -0.019294482 0.0081693275
## 2010-03-31 0.143240626 0.1707044352
## 2010-04-30 0.068996788 0.0964605973
## 2010-05-28 -0.298183908 -0.2707200988
## 2010-06-30 -0.135752250 -0.1082884413
## 2010-07-30 0.159175706 0.1866395149
## 2010-08-31 -0.120108648 -0.0926448391
## 2010-09-30 0.175586467 0.2030502759
## 2010-10-29 0.033029570 0.0604933794
## 2010-11-30 -0.060966173 -0.0335023641
## 2010-12-31 0.101677971 0.1291417798
## 2011-01-31 0.040161313 0.0676251222
## 2011-02-28 -0.006588653 0.0208751561
## 2011-03-31 -0.028480156 -0.0010163467
## 2011-04-29 0.031664546 0.0591283552
## 2011-05-31 0.012426989 0.0398907980
## 2011-06-30 -0.048754991 -0.0212911818
## 2011-07-29 -0.112149073 -0.0846852642
## 2011-08-31 -0.196802082 -0.1693382735
## 2011-09-30 -0.195235296 -0.1677714867
## 2011-10-31 0.258784044 0.2862478533
## 2011-11-30 -0.033711481 -0.0062476719
## 2011-12-30 0.040004877 0.0674686859
## 2012-01-31 0.076564609 0.1040284179
## 2012-02-29 0.051693168 0.0791569770
## 2012-03-30 0.043392551 0.0708563600
## 2012-04-30 -0.004087038 0.0233767713
## 2012-05-31 -0.197020705 -0.1695568957
## 2012-06-29 0.064708426 0.0921722350
## 2012-07-31 0.020860929 0.0483247377
## 2012-08-31 -0.005352992 0.0221108169
## 2012-09-28 0.030614999 0.0580788076
## 2012-10-31 -0.216142737 -0.1886789283
## 2012-11-30 -0.002528713 0.0249350959
## 2012-12-31 0.081018351 0.1084821602
## 2013-01-31 0.099125874 0.1265896828
## 2013-02-28 -0.033205942 -0.0057421333
## 2013-03-28 0.111852024 0.1393158333
## 2013-04-30 -0.027851644 -0.0003878347
## 2013-05-31 0.143767007 0.1712308165
## 2013-06-28 0.005829391 0.0332931999
## 2013-07-31 0.048835128 0.0762989375
## 2013-08-30 -0.097130224 -0.0696664147
## 2013-09-30 0.080659652 0.1081234608
## 2013-10-31 -0.022932709 0.0045311002
## 2013-11-29 0.030184296 0.0576481055
## 2013-12-31 0.076439312 0.1039031214
## 2014-01-31 -0.181620298 -0.1541564893
## 2014-02-28 0.097756503 0.1252203125
## 2014-03-31 -0.060311922 -0.0328481129
## 2014-04-30 -0.130736975 -0.1032731658
## 2014-05-30 0.042726338 0.0701901473
## 2014-06-30 0.052566525 0.0800303341
## 2014-07-31 0.002745927 0.0302097359
## 2014-08-29 -0.018238218 0.0092255907
## 2014-09-30 -0.117420480 -0.0899566708
## 2014-10-31 0.100633887 0.1280976960
## 2014-11-28 0.079703203 0.1071670118
## 2014-12-31 -0.044008626 -0.0165448169
#
# use first 3 eigen-vectors to compue three factor (with normalization to have pos correlation with market)
# note: cannot treat pc as a portfolio b/c weights do not sum to unity
p3 = pc.fit$loadings[, 1:3]
p3 # refers to B
## Comp.1 Comp.2 Comp.3
## AXP 0.3945373 0.2307053 0.408723827
## CIT 0.5396879 0.1686139 -0.782820825
## EFX 0.2697766 0.4293297 -0.007390308
## V 0.3219883 0.4566393 0.420309273
## WU 0.6136949 -0.7249145 0.208379191
colSums(p3)
## Comp.1 Comp.2 Comp.3
## 2.1396850 0.5603736 0.2472012
# create factor mimicking portfolio by normalizing weights to unity
p3 = p3/colSums(p3)
p3
## Comp.1 Comp.2 Comp.3
## AXP 0.1843904 0.93326932 0.729377314
## CIT 0.9630859 0.07880316 -3.166736086
## EFX 1.0913241 0.76614891 -0.003453924
## V 0.1504840 1.84723771 0.750051816
## WU 1.0951530 -0.33879497 0.842953948
barplot(p3[,1], horiz=F, main="Factor mimicking weights", col="blue", cex.names = 0.75, las=2)
# create first 3 factors
f3 = X_i %*% p3
head(f3)
## Comp.1 Comp.2 Comp.3
## [1,] 0.146446268 -0.13166045 -0.59194791
## [2,] -0.004487801 0.15823639 -0.54315522
## [3,] 0.298734927 0.26682847 -0.04127011
## [4,] 0.077171825 0.02416165 0.01034856
## [5,] -0.389742459 -0.52841644 -0.05392176
## [6,] -0.227507680 -0.08399808 0.18235557
head(pc.fit$scores[, 1:3])
## Comp.1 Comp.2 Comp.3
## 2010-01-29 0.008189417 -0.01078726 -0.18323209
## 2010-02-26 -0.019294482 0.13827109 -0.12832772
## 2010-03-31 0.143240626 0.03199934 0.01747032
## 2010-04-30 0.068996788 -0.07140896 0.02091511
## 2010-05-28 -0.298183908 -0.10794932 -0.09650642
## 2010-06-30 -0.135752250 -0.03017940 0.03317428
# chart.TimeSeries(f1, main="First principal component factor", colorset="blue")
# estimate factor betas by multivariate regression
n.obs <- dim(X_i)[1]
X.mat = cbind(rep(1, n.obs), f3)
colnames(X.mat) = c("intercept", "Factor 1", "Factor 2", "Factor 3")
XX.mat = crossprod(X.mat)
# multivariate least squares
G.hat = solve(XX.mat)%*%crossprod(X.mat, X_i)
t(G.hat)
## intercept Factor 1 Factor 2 Factor 3
## AXP -0.001500268 0.13002109 0.19368183 0.063476179
## CIT -0.001523326 0.18798351 0.05685706 -0.241979512
## EFX 0.004749503 0.12217519 0.12782575 -0.006238398
## V -0.001680584 -0.01324126 0.34094848 0.018580885
## WU -0.002909746 0.60598014 -0.25683890 0.205774574
# can also use solve(qr(X.mat), returns.mat)
beta.hat = G.hat[2:4,]
beta.hat
## AXP CIT EFX V WU
## Factor 1 0.13002109 0.18798351 0.122175193 -0.01324126 0.6059801
## Factor 2 0.19368183 0.05685706 0.127825753 0.34094848 -0.2568389
## Factor 3 0.06347618 -0.24197951 -0.006238398 0.01858088 0.2057746
B
## [,1] [,2] [,3]
## [1,] -0.04182299 0.013416021 -0.0224280442
## [2,] -0.05720970 0.009805273 0.0429559985
## [3,] -0.02859771 0.024966469 0.0004055309
## [4,] -0.03413242 0.026554585 -0.0230637764
## [5,] -0.06505482 -0.042155380 -0.0114344636
E.hat = X_i - X.mat%*%G.hat
diagD.hat = diag(crossprod(E.hat)/(n.obs-4))
# compute covariance/correlation matrices with three pc factor
cov.pc3 = t(beta.hat)%*%var(f3)%*%(beta.hat) + diag(diagD.hat)
cov.pc3
## AXP CIT EFX V WU
## AXP 0.003275959 0.001473543 0.001610502 0.002206241 0.002093017
## CIT 0.001473543 0.005332755 0.001940727 0.001244919 0.002500599
## EFX 0.001610502 0.001940727 0.002734488 0.001609023 0.001827145
## V 0.002206241 0.001244919 0.001609023 0.003103769 0.001045026
## WU 0.002093017 0.002500599 0.001827145 0.001045026 0.006245163
Sigma_PCA3
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0.003217207 0.001560810 0.0015218970 0.002301052 0.0024116822
## [2,] 0.001560810 0.005325473 0.0018982895 0.001222353 0.0028172433
## [3,] 0.001521897 0.001898289 0.0026658952 0.001629730 0.0008033108
## [4,] 0.002301052 0.001222353 0.0016297300 0.003080549 0.0013647815
## [5,] 0.002411682 0.002817243 0.0008033108 0.001364781 0.0062183316
diag(cov.pc3)
## AXP CIT EFX V WU
## 0.003275959 0.005332755 0.002734488 0.003103769 0.006245163
# error difference between pca and empirical covariance matrix
norm(cov.pc3 - cov(X_i), "F")
## [1] 0.001755478
norm(Sigma_PCA3 - cov(X_i), "F")
## [1] 0.00127828
#==========================================================
# Plot perfromance
plotbt(models, plotX = T, log = 'y', LeftMargin = 3)
mtext('Cumulative Performance', side = 2, line = 1)
# Plot Strategy Statistics Side by Side
layout(1:1)
plotbt.strategy.sidebyside(models)
# Plot transition maps
layout(1:len(models))
for(m in names(models)) {
plotbt.transition.map(models[[m]]$weight, name=m)
legend('topright', legend = m, bty = 'n')
}
#