Final Project: Rerun the coding file ‘final_2021_solution_update.R’ and use the data you collected from the market. Make sure you collect or download data from the market (not restricted to stocks) and try to keep your portfolio including at least 5 assets. Show the performance of MVP (minimum variance portfolio) based on equal weighting, single factor, three factor and PCA models.
#===========================================================
# CLEANING ENVIRONMENT
#===========================================================
rm(list = ls())
#===========================================================
# 1. LOAD PACKAGES
#===========================================================
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)
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)
library(covFactorModel)
library(RColorBrewer)
#===========================================================
# 2. IMPORTING DATA_7 INDONESIAN NON-CYCLICAL SECTOR STOCKS
#===========================================================
tickers = spl('UNVR.JK,INDF.JK,GGRM.JK,JPFA.JK,HMSP.JK,MYOR.JK,ULTJ.JK')
datas <- new.env()
getSymbols(tickers, src = 'yahoo', from = '1980-01-01', env = datas, auto.assign = T)
## 'getSymbols' currently uses auto.assign=TRUE by default, but will
## use auto.assign=FALSE in 0.5-0. You will still be able to use
## 'loadSymbols' to automatically load data. getOption("getSymbols.env")
## and getOption("getSymbols.auto.assign") will still be checked for
## alternate defaults.
##
## This message is shown once per session and may be disabled by setting
## options("getSymbols.warning4.0"=FALSE). See ?getSymbols for details.
## Warning: INDF.JK contains missing values. Some functions will not work if
## objects contain missing values in the middle of the series. Consider using
## na.omit(), na.approx(), na.fill(), etc to remove or replace them.
## Warning: GGRM.JK contains missing values. Some functions will not work if
## objects contain missing values in the middle of the series. Consider using
## na.omit(), na.approx(), na.fill(), etc to remove or replace them.
## Warning: JPFA.JK contains missing values. Some functions will not work if
## objects contain missing values in the middle of the series. Consider using
## na.omit(), na.approx(), na.fill(), etc to remove or replace them.
## Warning: HMSP.JK contains missing values. Some functions will not work if
## objects contain missing values in the middle of the series. Consider using
## na.omit(), na.approx(), na.fill(), etc to remove or replace them.
## pausing 1 second between requests for more than 5 symbols
## Warning: MYOR.JK contains missing values. Some functions will not work if
## objects contain missing values in the middle of the series. Consider using
## na.omit(), na.approx(), na.fill(), etc to remove or replace them.
## pausing 1 second between requests for more than 5 symbols
## Warning: ULTJ.JK contains missing values. Some functions will not work if
## objects contain missing values in the middle of the series. Consider using
## na.omit(), na.approx(), na.fill(), etc to remove or replace them.
## pausing 1 second between requests for more than 5 symbols
## [1] "UNVR.JK" "INDF.JK" "GGRM.JK" "JPFA.JK" "HMSP.JK" "MYOR.JK" "ULTJ.JK"
for(i in ls(datas)) datas[[i]] = adjustOHLC(datas[[i]], use.Adjusted=T)
names(datas$UNVR.JK)
## [1] "UNVR.JK.Open" "UNVR.JK.High" "UNVR.JK.Low" "UNVR.JK.Close"
## [5] "UNVR.JK.Volume" "UNVR.JK.Adjusted"
head(datas$UNVR.JK)
## UNVR.JK.Open UNVR.JK.High UNVR.JK.Low UNVR.JK.Close UNVR.JK.Volume
## 2003-09-03 354.3524 388.9234 348.5906 388.9234 43162500
## 2003-09-04 397.5661 432.1371 388.9234 394.6852 82850000
## 2003-09-05 394.6852 403.3279 391.8043 397.5661 24055000
## 2003-09-08 397.5662 397.5662 383.1616 391.8044 18007500
## 2003-09-09 391.8043 391.8043 380.2806 383.1616 14075000
## 2003-09-10 380.2807 380.2807 368.7570 368.7570 14190000
## UNVR.JK.Adjusted
## 2003-09-03 388.9234
## 2003-09-04 394.6852
## 2003-09-05 397.5661
## 2003-09-08 391.8044
## 2003-09-09 383.1616
## 2003-09-10 368.7570
#Data Preparation
bt.prep(datas, align='remove.na')
names(datas)
## [1] "prices" "UNVR.JK" "MYOR.JK" "dates"
## [5] "weight" ".getSymbols" "symbolnames" "execution.price"
## [9] "JPFA.JK" "GGRM.JK" "HMSP.JK" "ULTJ.JK"
## [13] "INDF.JK"
#Data Checking
head(datas$HMSP.JK)
## HMSP.JK.Open HMSP.JK.High HMSP.JK.Low HMSP.JK.Close
## 2005-09-29 07:00:00 151.9392 152.8329 151.9392 151.9392
## 2005-09-30 07:00:00 155.5142 156.4079 151.9391 155.5142
## 2005-10-03 07:00:00 155.5142 155.5142 151.9391 155.5142
## 2005-10-04 07:00:00 154.6204 155.5142 154.6204 154.6204
## 2005-10-05 07:00:00 151.9392 153.7267 151.9392 151.9392
## 2005-10-06 07:00:00 153.7266 153.7266 153.7266 153.7266
## HMSP.JK.Volume HMSP.JK.Adjusted
## 2005-09-29 07:00:00 2627165 151.9392
## 2005-09-30 07:00:00 19650667 155.5142
## 2005-10-03 07:00:00 159222 155.5142
## 2005-10-04 07:00:00 1831054 154.6204
## 2005-10-05 07:00:00 1074749 151.9392
## 2005-10-06 07:00:00 66342 153.7266
head(datas$prices)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK
## 2005-09-29 07:00:00 7249.801 151.9392 475.9389 31.37117 17.88706 58.47855
## 2005-09-30 07:00:00 7350.961 155.5142 496.3361 31.37117 18.16654 58.47855
## 2005-10-03 07:00:00 7418.402 155.5142 469.1397 31.37117 17.88706 58.47855
## 2005-10-04 07:00:00 7587.000 154.6204 496.3361 31.37117 19.56397 59.64812
## 2005-10-05 07:00:00 7620.721 151.9392 496.3361 31.37117 19.84346 59.64812
## 2005-10-06 07:00:00 7418.402 153.7266 475.9389 32.83030 19.28448 63.15683
## UNVR.JK
## 2005-09-29 07:00:00 522.6602
## 2005-09-30 07:00:00 525.8865
## 2005-10-03 07:00:00 542.0180
## 2005-10-04 07:00:00 564.6020
## 2005-10-05 07:00:00 554.9231
## 2005-10-06 07:00:00 574.2809
#===========================================================
# 3. CALCULATING MONTHLY PRICES & RETURNS
#===========================================================
#Convert daily prices into monthly prices
prices_monthly <- to.monthly(datas$prices, indexAt = "last", OHLC = FALSE) # indexAt = 'endof'
## Warning in to.period(x, "months", indexAt = indexAt, name = name, ...): missing
## values removed from data
head(prices_monthly)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK UNVR.JK
## 2005-09-30 7350.961 155.5142 496.3361 31.37117 18.16654 58.47855 525.8865
## 2005-10-31 6878.881 162.7312 557.5283 35.74855 17.88706 59.64812 564.6020
## 2005-11-30 7384.679 160.8714 577.9257 34.28942 16.48963 58.47855 558.1495
## 2005-12-30 7856.762 165.5209 618.7205 35.74855 22.91779 72.51341 559.3682
## 2006-01-31 7283.522 157.1518 598.3231 38.66680 23.47676 63.15683 562.6393
## 2006-02-28 7418.402 158.0818 571.1265 40.12592 20.40243 59.64812 559.3682
#Convert monthly prices into monthly return
monthly.ret <- na.omit(Return.calculate(prices_monthly, method = "discrete"))
head(monthly.ret)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK
## 2005-10-31 -0.06422012 0.046407710 0.12328789 0.13953517 -0.01538476
## 2005-11-30 0.07352908 -0.011428483 0.03658541 -0.04081637 -0.07812499
## 2005-12-30 0.06392729 0.028901711 0.07058831 0.04255324 0.38983052
## 2006-01-31 -0.07296133 -0.050561982 -0.03296716 0.08163272 0.02439022
## 2006-02-28 0.01851856 0.005917411 -0.04545460 0.03773568 -0.13095226
## 2006-03-31 -0.04545462 -0.023529525 0.05952377 0.00000000 0.06849303
## ULTJ.JK UNVR.JK
## 2005-10-31 0.02000007 0.073619530
## 2005-11-30 -0.01960791 -0.011428431
## 2005-12-30 0.24000014 0.002183555
## 2006-01-31 -0.12903229 0.005847770
## 2006-02-28 -0.05555556 -0.005813773
## 2006-03-31 0.07843117 -0.005847880
#===========================================================
# 4. FAMA FRENCH FACTORS
#===========================================================
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
#*****************************************************************
# In this case we will use data from 2005-01 to 2021-03
#*****************************************************************
dates <- '2005-01::2021-05'
X <- monthly.ret[dates]
head(X)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK
## 2005-10-31 -0.06422012 0.046407710 0.12328789 0.13953517 -0.01538476
## 2005-11-30 0.07352908 -0.011428483 0.03658541 -0.04081637 -0.07812499
## 2005-12-30 0.06392729 0.028901711 0.07058831 0.04255324 0.38983052
## 2006-01-31 -0.07296133 -0.050561982 -0.03296716 0.08163272 0.02439022
## 2006-02-28 0.01851856 0.005917411 -0.04545460 0.03773568 -0.13095226
## 2006-03-31 -0.04545462 -0.023529525 0.05952377 0.00000000 0.06849303
## ULTJ.JK UNVR.JK
## 2005-10-31 0.02000007 0.073619530
## 2005-11-30 -0.01960791 -0.011428431
## 2005-12-30 0.24000014 0.002183555
## 2006-01-31 -0.12903229 0.005847770
## 2006-02-28 -0.05555556 -0.005813773
## 2006-03-31 0.07843117 -0.005847880
dim(X)
## [1] 188 7
#Convert daily prices into monthly prices
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] 196 3
#=============================================================================
# 5. COMPUTING ESTIMATED COEFFICIENTS
#=============================================================================
#****************************************************************************
# First Way: Professor Palomar's Package for Computing Estimated Coefficients
# Based on CAPM Model, Computing Covariance Matrix for the 8-stocks Portfolio
# Using Past 60-month Returns from 2015/01 to 2019/12
#****************************************************************************
insample_range <- '2013-01::2019-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
## GGRM.JK 0.004313663 0.2195276
## HMSP.JK 0.004235259 -0.4012193
## INDF.JK 0.008618843 1.1827043
## JPFA.JK 0.015389381 1.1988523
## MYOR.JK 0.016557086 -1.6554832
## ULTJ.JK 0.024315814 -0.6525357
## UNVR.JK 0.011233395 -1.8496954
#****************************************************************************
#Second way : Using matrix notation to compute covariance matrix
#****************************************************************************
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
## GGRM.JK 0.004313663 0.2195276
## HMSP.JK 0.004235259 -0.4012193
## INDF.JK 0.008618843 1.1827043
## JPFA.JK 0.015389381 1.1988523
## MYOR.JK 0.016557086 -1.6554832
## ULTJ.JK 0.024315814 -0.6525357
## UNVR.JK 0.011233395 -1.8496954
#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
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK
## GGRM.JK 5.478408e-03 -4.897683e-06 1.443727e-05 1.463439e-05 -2.020848e-05
## HMSP.JK -4.897683e-06 5.678143e-03 -2.638625e-05 -2.674652e-05 3.693400e-05
## INDF.JK 1.443727e-05 -2.638625e-05 4.735230e-03 7.884273e-05 -1.088731e-04
## JPFA.JK 1.463439e-05 -2.674652e-05 7.884273e-05 2.183516e-02 -1.103596e-04
## MYOR.JK -2.020848e-05 3.693400e-05 -1.088731e-04 -1.103596e-04 6.738179e-03
## ULTJ.JK -7.965502e-06 1.455814e-05 -4.291413e-05 -4.350005e-05 6.006879e-05
## UNVR.JK -2.257923e-05 4.126689e-05 -1.216455e-04 -1.233064e-04 1.702726e-04
## ULTJ.JK UNVR.JK
## GGRM.JK -7.965502e-06 -2.257923e-05
## HMSP.JK 1.455814e-05 4.126689e-05
## INDF.JK -4.291413e-05 -1.216455e-04
## JPFA.JK -4.350005e-05 -1.233064e-04
## MYOR.JK 6.006879e-05 1.702726e-04
## ULTJ.JK 1.108788e-02 6.711573e-05
## UNVR.JK 6.711573e-05 3.404555e-03
#****************************************************************************
#Third way : Using lm() function 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]
## GGRM.JK 0.2195276
## HMSP.JK -0.4012193
## INDF.JK 1.1827043
## JPFA.JK 1.1988523
## MYOR.JK -1.6554832
## ULTJ.JK -0.6525357
## UNVR.JK -1.8496954
sigeps = crossprod(fit$residuals)/(T-2)
sigeps = diag(diag(sigeps))
sigeps
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 0.005475728 0.000000000 0.000000000 0.00000000 0.000000000 0.0000000
## [2,] 0.000000000 0.005669191 0.000000000 0.00000000 0.000000000 0.0000000
## [3,] 0.000000000 0.000000000 0.004657449 0.00000000 0.000000000 0.0000000
## [4,] 0.000000000 0.000000000 0.000000000 0.02175524 0.000000000 0.0000000
## [5,] 0.000000000 0.000000000 0.000000000 0.00000000 0.006585785 0.0000000
## [6,] 0.000000000 0.000000000 0.000000000 0.00000000 0.000000000 0.0110642
## [7,] 0.000000000 0.000000000 0.000000000 0.00000000 0.000000000 0.0000000
## [,7]
## [1,] 0.000000000
## [2,] 0.000000000
## [3,] 0.000000000
## [4,] 0.000000000
## [5,] 0.000000000
## [6,] 0.000000000
## [7,] 0.003214307
cov_1f = sigF*beta_%*%t(beta_)+sigeps
cov_1f # This is covariance matrix computed from single factor model (from lm())
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK
## GGRM.JK 5.478408e-03 -4.897683e-06 1.443727e-05 1.463439e-05 -2.020848e-05
## HMSP.JK -4.897683e-06 5.678143e-03 -2.638625e-05 -2.674652e-05 3.693400e-05
## INDF.JK 1.443727e-05 -2.638625e-05 4.735230e-03 7.884273e-05 -1.088731e-04
## JPFA.JK 1.463439e-05 -2.674652e-05 7.884273e-05 2.183516e-02 -1.103596e-04
## MYOR.JK -2.020848e-05 3.693400e-05 -1.088731e-04 -1.103596e-04 6.738179e-03
## ULTJ.JK -7.965502e-06 1.455814e-05 -4.291413e-05 -4.350005e-05 6.006879e-05
## UNVR.JK -2.257923e-05 4.126689e-05 -1.216455e-04 -1.233064e-04 1.702726e-04
## ULTJ.JK UNVR.JK
## GGRM.JK -7.965502e-06 -2.257923e-05
## HMSP.JK 1.455814e-05 4.126689e-05
## INDF.JK -4.291413e-05 -1.216455e-04
## JPFA.JK -4.350005e-05 -1.233064e-04
## MYOR.JK 6.006879e-05 1.702726e-04
## ULTJ.JK 1.108788e-02 6.711573e-05
## UNVR.JK 6.711573e-05 3.404555e-03
#===========================================================
# 6. BACKTESTING PORTFOLIO_SIT PACKAGE
#===========================================================
dates <- '2005-01::2021-03'
dates <- '2005-01::2021-05'
X <- monthly.ret[dates]
head(X)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK
## 2005-10-31 -0.06422012 0.046407710 0.12328789 0.13953517 -0.01538476
## 2005-11-30 0.07352908 -0.011428483 0.03658541 -0.04081637 -0.07812499
## 2005-12-30 0.06392729 0.028901711 0.07058831 0.04255324 0.38983052
## 2006-01-31 -0.07296133 -0.050561982 -0.03296716 0.08163272 0.02439022
## 2006-02-28 0.01851856 0.005917411 -0.04545460 0.03773568 -0.13095226
## 2006-03-31 -0.04545462 -0.023529525 0.05952377 0.00000000 0.06849303
## ULTJ.JK UNVR.JK
## 2005-10-31 0.02000007 0.073619530
## 2005-11-30 -0.01960791 -0.011428431
## 2005-12-30 0.24000014 0.002183555
## 2006-01-31 -0.12903229 0.005847770
## 2006-02-28 -0.05555556 -0.005813773
## 2006-03-31 0.07843117 -0.005847880
dim(X)
## [1] 188 7
tail(X)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK
## 2020-12-30 -0.029585799 -0.01311475 -0.03521127 0.09737833 0.13865546
## 2021-01-29 -0.079878049 -0.12956809 -0.11678832 -0.07167239 0.02952030
## 2021-02-26 -0.032471836 0.01908401 0.00000000 0.12867645 -0.02867384
## 2021-03-31 -0.008904110 0.02996253 0.09090909 0.25081439 -0.03321033
## 2021-04-30 -0.002073255 -0.04000003 -0.01136364 0.11959599 -0.06106870
## 2021-05-31 -0.081717452 -0.03787877 -0.02681992 -0.05687204 0.03252033
## ULTJ.JK UNVR.JK
## 2020-12-30 -0.006211180 -0.03770626
## 2021-01-29 -0.056250000 -0.05782312
## 2021-02-26 0.003311258 0.01083030
## 2021-03-31 0.000000000 -0.06071427
## 2021-04-30 0.062706271 -0.08745248
## 2021-05-31 -0.046583851 -0.02499995
#Convert daily prices to the monthly prices at the expected date
prices_monthly <- to.monthly(datas$prices, indexAt = "last", OHLC = FALSE) # indexAt = 'endof'
## Warning in to.period(x, "months", indexAt = indexAt, name = name, ...): missing
## values removed from data
head(prices_monthly)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK UNVR.JK
## 2005-09-30 7350.961 155.5142 496.3361 31.37117 18.16654 58.47855 525.8865
## 2005-10-31 6878.881 162.7312 557.5283 35.74855 17.88706 59.64812 564.6020
## 2005-11-30 7384.679 160.8714 577.9257 34.28942 16.48963 58.47855 558.1495
## 2005-12-30 7856.762 165.5209 618.7205 35.74855 22.91779 72.51341 559.3682
## 2006-01-31 7283.522 157.1518 598.3231 38.66680 23.47676 63.15683 562.6393
## 2006-02-28 7418.402 158.0818 571.1265 40.12592 20.40243 59.64812 559.3682
prices_monthly <- prices_monthly[dates]
head(prices_monthly)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK UNVR.JK
## 2005-09-30 7350.961 155.5142 496.3361 31.37117 18.16654 58.47855 525.8865
## 2005-10-31 6878.881 162.7312 557.5283 35.74855 17.88706 59.64812 564.6020
## 2005-11-30 7384.679 160.8714 577.9257 34.28942 16.48963 58.47855 558.1495
## 2005-12-30 7856.762 165.5209 618.7205 35.74855 22.91779 72.51341 559.3682
## 2006-01-31 7283.522 157.1518 598.3231 38.66680 23.47676 63.15683 562.6393
## 2006-02-28 7418.402 158.0818 571.1265 40.12592 20.40243 59.64812 559.3682
tail(prices_monthly)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK UNVR.JK
## 2020-12-30 41000 1422.310 6850 1437.995 2710 1600 7219.333
## 2021-01-29 37725 1238.024 6050 1334.931 2790 1510 6801.889
## 2021-02-26 36500 1261.651 6050 1506.705 2710 1515 6875.555
## 2021-03-31 36175 1299.453 6600 1884.608 2620 1515 6458.111
## 2021-04-30 36100 1247.475 6525 2110.000 2460 1610 5893.333
## 2021-05-31 33150 1200.222 6350 1990.000 2540 1535 5746.000
#*****************************************************************
# 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] "ULTJ.JK" "MYOR.JK" "HMSP.JK" "JPFA.JK" "GGRM.JK" "INDF.JK" "UNVR.JK"
# Check if the column name is 'Close'
head(data_m$UNVR.JK)
## Close
## 2005-09-30 7350.961
## 2005-10-31 6878.881
## 2005-11-30 7384.679
## 2005-12-30 7856.762
## 2006-01-31 7283.522
## 2006-02-28 7418.402
#
bt.prep(data_m, align='remove.na', dates = dates)
names(data_m)
## [1] "prices" "execution.price" "weight" "dates"
## [5] "symbolnames" "ULTJ.JK" "MYOR.JK" "HMSP.JK"
## [9] "JPFA.JK" "GGRM.JK" "INDF.JK" "UNVR.JK"
#===========================================================
# 7. CALCULATING MINIMUM VARIANCE PORTFOLIO (MVP)
#===========================================================
#===========================================================
# a. 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)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK
## 2005-09-30 07:00:00 0.1428571 0.1428571 0.1428571 0.1428571 0.1428571 0.1428571
## 2005-10-31 07:00:00 0.1428571 0.1428571 0.1428571 0.1428571 0.1428571 0.1428571
## 2005-11-30 07:00:00 0.1428571 0.1428571 0.1428571 0.1428571 0.1428571 0.1428571
## 2005-12-30 07:00:00 0.1428571 0.1428571 0.1428571 0.1428571 0.1428571 0.1428571
## 2006-01-31 07:00:00 0.1428571 0.1428571 0.1428571 0.1428571 0.1428571 0.1428571
## 2006-02-28 07:00:00 0.1428571 0.1428571 0.1428571 0.1428571 0.1428571 0.1428571
## UNVR.JK
## 2005-09-30 07:00:00 0.1428571
## 2005-10-31 07:00:00 0.1428571
## 2005-11-30 07:00:00 0.1428571
## 2005-12-30 07:00:00 0.1428571
## 2006-01-31 07:00:00 0.1428571
## 2006-02-28 07:00:00 0.1428571
data_m$weight[1:83, ] <- NA
models$equal.weight = bt.run.share(data_m)
## Latest weights :
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK UNVR.JK
## 2021-05-31 07:00:00 8.74 21.27 5.07 16.77 35.62 7.58 4.95
##
## Performance summary :
## CAGR Best Worst
## 5.9 14.2 -10.9
head(models$equal.weight$ret, 86)
## GGRM.JK
## 2005-09-30 07:00:00 0.00000000
## 2005-10-31 07:00:00 0.00000000
## 2005-11-30 07:00:00 0.00000000
## 2005-12-30 07:00:00 0.00000000
## 2006-01-31 07:00:00 0.00000000
## 2006-02-28 07:00:00 0.00000000
## 2006-03-31 07:00:00 0.00000000
## 2006-04-28 07:00:00 0.00000000
## 2006-05-31 07:00:00 0.00000000
## 2006-06-30 07:00:00 0.00000000
## 2006-07-31 07:00:00 0.00000000
## 2006-08-31 07:00:00 0.00000000
## 2006-09-29 07:00:00 0.00000000
## 2006-10-31 07:00:00 0.00000000
## 2006-11-30 07:00:00 0.00000000
## 2006-12-28 07:00:00 0.00000000
## 2007-01-31 07:00:00 0.00000000
## 2007-02-28 07:00:00 0.00000000
## 2007-03-30 07:00:00 0.00000000
## 2007-04-30 07:00:00 0.00000000
## 2007-05-31 07:00:00 0.00000000
## 2007-06-29 07:00:00 0.00000000
## 2007-07-31 07:00:00 0.00000000
## 2007-08-31 07:00:00 0.00000000
## 2007-09-28 07:00:00 0.00000000
## 2007-10-31 07:00:00 0.00000000
## 2007-11-30 07:00:00 0.00000000
## 2007-12-31 07:00:00 0.00000000
## 2008-01-31 07:00:00 0.00000000
## 2008-02-29 07:00:00 0.00000000
## 2008-03-31 07:00:00 0.00000000
## 2008-04-30 07:00:00 0.00000000
## 2008-05-30 07:00:00 0.00000000
## 2008-06-30 07:00:00 0.00000000
## 2008-07-29 07:00:00 0.00000000
## 2008-08-29 07:00:00 0.00000000
## 2008-09-26 07:00:00 0.00000000
## 2008-10-31 07:00:00 0.00000000
## 2008-11-28 07:00:00 0.00000000
## 2008-12-31 07:00:00 0.00000000
## 2009-01-30 07:00:00 0.00000000
## 2009-02-27 07:00:00 0.00000000
## 2009-03-31 07:00:00 0.00000000
## 2009-04-30 07:00:00 0.00000000
## 2009-05-29 07:00:00 0.00000000
## 2009-06-30 07:00:00 0.00000000
## 2009-07-31 07:00:00 0.00000000
## 2009-08-31 07:00:00 0.00000000
## 2009-09-30 07:00:00 0.00000000
## 2009-10-30 07:00:00 0.00000000
## 2009-11-30 07:00:00 0.00000000
## 2009-12-30 07:00:00 0.00000000
## 2010-01-29 07:00:00 0.00000000
## 2010-02-25 07:00:00 0.00000000
## 2010-03-31 07:00:00 0.00000000
## 2010-04-30 07:00:00 0.00000000
## 2010-05-31 07:00:00 0.00000000
## 2010-06-30 07:00:00 0.00000000
## 2010-07-30 07:00:00 0.00000000
## 2010-08-31 07:00:00 0.00000000
## 2010-09-30 07:00:00 0.00000000
## 2010-10-29 07:00:00 0.00000000
## 2010-11-30 07:00:00 0.00000000
## 2010-12-30 07:00:00 0.00000000
## 2011-01-31 07:00:00 0.00000000
## 2011-02-28 07:00:00 0.00000000
## 2011-03-31 07:00:00 0.00000000
## 2011-04-29 07:00:00 0.00000000
## 2011-05-31 07:00:00 0.00000000
## 2011-06-30 07:00:00 0.00000000
## 2011-07-29 07:00:00 0.00000000
## 2011-08-26 07:00:00 0.00000000
## 2011-09-30 07:00:00 0.00000000
## 2011-10-31 07:00:00 0.00000000
## 2011-11-30 07:00:00 0.00000000
## 2011-12-30 07:00:00 0.00000000
## 2012-01-31 07:00:00 0.00000000
## 2012-02-29 07:00:00 0.00000000
## 2012-03-30 07:00:00 0.00000000
## 2012-04-30 07:00:00 0.00000000
## 2012-05-31 07:00:00 0.00000000
## 2012-06-29 07:00:00 0.00000000
## 2012-07-31 07:00:00 0.00000000
## 2012-08-31 07:00:00 0.00000000
## 2012-09-28 07:00:00 0.02360928
## 2012-10-31 07:00:00 0.04232746
# 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 :
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK UNVR.JK
## 2021-05-31 07:00:00 14.29 14.29 14.29 14.29 14.29 14.29 14.29
##
## Performance summary :
## CAGR Best Worst
## 6.1 12 -10.7
head(models$equal.weight.share$ret, 86)
## GGRM.JK
## 2005-09-30 07:00:00 0.00000000
## 2005-10-31 07:00:00 0.00000000
## 2005-11-30 07:00:00 0.00000000
## 2005-12-30 07:00:00 0.00000000
## 2006-01-31 07:00:00 0.00000000
## 2006-02-28 07:00:00 0.00000000
## 2006-03-31 07:00:00 0.00000000
## 2006-04-28 07:00:00 0.00000000
## 2006-05-31 07:00:00 0.00000000
## 2006-06-30 07:00:00 0.00000000
## 2006-07-31 07:00:00 0.00000000
## 2006-08-31 07:00:00 0.00000000
## 2006-09-29 07:00:00 0.00000000
## 2006-10-31 07:00:00 0.00000000
## 2006-11-30 07:00:00 0.00000000
## 2006-12-28 07:00:00 0.00000000
## 2007-01-31 07:00:00 0.00000000
## 2007-02-28 07:00:00 0.00000000
## 2007-03-30 07:00:00 0.00000000
## 2007-04-30 07:00:00 0.00000000
## 2007-05-31 07:00:00 0.00000000
## 2007-06-29 07:00:00 0.00000000
## 2007-07-31 07:00:00 0.00000000
## 2007-08-31 07:00:00 0.00000000
## 2007-09-28 07:00:00 0.00000000
## 2007-10-31 07:00:00 0.00000000
## 2007-11-30 07:00:00 0.00000000
## 2007-12-31 07:00:00 0.00000000
## 2008-01-31 07:00:00 0.00000000
## 2008-02-29 07:00:00 0.00000000
## 2008-03-31 07:00:00 0.00000000
## 2008-04-30 07:00:00 0.00000000
## 2008-05-30 07:00:00 0.00000000
## 2008-06-30 07:00:00 0.00000000
## 2008-07-29 07:00:00 0.00000000
## 2008-08-29 07:00:00 0.00000000
## 2008-09-26 07:00:00 0.00000000
## 2008-10-31 07:00:00 0.00000000
## 2008-11-28 07:00:00 0.00000000
## 2008-12-31 07:00:00 0.00000000
## 2009-01-30 07:00:00 0.00000000
## 2009-02-27 07:00:00 0.00000000
## 2009-03-31 07:00:00 0.00000000
## 2009-04-30 07:00:00 0.00000000
## 2009-05-29 07:00:00 0.00000000
## 2009-06-30 07:00:00 0.00000000
## 2009-07-31 07:00:00 0.00000000
## 2009-08-31 07:00:00 0.00000000
## 2009-09-30 07:00:00 0.00000000
## 2009-10-30 07:00:00 0.00000000
## 2009-11-30 07:00:00 0.00000000
## 2009-12-30 07:00:00 0.00000000
## 2010-01-29 07:00:00 0.00000000
## 2010-02-25 07:00:00 0.00000000
## 2010-03-31 07:00:00 0.00000000
## 2010-04-30 07:00:00 0.00000000
## 2010-05-31 07:00:00 0.00000000
## 2010-06-30 07:00:00 0.00000000
## 2010-07-30 07:00:00 0.00000000
## 2010-08-31 07:00:00 0.00000000
## 2010-09-30 07:00:00 0.00000000
## 2010-10-29 07:00:00 0.00000000
## 2010-11-30 07:00:00 0.00000000
## 2010-12-30 07:00:00 0.00000000
## 2011-01-31 07:00:00 0.00000000
## 2011-02-28 07:00:00 0.00000000
## 2011-03-31 07:00:00 0.00000000
## 2011-04-29 07:00:00 0.00000000
## 2011-05-31 07:00:00 0.00000000
## 2011-06-30 07:00:00 0.00000000
## 2011-07-29 07:00:00 0.00000000
## 2011-08-26 07:00:00 0.00000000
## 2011-09-30 07:00:00 0.00000000
## 2011-10-31 07:00:00 0.00000000
## 2011-11-30 07:00:00 0.00000000
## 2011-12-30 07:00:00 0.00000000
## 2012-01-31 07:00:00 0.00000000
## 2012-02-29 07:00:00 0.00000000
## 2012-03-30 07:00:00 0.00000000
## 2012-04-30 07:00:00 0.00000000
## 2012-05-31 07:00:00 0.00000000
## 2012-06-29 07:00:00 0.00000000
## 2012-07-31 07:00:00 0.00000000
## 2012-08-31 07:00:00 0.00000000
## 2012-09-28 07:00:00 0.02360928
## 2012-10-31 07:00:00 0.04169903
head(models$equal.weight$ret)
## GGRM.JK
## 2005-09-30 07:00:00 0
## 2005-10-31 07:00:00 0
## 2005-11-30 07:00:00 0
## 2005-12-30 07:00:00 0
## 2006-01-31 07:00:00 0
## 2006-02-28 07:00:00 0
#*****************************************************************
# 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 = 84
# 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 = 84
for( i in 84:dim(weight)[1]) {
hist = ret[ (i- 84 + 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] 189 7
head(weight, 90)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK
## [1,] NA NA NA NA NA NA
## [2,] NA NA NA NA NA NA
## [3,] NA NA NA NA NA NA
## [4,] NA NA NA NA NA NA
## [5,] NA NA NA NA NA NA
## [6,] NA NA NA NA NA NA
## [7,] NA NA NA NA NA NA
## [8,] NA NA NA NA NA NA
## [9,] NA NA NA NA NA NA
## [10,] NA NA NA NA NA NA
## [11,] NA NA NA NA NA NA
## [12,] NA NA NA NA NA NA
## [13,] NA NA NA NA NA NA
## [14,] NA NA NA NA NA NA
## [15,] NA NA NA NA NA NA
## [16,] NA NA NA NA NA NA
## [17,] NA NA NA NA NA NA
## [18,] NA NA NA NA NA NA
## [19,] NA NA NA NA NA NA
## [20,] NA NA NA NA NA NA
## [21,] NA NA NA NA NA NA
## [22,] NA NA NA NA NA NA
## [23,] NA NA NA NA NA NA
## [24,] NA NA NA NA NA NA
## [25,] NA NA NA NA NA NA
## [26,] NA NA NA NA NA NA
## [27,] NA NA NA NA NA NA
## [28,] NA NA NA NA NA NA
## [29,] NA NA NA NA NA NA
## [30,] NA NA NA NA NA NA
## [31,] NA NA NA NA NA NA
## [32,] NA NA NA NA NA NA
## [33,] NA NA NA NA NA NA
## [34,] NA NA NA NA NA NA
## [35,] NA NA NA NA NA NA
## [36,] NA NA NA NA NA NA
## [37,] NA NA NA NA NA NA
## [38,] NA NA NA NA NA NA
## [39,] NA NA NA NA NA NA
## [40,] NA NA NA NA NA NA
## [41,] NA NA NA NA NA NA
## [42,] NA NA NA NA NA NA
## [43,] NA NA NA NA NA NA
## [44,] NA NA NA NA NA NA
## [45,] NA NA NA NA NA NA
## [46,] NA NA NA NA NA NA
## [47,] NA NA NA NA NA NA
## [48,] NA NA NA NA NA NA
## [49,] NA NA NA NA NA NA
## [50,] NA NA NA NA NA NA
## [51,] NA NA NA NA NA NA
## [52,] NA NA NA NA NA NA
## [53,] NA NA NA NA NA NA
## [54,] NA NA NA NA NA NA
## [55,] NA NA NA NA NA NA
## [56,] NA NA NA NA NA NA
## [57,] NA NA NA NA NA NA
## [58,] NA NA NA NA NA NA
## [59,] NA NA NA NA NA NA
## [60,] NA NA NA NA NA NA
## [61,] NA NA NA NA NA NA
## [62,] NA NA NA NA NA NA
## [63,] NA NA NA NA NA NA
## [64,] NA NA NA NA NA NA
## [65,] NA NA NA NA NA NA
## [66,] NA NA NA NA NA NA
## [67,] NA NA NA NA NA NA
## [68,] NA NA NA NA NA NA
## [69,] NA NA NA NA NA NA
## [70,] NA NA NA NA NA NA
## [71,] NA NA NA NA NA NA
## [72,] NA NA NA NA NA NA
## [73,] NA NA NA NA NA NA
## [74,] NA NA NA NA NA NA
## [75,] NA NA NA NA NA NA
## [76,] NA NA NA NA NA NA
## [77,] NA NA NA NA NA NA
## [78,] NA NA NA NA NA NA
## [79,] NA NA NA NA NA NA
## [80,] NA NA NA NA NA NA
## [81,] NA NA NA NA NA NA
## [82,] NA NA NA NA NA NA
## [83,] NA NA NA NA NA NA
## [84,] 0.05589156 0.01591301 0.3246627 -0.013006255 0.02859097 0.5062156
## [85,] 0.05847307 0.01962355 0.3266480 -0.013353038 0.02987714 0.5021791
## [86,] 0.06180055 0.01674760 0.3264893 -0.012456929 0.02991491 0.5040421
## [87,] 0.05976579 0.02157313 0.3282562 -0.012163659 0.02993290 0.5029061
## [88,] 0.05612153 0.02355748 0.3423882 -0.006194351 0.03170148 0.4716754
## [89,] 0.05597230 0.02389361 0.3424201 -0.009048950 0.03303158 0.4669915
## [90,] 0.04914426 0.02209458 0.3336246 -0.010966224 0.03508294 0.4717945
## UNVR.JK
## [1,] NA
## [2,] NA
## [3,] NA
## [4,] NA
## [5,] NA
## [6,] NA
## [7,] NA
## [8,] NA
## [9,] NA
## [10,] NA
## [11,] NA
## [12,] NA
## [13,] NA
## [14,] NA
## [15,] NA
## [16,] NA
## [17,] NA
## [18,] NA
## [19,] NA
## [20,] NA
## [21,] NA
## [22,] NA
## [23,] NA
## [24,] NA
## [25,] NA
## [26,] NA
## [27,] NA
## [28,] NA
## [29,] NA
## [30,] NA
## [31,] NA
## [32,] NA
## [33,] NA
## [34,] NA
## [35,] NA
## [36,] NA
## [37,] NA
## [38,] NA
## [39,] NA
## [40,] NA
## [41,] NA
## [42,] NA
## [43,] NA
## [44,] NA
## [45,] NA
## [46,] NA
## [47,] NA
## [48,] NA
## [49,] NA
## [50,] NA
## [51,] NA
## [52,] NA
## [53,] NA
## [54,] NA
## [55,] NA
## [56,] NA
## [57,] NA
## [58,] NA
## [59,] NA
## [60,] NA
## [61,] NA
## [62,] NA
## [63,] NA
## [64,] NA
## [65,] NA
## [66,] NA
## [67,] NA
## [68,] NA
## [69,] NA
## [70,] NA
## [71,] NA
## [72,] NA
## [73,] NA
## [74,] NA
## [75,] NA
## [76,] NA
## [77,] NA
## [78,] NA
## [79,] NA
## [80,] NA
## [81,] NA
## [82,] NA
## [83,] NA
## [84,] 0.08173233
## [85,] 0.07655218
## [86,] 0.07346246
## [87,] 0.06972958
## [88,] 0.08075027
## [89,] 0.08673983
## [90,] 0.09922533
tail(weight)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK
## [184,] 0.1300397 0.1275431 0.10359087 -0.003374394 0.2870957 0.2324561
## [185,] 0.1108294 0.1367895 0.09553085 0.002374656 0.2864743 0.2529835
## [186,] 0.1103073 0.1401726 0.09223626 0.003637190 0.2819134 0.2502825
## [187,] 0.1075244 0.1370056 0.09428081 0.008114382 0.2925011 0.2451933
## [188,] 0.1048438 0.1277215 0.08931505 0.008158930 0.3021587 0.2398539
## [189,] 0.1090243 0.1317076 0.09043708 0.005751088 0.2993620 0.2367152
## UNVR.JK
## [184,] 0.1226489
## [185,] 0.1150177
## [186,] 0.1214507
## [187,] 0.1153804
## [188,] 0.1279482
## [189,] 0.1270027
# 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 :
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK UNVR.JK
## 2021-05-31 07:00:00 10.48 12.77 8.93 0.82 30.22 23.99 12.79
##
## Performance summary :
## CAGR Best Worst
## 3.2 14.4 -12.9
#=================================================================
# b. CAPM (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 = 84
f <- fama_lib_month[dates]/100
for( i in 84:dim(weight_1)[1]) {
hist = ret[ (i- 84 + 1):i, ]
Xi <- hist
fi <- f$Mkt.RF[(i - 84 + 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] 189 7
head(weight_1, 90)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK UNVR.JK
## [1,] NA NA NA NA NA NA NA
## [2,] NA NA NA NA NA NA NA
## [3,] NA NA NA NA NA NA NA
## [4,] NA NA NA NA NA NA NA
## [5,] NA NA NA NA NA NA NA
## [6,] NA NA NA NA NA NA NA
## [7,] NA NA NA NA NA NA NA
## [8,] NA NA NA NA NA NA NA
## [9,] NA NA NA NA NA NA NA
## [10,] NA NA NA NA NA NA NA
## [11,] NA NA NA NA NA NA NA
## [12,] NA NA NA NA NA NA NA
## [13,] NA NA NA NA NA NA NA
## [14,] NA NA NA NA NA NA NA
## [15,] NA NA NA NA NA NA NA
## [16,] NA NA NA NA NA NA NA
## [17,] NA NA NA NA NA NA NA
## [18,] NA NA NA NA NA NA NA
## [19,] NA NA NA NA NA NA NA
## [20,] NA NA NA NA NA NA NA
## [21,] NA NA NA NA NA NA NA
## [22,] NA NA NA NA NA NA NA
## [23,] NA NA NA NA NA NA NA
## [24,] NA NA NA NA NA NA NA
## [25,] NA NA NA NA NA NA NA
## [26,] NA NA NA NA NA NA NA
## [27,] NA NA NA NA NA NA NA
## [28,] NA NA NA NA NA NA NA
## [29,] NA NA NA NA NA NA NA
## [30,] NA NA NA NA NA NA NA
## [31,] NA NA NA NA NA NA NA
## [32,] NA NA NA NA NA NA NA
## [33,] NA NA NA NA NA NA NA
## [34,] NA NA NA NA NA NA NA
## [35,] NA NA NA NA NA NA NA
## [36,] NA NA NA NA NA NA NA
## [37,] NA NA NA NA NA NA NA
## [38,] NA NA NA NA NA NA NA
## [39,] NA NA NA NA NA NA NA
## [40,] NA NA NA NA NA NA NA
## [41,] NA NA NA NA NA NA NA
## [42,] NA NA NA NA NA NA NA
## [43,] NA NA NA NA NA NA NA
## [44,] NA NA NA NA NA NA NA
## [45,] NA NA NA NA NA NA NA
## [46,] NA NA NA NA NA NA NA
## [47,] NA NA NA NA NA NA NA
## [48,] NA NA NA NA NA NA NA
## [49,] NA NA NA NA NA NA NA
## [50,] NA NA NA NA NA NA NA
## [51,] NA NA NA NA NA NA NA
## [52,] NA NA NA NA NA NA NA
## [53,] NA NA NA NA NA NA NA
## [54,] NA NA NA NA NA NA NA
## [55,] NA NA NA NA NA NA NA
## [56,] NA NA NA NA NA NA NA
## [57,] NA NA NA NA NA NA NA
## [58,] NA NA NA NA NA NA NA
## [59,] NA NA NA NA NA NA NA
## [60,] NA NA NA NA NA NA NA
## [61,] NA NA NA NA NA NA NA
## [62,] NA NA NA NA NA NA NA
## [63,] NA NA NA NA NA NA NA
## [64,] NA NA NA NA NA NA NA
## [65,] NA NA NA NA NA NA NA
## [66,] NA NA NA NA NA NA NA
## [67,] NA NA NA NA NA NA NA
## [68,] NA NA NA NA NA NA NA
## [69,] NA NA NA NA NA NA NA
## [70,] NA NA NA NA NA NA NA
## [71,] NA NA NA NA NA NA NA
## [72,] NA NA NA NA NA NA NA
## [73,] NA NA NA NA NA NA NA
## [74,] NA NA NA NA NA NA NA
## [75,] NA NA NA NA NA NA NA
## [76,] NA NA NA NA NA NA NA
## [77,] NA NA NA NA NA NA NA
## [78,] NA NA NA NA NA NA NA
## [79,] NA NA NA NA NA NA NA
## [80,] NA NA NA NA NA NA NA
## [81,] NA NA NA NA NA NA NA
## [82,] NA NA NA NA NA NA NA
## [83,] NA NA NA NA NA NA NA
## [84,] 0.1147953 0.1070467 0.2143652 0.04518558 0.04702557 0.3448608 0.1267207
## [85,] 0.1154380 0.1074035 0.2152707 0.04537034 0.04720630 0.3429900 0.1263213
## [86,] 0.1155807 0.1077548 0.2147433 0.04526610 0.04713133 0.3427952 0.1267286
## [87,] 0.1155384 0.1071722 0.2146291 0.04529557 0.04713947 0.3435805 0.1266447
## [88,] 0.1187136 0.1198909 0.2198811 0.04630157 0.04936194 0.3157269 0.1301239
## [89,] 0.1191409 0.1195074 0.2215505 0.04607732 0.04920009 0.3145284 0.1299955
## [90,] 0.1166826 0.1202855 0.2159777 0.04620396 0.05041389 0.3203952 0.1300411
tail(weight_1)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK UNVR.JK
## [184,] 0.1530023 0.1398117 0.1191477 0.03111713 0.1825224 0.2332738 0.1411249
## [185,] 0.1494830 0.1410791 0.1175703 0.03167631 0.1821279 0.2389171 0.1391464
## [186,] 0.1481966 0.1423281 0.1167477 0.03190315 0.1812203 0.2368311 0.1427730
## [187,] 0.1458659 0.1412417 0.1163061 0.03147071 0.1901634 0.2324238 0.1425285
## [188,] 0.1455562 0.1411408 0.1158669 0.03143990 0.1916472 0.2249347 0.1494142
## [189,] 0.1464869 0.1414640 0.1155808 0.03116168 0.1909967 0.2249725 0.1493375
# 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 :
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK UNVR.JK
## 2021-05-31 07:00:00 14.56 14.11 11.59 3.14 19.16 22.49 14.94
##
## Performance summary :
## CAGR Best Worst
## 4.1 12.4 -12.3
models$mvp.capm.cov$cagr
## [1] 0.04121181
models$mvp.hist.cov$cagr
## [1] 0.03174668
#=================================================================
# c. FAMA FRENCH (Three Factors 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 = 84
f <- fama_lib_month[dates]/100
for( i in 84:dim(weight_1)[1]) {
hist = ret[ (i- 84 + 1):i, ]
Xi <- hist
fi <- f[(i - 84 + 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] 189 7
head(weight_3, 90)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK UNVR.JK
## [1,] NA NA NA NA NA NA NA
## [2,] NA NA NA NA NA NA NA
## [3,] NA NA NA NA NA NA NA
## [4,] NA NA NA NA NA NA NA
## [5,] NA NA NA NA NA NA NA
## [6,] NA NA NA NA NA NA NA
## [7,] NA NA NA NA NA NA NA
## [8,] NA NA NA NA NA NA NA
## [9,] NA NA NA NA NA NA NA
## [10,] NA NA NA NA NA NA NA
## [11,] NA NA NA NA NA NA NA
## [12,] NA NA NA NA NA NA NA
## [13,] NA NA NA NA NA NA NA
## [14,] NA NA NA NA NA NA NA
## [15,] NA NA NA NA NA NA NA
## [16,] NA NA NA NA NA NA NA
## [17,] NA NA NA NA NA NA NA
## [18,] NA NA NA NA NA NA NA
## [19,] NA NA NA NA NA NA NA
## [20,] NA NA NA NA NA NA NA
## [21,] NA NA NA NA NA NA NA
## [22,] NA NA NA NA NA NA NA
## [23,] NA NA NA NA NA NA NA
## [24,] NA NA NA NA NA NA NA
## [25,] NA NA NA NA NA NA NA
## [26,] NA NA NA NA NA NA NA
## [27,] NA NA NA NA NA NA NA
## [28,] NA NA NA NA NA NA NA
## [29,] NA NA NA NA NA NA NA
## [30,] NA NA NA NA NA NA NA
## [31,] NA NA NA NA NA NA NA
## [32,] NA NA NA NA NA NA NA
## [33,] NA NA NA NA NA NA NA
## [34,] NA NA NA NA NA NA NA
## [35,] NA NA NA NA NA NA NA
## [36,] NA NA NA NA NA NA NA
## [37,] NA NA NA NA NA NA NA
## [38,] NA NA NA NA NA NA NA
## [39,] NA NA NA NA NA NA NA
## [40,] NA NA NA NA NA NA NA
## [41,] NA NA NA NA NA NA NA
## [42,] NA NA NA NA NA NA NA
## [43,] NA NA NA NA NA NA NA
## [44,] NA NA NA NA NA NA NA
## [45,] NA NA NA NA NA NA NA
## [46,] NA NA NA NA NA NA NA
## [47,] NA NA NA NA NA NA NA
## [48,] NA NA NA NA NA NA NA
## [49,] NA NA NA NA NA NA NA
## [50,] NA NA NA NA NA NA NA
## [51,] NA NA NA NA NA NA NA
## [52,] NA NA NA NA NA NA NA
## [53,] NA NA NA NA NA NA NA
## [54,] NA NA NA NA NA NA NA
## [55,] NA NA NA NA NA NA NA
## [56,] NA NA NA NA NA NA NA
## [57,] NA NA NA NA NA NA NA
## [58,] NA NA NA NA NA NA NA
## [59,] NA NA NA NA NA NA NA
## [60,] NA NA NA NA NA NA NA
## [61,] NA NA NA NA NA NA NA
## [62,] NA NA NA NA NA NA NA
## [63,] NA NA NA NA NA NA NA
## [64,] NA NA NA NA NA NA NA
## [65,] NA NA NA NA NA NA NA
## [66,] NA NA NA NA NA NA NA
## [67,] NA NA NA NA NA NA NA
## [68,] NA NA NA NA NA NA NA
## [69,] NA NA NA NA NA NA NA
## [70,] NA NA NA NA NA NA NA
## [71,] NA NA NA NA NA NA NA
## [72,] NA NA NA NA NA NA NA
## [73,] NA NA NA NA NA NA NA
## [74,] NA NA NA NA NA NA NA
## [75,] NA NA NA NA NA NA NA
## [76,] NA NA NA NA NA NA NA
## [77,] NA NA NA NA NA NA NA
## [78,] NA NA NA NA NA NA NA
## [79,] NA NA NA NA NA NA NA
## [80,] NA NA NA NA NA NA NA
## [81,] NA NA NA NA NA NA NA
## [82,] NA NA NA NA NA NA NA
## [83,] NA NA NA NA NA NA NA
## [84,] 0.1084401 0.09946205 0.2407462 0.03985597 0.04665202 0.3470972 0.1177464
## [85,] 0.1089879 0.09986887 0.2416018 0.04006016 0.04682863 0.3453371 0.1173155
## [86,] 0.1091677 0.10038412 0.2406194 0.04006577 0.04649909 0.3453941 0.1178699
## [87,] 0.1092028 0.10000879 0.2411517 0.03968103 0.04653161 0.3458037 0.1176205
## [88,] 0.1121166 0.11313234 0.2466584 0.04035408 0.04855380 0.3175521 0.1216326
## [89,] 0.1128293 0.11229594 0.2487243 0.03991052 0.04834940 0.3157299 0.1221607
## [90,] 0.1103589 0.11362848 0.2417988 0.04110288 0.04910347 0.3203859 0.1236217
tail(weight_3)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK UNVR.JK
## [184,] 0.1503660 0.1379182 0.1199567 0.03231837 0.1852583 0.2350303 0.1391521
## [185,] 0.1453846 0.1421613 0.1185030 0.03306159 0.1843279 0.2402611 0.1363007
## [186,] 0.1439377 0.1431954 0.1175903 0.03296817 0.1843244 0.2385927 0.1393914
## [187,] 0.1408346 0.1427098 0.1167004 0.03121124 0.1933701 0.2358711 0.1393028
## [188,] 0.1402721 0.1408792 0.1160734 0.03143374 0.1968044 0.2268273 0.1477098
## [189,] 0.1420407 0.1409025 0.1157030 0.03142472 0.1956406 0.2258141 0.1484743
# 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 :
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK UNVR.JK
## 2021-05-31 07:00:00 14.03 14.09 11.61 3.14 19.68 22.68 14.77
##
## Performance summary :
## CAGR Best Worst
## 4.2 12.4 -12.3
#=================================================================
# d. PRINCIPAL COMPONENT ANALYSIS (PCA)
#=================================================================
X_i <-X[1:84,]
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
## GGRM.JK 0.02628758 -0.049315229 -0.0223801161 -0.05465939
## HMSP.JK 0.03058379 -0.005467683 0.0003314439 -0.02364755
## INDF.JK 0.03412201 -0.060882258 -0.0382898552 -0.06377484
## JPFA.JK 0.05531731 -0.181530276 -0.0780533965 0.05384842
## MYOR.JK 0.05287540 -0.071509844 -0.0323362435 -0.03374303
## ULTJ.JK 0.03338365 -0.135004575 0.1481203175 -0.00387014
## UNVR.JK 0.02781668 -0.019793575 -0.0041662546 -0.00667288
#
# 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.057285372 -0.0290389434 -0.068929850
## [2,] -0.006476672 -0.0006698376 -0.034609680
## [3,] -0.068769418 -0.0459158734 -0.063199106
## [4,] -0.181603175 -0.0608790312 0.075564190
## [5,] -0.085970599 -0.0428769455 -0.039648161
## [6,] -0.127673016 0.1539737431 -0.013285625
## [7,] -0.021609515 -0.0042045047 -0.004577221
# fiti = lm(formula = X_i ~ t(B))
Sigma_PCA3 <- Sigma
Sigma_PCA3
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 0.014091485 0.0027761099 0.009629135 0.006962440 0.008902901 0.003758338
## [2,] 0.002776110 0.0086589522 0.002663454 -0.001398289 0.001957734 0.001183570
## [3,] 0.009629135 0.0026634539 0.015412356 0.010508469 0.010386609 0.002549800
## [4,] 0.006962440 -0.0013982892 0.010508469 0.042961470 0.015226859 0.012808135
## [5,] 0.008902901 0.0019577341 0.010386609 0.015226859 0.018051662 0.004900952
## [6,] 0.003758338 0.0011835700 0.002549800 0.012808135 0.004900952 0.040213041
## [7,] 0.001675511 0.0003011902 0.001968404 0.003834449 0.002219538 0.002172380
## [,7]
## [1,] 0.0016755106
## [2,] 0.0003011902
## [3,] 0.0019684035
## [4,] 0.0038344487
## [5,] 0.0022195376
## [6,] 0.0021723799
## [7,] 0.0056250047
diag(Sigma_PCA3)
## [1] 0.014091485 0.008658952 0.015412356 0.042961470 0.018051662 0.040213041
## [7] 0.005625005
# error
norm(Sigma_PCA3 - cov(X_i), "F")
## [1] 0.008265346
#*****************************************************************
# 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 Comp.6 Comp.7
## 0.25380059 0.17843390 0.13120690 0.10552187 0.08619573 0.08168248 0.06769319
##
## 7 variables and 84 observations.
summary(pc.fit)
## Importance of components:
## Comp.1 Comp.2 Comp.3 Comp.4 Comp.5
## Standard deviation 0.2538006 0.1784339 0.1312069 0.10552187 0.08619573
## Proportion of Variance 0.4495486 0.2222010 0.1201447 0.07770989 0.05185169
## Cumulative Proportion 0.4495486 0.6717496 0.7918943 0.86960422 0.92145590
## Comp.6 Comp.7
## Standard deviation 0.08168248 0.06769319
## Proportion of Variance 0.04656389 0.03198021
## Cumulative Proportion 0.96801979 1.00000000
#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 Comp.6 Comp.7
## 0.25380059 0.17843390 0.13120690 0.10552187 0.08619573 0.08168248 0.06769319
##
## 7 variables and 84 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.057285372 -0.0290389434 -0.068929850
## [2,] -0.006476672 -0.0006698376 -0.034609680
## [3,] -0.068769418 -0.0459158734 -0.063199106
## [4,] -0.181603175 -0.0608790312 0.075564190
## [5,] -0.085970599 -0.0428769455 -0.039648161
## [6,] -0.127673016 0.1539737431 -0.013285625
## [7,] -0.021609515 -0.0042045047 -0.004577221
#
#
plot(pc.fit,col=brewer.pal(7,"Set2"),ylim=c(0,0.07))
loadings(pc.fit)
##
## Loadings:
## Comp.1 Comp.2 Comp.3 Comp.4 Comp.5 Comp.6 Comp.7
## GGRM.JK 0.224 0.162 0.522 0.293 0.751
## HMSP.JK 0.262 0.477 -0.389 0.740
## INDF.JK 0.269 0.256 0.479 0.165 -0.521 -0.569 -0.104
## JPFA.JK 0.711 0.339 -0.572 0.220
## MYOR.JK 0.337 0.239 0.300 -0.733 0.333 0.289
## ULTJ.JK 0.500 -0.858 0.101
## UNVR.JK -0.270 0.112 -0.949
##
## Comp.1 Comp.2 Comp.3 Comp.4 Comp.5 Comp.6 Comp.7
## SS loadings 1.000 1.000 1.000 1.000 1.000 1.000 1.000
## Proportion Var 0.143 0.143 0.143 0.143 0.143 0.143 0.143
## Cumulative Var 0.143 0.286 0.429 0.571 0.714 0.857 1.000
pc.fit$loadings[, 1:3]
## Comp.1 Comp.2 Comp.3
## GGRM.JK 0.22436262 0.16177181 0.52221587
## HMSP.JK 0.02536639 0.00373157 0.26220460
## INDF.JK 0.26934079 0.25579077 0.47879947
## JPFA.JK 0.71126299 0.33914839 -0.57247794
## MYOR.JK 0.33671055 0.23886134 0.30037638
## ULTJ.JK 0.50004132 -0.85776573 0.10065253
## UNVR.JK 0.08463535 0.02342270 0.03467725
# 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
## 2005-10-31 0.03821218 0.03303570 -0.0688982628
## 2005-11-30 -0.13210802 -0.01124371 0.0238242646
## 2005-12-30 0.22374918 -0.08626179 0.1651031375
## 2006-01-31 -0.11634409 0.10740181 -0.1459590741
## 2006-02-28 -0.14552348 0.00392537 -0.1038965436
## 2006-03-31 -0.02503732 -0.05976932 0.0002345293
pc.fit$scores[, 1:3]
## Comp.1 Comp.2 Comp.3
## 2005-10-31 0.038212184 0.0330357033 -0.0688982628
## 2005-11-30 -0.132108017 -0.0112437075 0.0238242646
## 2005-12-30 0.223749181 -0.0862617912 0.1651031375
## 2006-01-31 -0.116344088 0.1074018117 -0.1459590741
## 2006-02-28 -0.145523480 0.0039253701 -0.1038965436
## 2006-03-31 -0.025037324 -0.0597693206 0.0002345293
## 2006-04-28 0.283742277 0.1214460020 0.0985581842
## 2006-05-31 -0.407889696 0.0635513634 -0.0981050140
## 2006-06-30 -0.009780020 -0.3237799014 -0.0205695773
## 2006-07-31 -0.016217279 0.0488272333 0.1071050228
## 2006-08-31 -0.071423040 0.1079406727 0.0720869751
## 2006-09-29 0.195296303 -0.1225613964 0.0468369664
## 2006-10-31 0.163902600 -0.2262654892 -0.0215427800
## 2006-11-30 0.327523256 0.2551072648 -0.1466452271
## 2006-12-28 -0.183340956 -0.0906674449 0.1155835488
## 2007-01-31 -0.090189240 0.0202210927 0.1355683529
## 2007-02-28 -0.072000566 -0.0100893170 -0.0413922501
## 2007-03-30 -0.139492897 -0.0494778548 -0.0294797009
## 2007-04-30 -0.039852323 0.1488301610 -0.0101928238
## 2007-05-31 0.819897850 0.2199435991 -0.5373433558
## 2007-06-29 0.096791108 -0.1852320484 0.2130661248
## 2007-07-31 -0.100241811 -0.0841427645 -0.0373508095
## 2007-08-31 -0.318791221 0.0702670677 -0.0801966896
## 2007-09-28 0.309968214 -0.4871582015 -0.0086707759
## 2007-10-31 -0.050745273 0.2754567754 -0.0448996286
## 2007-11-30 -0.120380051 -0.0748333772 0.0071416554
## 2007-12-31 -0.082250691 -0.0434948215 0.0165557883
## 2008-01-31 -0.283090981 0.1929739205 -0.0060261340
## 2008-02-29 -0.166487233 -0.0448852892 -0.0131023123
## 2008-03-31 -0.137068496 -0.4802295313 -0.1247932929
## 2008-04-30 -0.246461093 -0.0591430380 0.0472200342
## 2008-05-30 0.571434283 0.2026964251 -0.2526447900
## 2008-06-30 -0.218774077 -0.1818977955 -0.1117473985
## 2008-07-29 -0.017993105 0.1205669616 0.0602791920
## 2008-08-29 -0.221920950 0.0410823722 -0.0731750532
## 2008-09-26 -0.287543741 -0.2069814525 -0.0127695889
## 2008-10-31 -0.559824569 -0.2692061915 -0.3200337898
## 2008-11-28 -0.101275399 -0.0901349528 -0.0320250220
## 2008-12-31 -0.023482361 -0.2450110360 -0.0528827700
## 2009-01-30 -0.058096734 0.1326860800 0.1214245315
## 2009-02-27 -0.055849103 -0.0771229012 -0.1281944580
## 2009-03-31 0.116521892 0.1018019001 -0.0108085874
## 2009-04-30 0.068074346 0.2422931460 0.3620071780
## 2009-05-29 0.261116822 0.3397672180 0.3767185690
## 2009-06-30 0.087017762 0.1208004885 -0.0271027713
## 2009-07-31 0.371935588 0.2044862566 0.1352046072
## 2009-08-31 -0.041134641 0.0650161906 0.0863901178
## 2009-09-30 0.126668983 0.1005407420 0.1444756382
## 2009-10-30 -0.095737848 0.0865045498 -0.1044514406
## 2009-11-30 0.451283219 0.2020930133 -0.0732895323
## 2009-12-30 0.024007744 0.1355319981 0.2208409244
## 2010-01-29 -0.121323938 -0.0687639665 0.1492784320
## 2010-02-25 -0.114837985 -0.0228164588 0.0366936403
## 2010-03-31 0.007630307 -0.0246930464 -0.0682784347
## 2010-04-30 0.183168138 0.1066599078 0.0228853892
## 2010-05-31 -0.037484498 -0.1482149673 0.2129622724
## 2010-06-30 0.086802671 0.2049961123 0.1205805513
## 2010-07-30 0.498457926 0.3169542901 -0.2601746663
## 2010-08-31 -0.027199219 -0.0390091582 0.0819640612
## 2010-09-30 1.194791038 -0.7872218873 0.0802594990
## 2010-10-29 -0.199628260 -0.1045230671 0.0902713562
## 2010-11-30 -0.234249199 0.0905006664 -0.1870803140
## 2010-12-30 -0.183807171 0.0796673528 0.0424867365
## 2011-01-31 -0.270612844 0.0959300689 -0.1220221431
## 2011-02-28 -0.094188531 -0.0312869412 -0.0268271945
## 2011-03-31 0.150101029 0.0925049166 0.0842175398
## 2011-04-29 0.112672887 -0.2921261792 -0.0178672476
## 2011-05-31 0.078028749 0.0797583968 -0.0218126826
## 2011-06-30 0.086843450 0.1078981184 -0.0241757525
## 2011-07-29 0.218195201 0.0670959029 0.1062443431
## 2011-08-26 -0.252364815 0.0895450387 -0.0178833368
## 2011-09-30 -0.372179827 -0.0063905908 -0.1325652473
## 2011-10-31 0.135459487 0.0479538815 0.0010512784
## 2011-11-30 -0.162278963 -0.0738541571 0.1087049985
## 2011-12-30 -0.205200383 -0.0642325213 0.0379054692
## 2012-01-31 -0.024256752 -0.0254387563 -0.0617853438
## 2012-02-29 -0.014916369 0.0194843659 0.0462877367
## 2012-03-30 -0.022197639 -0.0069431154 0.0572604953
## 2012-04-30 -0.035484604 -0.0009003216 0.0177703729
## 2012-05-31 -0.125582216 0.0003181936 -0.0603624440
## 2012-06-29 0.110598930 0.1999852904 -0.0099296297
## 2012-07-31 -0.113135508 -0.1467769044 0.0614884802
## 2012-08-31 -0.160811876 0.0308558603 -0.1264442395
## 2012-09-28 0.008195478 -0.0421220799 -0.0391398633
# 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
## GGRM.JK 0.22436262 0.16177181 0.52221587 -0.22436262 -0.16177181 -0.52221587
## HMSP.JK 0.02536639 0.00373157 0.26220460 -0.02536639 -0.00373157 -0.26220460
## INDF.JK 0.26934079 0.25579077 0.47879947 -0.26934079 -0.25579077 -0.47879947
## JPFA.JK 0.71126299 0.33914839 -0.57247794 -0.71126299 -0.33914839 0.57247794
## MYOR.JK 0.33671055 0.23886134 0.30037638 -0.33671055 -0.23886134 -0.30037638
## ULTJ.JK 0.50004132 -0.85776573 0.10065253 -0.50004132 0.85776573 -0.10065253
## UNVR.JK 0.08463535 0.02342270 0.03467725 -0.08463535 -0.02342270 -0.03467725
# 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
## 2005-10-31 0.038212184 0.130272725
## 2005-11-30 -0.132108017 -0.040047475
## 2005-12-30 0.223749181 0.315809722
## 2006-01-31 -0.116344088 -0.024283547
## 2006-02-28 -0.145523480 -0.053462939
## 2006-03-31 -0.025037324 0.067023217
## 2006-04-28 0.283742277 0.375802818
## 2006-05-31 -0.407889696 -0.315829154
## 2006-06-30 -0.009780020 0.082280522
## 2006-07-31 -0.016217279 0.075843263
## 2006-08-31 -0.071423040 0.020637501
## 2006-09-29 0.195296303 0.287356844
## 2006-10-31 0.163902600 0.255963141
## 2006-11-30 0.327523256 0.419583797
## 2006-12-28 -0.183340956 -0.091280415
## 2007-01-31 -0.090189240 0.001871301
## 2007-02-28 -0.072000566 0.020059975
## 2007-03-30 -0.139492897 -0.047432355
## 2007-04-30 -0.039852323 0.052208218
## 2007-05-31 0.819897850 0.911958392
## 2007-06-29 0.096791108 0.188851649
## 2007-07-31 -0.100241811 -0.008181270
## 2007-08-31 -0.318791221 -0.226730680
## 2007-09-28 0.309968214 0.402028755
## 2007-10-31 -0.050745273 0.041315269
## 2007-11-30 -0.120380051 -0.028319509
## 2007-12-31 -0.082250691 0.009809851
## 2008-01-31 -0.283090981 -0.191030439
## 2008-02-29 -0.166487233 -0.074426691
## 2008-03-31 -0.137068496 -0.045007955
## 2008-04-30 -0.246461093 -0.154400551
## 2008-05-30 0.571434283 0.663494824
## 2008-06-30 -0.218774077 -0.126713535
## 2008-07-29 -0.017993105 0.074067436
## 2008-08-29 -0.221920950 -0.129860409
## 2008-09-26 -0.287543741 -0.195483199
## 2008-10-31 -0.559824569 -0.467764027
## 2008-11-28 -0.101275399 -0.009214857
## 2008-12-31 -0.023482361 0.068578181
## 2009-01-30 -0.058096734 0.033963808
## 2009-02-27 -0.055849103 0.036211438
## 2009-03-31 0.116521892 0.208582433
## 2009-04-30 0.068074346 0.160134887
## 2009-05-29 0.261116822 0.353177363
## 2009-06-30 0.087017762 0.179078304
## 2009-07-31 0.371935588 0.463996129
## 2009-08-31 -0.041134641 0.050925900
## 2009-09-30 0.126668983 0.218729524
## 2009-10-30 -0.095737848 -0.003677306
## 2009-11-30 0.451283219 0.543343761
## 2009-12-30 0.024007744 0.116068285
## 2010-01-29 -0.121323938 -0.029263397
## 2010-02-25 -0.114837985 -0.022777444
## 2010-03-31 0.007630307 0.099690849
## 2010-04-30 0.183168138 0.275228679
## 2010-05-31 -0.037484498 0.054576044
## 2010-06-30 0.086802671 0.178863213
## 2010-07-30 0.498457926 0.590518468
## 2010-08-31 -0.027199219 0.064861322
## 2010-09-30 1.194791038 1.286851580
## 2010-10-29 -0.199628260 -0.107567719
## 2010-11-30 -0.234249199 -0.142188658
## 2010-12-30 -0.183807171 -0.091746630
## 2011-01-31 -0.270612844 -0.178552303
## 2011-02-28 -0.094188531 -0.002127989
## 2011-03-31 0.150101029 0.242161570
## 2011-04-29 0.112672887 0.204733428
## 2011-05-31 0.078028749 0.170089291
## 2011-06-30 0.086843450 0.178903991
## 2011-07-29 0.218195201 0.310255743
## 2011-08-26 -0.252364815 -0.160304274
## 2011-09-30 -0.372179827 -0.280119286
## 2011-10-31 0.135459487 0.227520029
## 2011-11-30 -0.162278963 -0.070218421
## 2011-12-30 -0.205200383 -0.113139842
## 2012-01-31 -0.024256752 0.067803789
## 2012-02-29 -0.014916369 0.077144173
## 2012-03-30 -0.022197639 0.069862902
## 2012-04-30 -0.035484604 0.056575937
## 2012-05-31 -0.125582216 -0.033521674
## 2012-06-29 0.110598930 0.202659472
## 2012-07-31 -0.113135508 -0.021074967
## 2012-08-31 -0.160811876 -0.068751335
## 2012-09-28 0.008195478 0.100256019
#
# 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
## GGRM.JK 0.22436262 0.16177181 0.52221587
## HMSP.JK 0.02536639 0.00373157 0.26220460
## INDF.JK 0.26934079 0.25579077 0.47879947
## JPFA.JK 0.71126299 0.33914839 -0.57247794
## MYOR.JK 0.33671055 0.23886134 0.30037638
## ULTJ.JK 0.50004132 -0.85776573 0.10065253
## UNVR.JK 0.08463535 0.02342270 0.03467725
colSums(p3)
## Comp.1 Comp.2 Comp.3
## 2.1517200 0.1649608 1.1264481
# create factor mimicking portfolio by normalizing weights to unity
p3 = p3/colSums(p3)
p3
## Comp.1 Comp.2 Comp.3
## GGRM.JK 0.10427129 0.980667936 0.46359512
## HMSP.JK 0.15377219 0.003312687 0.12185814
## INDF.JK 0.23910625 0.118877350 2.90250382
## JPFA.JK 0.33055555 2.055932716 -0.50821509
## MYOR.JK 2.04115445 0.212048233 0.13959826
## ULTJ.JK 0.44390976 -0.398641889 0.61016015
## UNVR.JK 0.03933381 0.141989427 0.03078459
barplot(p3[,1], horiz=F, main="Factor mimicking weights", col=brewer.pal(7,"Set3"), cex.names = 0.75, las=2)
# create first 3 factors
f3 = X_i %*% p3
head(f3)
## Comp.1 Comp.2 Comp.3
## [1,] 0.056414212 0.23792420 0.2751346
## [2,] -0.167453518 -0.01786923 0.1364060
## [3,] 0.944382959 0.14596394 0.4173403
## [4,] -0.003545775 0.14963390 -0.2523057
## [5,] -0.287737977 0.08391175 -0.1941613
## [6,] 0.180265905 -0.05515027 0.2060652
head(pc.fit$scores[, 1:3])
## Comp.1 Comp.2 Comp.3
## 2005-10-31 0.03821218 0.03303570 -0.0688982628
## 2005-11-30 -0.13210802 -0.01124371 0.0238242646
## 2005-12-30 0.22374918 -0.08626179 0.1651031375
## 2006-01-31 -0.11634409 0.10740181 -0.1459590741
## 2006-02-28 -0.14552348 0.00392537 -0.1038965436
## 2006-03-31 -0.02503732 -0.05976932 0.0002345293
# 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
## GGRM.JK 0.0007099487 -0.04893042 0.113405117 0.14545838
## HMSP.JK 0.0268890600 -0.03685023 0.004043170 0.07725371
## INDF.JK -0.0004551373 -0.07376988 0.083166278 0.29546456
## JPFA.JK -0.0028226686 0.04201929 0.407896667 -0.06794934
## MYOR.JK -0.0003863505 0.42380927 -0.053468794 -0.05027695
## ULTJ.JK -0.0068659585 0.32927061 -0.130471219 0.06323544
## UNVR.JK 0.0170216167 0.08367073 -0.002776087 -0.01730858
# can also use solve(qr(X.mat), returns.mat)
beta.hat = G.hat[2:4,]
beta.hat
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK
## Factor 1 -0.04893042 -0.03685023 -0.07376988 0.04201929 0.42380927
## Factor 2 0.11340512 0.00404317 0.08316628 0.40789667 -0.05346879
## Factor 3 0.14545838 0.07725371 0.29546456 -0.06794934 -0.05027695
## ULTJ.JK UNVR.JK
## Factor 1 0.32927061 0.083670729
## Factor 2 -0.13047122 -0.002776087
## Factor 3 0.06323544 -0.017308581
B
## [,1] [,2] [,3]
## [1,] -0.057285372 -0.0290389434 -0.068929850
## [2,] -0.006476672 -0.0006698376 -0.034609680
## [3,] -0.068769418 -0.0459158734 -0.063199106
## [4,] -0.181603175 -0.0608790312 0.075564190
## [5,] -0.085970599 -0.0428769455 -0.039648161
## [6,] -0.127673016 0.1539737431 -0.013285625
## [7,] -0.021609515 -0.0042045047 -0.004577221
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
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK
## GGRM.JK 0.014380093 1.446684e-03 0.008967669 0.0116028363 0.0055147023
## HMSP.JK 0.001446684 8.959740e-03 0.002713868 0.0002426334 0.0003520953
## INDF.JK 0.008967669 2.713868e-03 0.015456194 0.0108127170 0.0069478635
## JPFA.JK 0.011602836 2.426334e-04 0.010812717 0.0430883834 0.0153313751
## MYOR.JK 0.005514702 3.520953e-04 0.006947864 0.0153313751 0.0181154869
## ULTJ.JK 0.004273211 1.044330e-03 0.007282532 0.0057098132 0.0119388051
## UNVR.JK 0.001131545 1.647882e-05 0.001278558 0.0036044703 0.0033332718
## ULTJ.JK UNVR.JK
## GGRM.JK 0.004273211 1.131545e-03
## HMSP.JK 0.001044330 1.647882e-05
## INDF.JK 0.007282532 1.278558e-03
## JPFA.JK 0.005709813 3.604470e-03
## MYOR.JK 0.011938805 3.333272e-03
## ULTJ.JK 0.041314212 2.264390e-03
## UNVR.JK 0.002264390 5.809946e-03
Sigma_PCA3
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 0.014091485 0.0027761099 0.009629135 0.006962440 0.008902901 0.003758338
## [2,] 0.002776110 0.0086589522 0.002663454 -0.001398289 0.001957734 0.001183570
## [3,] 0.009629135 0.0026634539 0.015412356 0.010508469 0.010386609 0.002549800
## [4,] 0.006962440 -0.0013982892 0.010508469 0.042961470 0.015226859 0.012808135
## [5,] 0.008902901 0.0019577341 0.010386609 0.015226859 0.018051662 0.004900952
## [6,] 0.003758338 0.0011835700 0.002549800 0.012808135 0.004900952 0.040213041
## [7,] 0.001675511 0.0003011902 0.001968404 0.003834449 0.002219538 0.002172380
## [,7]
## [1,] 0.0016755106
## [2,] 0.0003011902
## [3,] 0.0019684035
## [4,] 0.0038344487
## [5,] 0.0022195376
## [6,] 0.0021723799
## [7,] 0.0056250047
diag(cov.pc3)
## GGRM.JK HMSP.JK INDF.JK JPFA.JK MYOR.JK ULTJ.JK
## 0.014380093 0.008959740 0.015456194 0.043088383 0.018115487 0.041314212
## UNVR.JK
## 0.005809946
# error difference between pca and empirical covariance matrix
norm(cov.pc3 - cov(X_i), "F")
## [1] 0.01689651
norm(Sigma_PCA3 - cov(X_i), "F")
## [1] 0.008265346
#============================================================
# 8. PERFORMANCE PLOTTING OF MVP (Minimum Variance Portfolio)
# Based on Equal Weighting, CAPM, Fama French, and PCA
#============================================================
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')
}
->CAGR is a pro forma number that provides a “smoothed” annual yield, so it can give the illusion that there is a steady growth rate even when the value of the underlying investment can vary significantly. ->A maximum drawdown (MaxDD) is the maximum observed loss from a peak to a trough of a portfolio, before a new peak is attained. ->The equal-weight share portfolio for the chosen 7 Indonesian non-cyclical sector stocks performed well during that period with 6.13% CAGR, which is the highest among the other portfolio strategies. But we found out that the maximum drawdown (MaxDD) using this strategy is also the highest among the other portfolio strategies with -34.06% maximum drawdown (MaxDD). But, if we compare the maximum drawdown (MaxDD) of equal-weight strategy rate with the other strategies, there are no significant differences because the lowest maximum drawdown (MaxDD) using the basic equal-weight strategy is -25.21%.