etf6 <- read.table('ETF6_20080101-20200430.csv', sep = ',', header = T)
#
head(etf6)
## 證券代碼 簡稱 年月日 收盤價.元.
## 1 0050 元大台灣50 20080102 39.6472
## 2 0052 富邦科技 20080102 27.0983
## 3 0056 元大高股息 20080102 14.5739
## 4 0050 元大台灣50 20080103 38.9876
## 5 0052 富邦科技 20080103 26.0676
## 6 0056 元大高股息 20080103 14.3758
etf6 <- etf6[, -2]
colnames(etf6) <- c('id', 'date', 'price')
head(etf6)
## id date price
## 1 0050 20080102 39.6472
## 2 0052 20080102 27.0983
## 3 0056 20080102 14.5739
## 4 0050 20080103 38.9876
## 5 0052 20080103 26.0676
## 6 0056 20080103 14.3758
library(pacman)
p_load(reshape2, xts, quantmod)
etf6.l <- dcast(etf6, date~id)
## Using price as value column: use value.var to override.
head(etf6.l)
## date 0050 0052 0056 0061 006206 00638R
## 1 20080102 39.6472 27.0983 14.5739 NA NA NA
## 2 20080103 38.9876 26.0676 14.3758 NA NA NA
## 3 20080104 38.9876 25.9346 14.4041 NA NA NA
## 4 20080107 37.2064 24.1391 14.1777 NA NA NA
## 5 20080108 37.5692 24.1391 14.3531 NA NA NA
## 6 20080109 38.2619 24.2721 14.4663 NA NA NA
etf6.l <- na.omit(etf6.l)
# head(etf6.l)
str(etf6.l)
## 'data.frame': 1214 obs. of 7 variables:
## $ date : int 20150518 20150519 20150520 20150521 20150522 20150525 20150526 20150527 20150528 20150529 ...
## $ 0050 : num 58.7 59.6 59.1 58.6 59.1 ...
## $ 0052 : num 34.8 34.9 35 34.6 35.1 ...
## $ 0056 : num 19.1 19.2 19.2 19 19 ...
## $ 0061 : num 21.8 22.4 22.7 22.8 23.3 ...
## $ 006206 : num 33.5 34.5 34.9 35 35.9 ...
## $ 00638R : num 20 19.5 19.2 19.2 18.6 ...
## - attr(*, "na.action")= 'omit' Named int [1:1827] 1 2 3 4 5 6 7 8 9 10 ...
## ..- attr(*, "names")= chr [1:1827] "1" "2" "3" "4" ...
# convert into xts
etf6.xts <- xts(etf6.l[, -1], order.by = as.Date(as.character(etf6.l$date), format = '%Y%m%d'))
class(etf6.xts)
## [1] "xts" "zoo"
head(etf6.xts)
## 0050 0052 0056 0061 006206 00638R
## 2015-05-18 58.6843 34.8094 19.0693 21.77 33.46 20.03
## 2015-05-19 59.5614 34.8596 19.1931 22.43 34.46 19.51
## 2015-05-20 59.1437 35.0268 19.1931 22.70 34.91 19.19
## 2015-05-21 58.6007 34.6339 18.9687 22.79 35.03 19.17
## 2015-05-22 59.0602 35.1104 18.9919 23.33 35.90 18.60
## 2015-05-25 59.0602 34.8596 18.9687 23.65 36.80 17.99
# SIT
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:base':
##
## close
#
data <- new.env()
model <- list()
etf3 <- etf6.xts[, 1:3]
head(etf3)
## 0050 0052 0056
## 2015-05-18 58.6843 34.8094 19.0693
## 2015-05-19 59.5614 34.8596 19.1931
## 2015-05-20 59.1437 35.0268 19.1931
## 2015-05-21 58.6007 34.6339 18.9687
## 2015-05-22 59.0602 35.1104 18.9919
## 2015-05-25 59.0602 34.8596 18.9687
names(etf3)
## [1] "0050 " "0052 " "0056 "
colnames(etf3) <- c('e50', 'e52', 'e56')
names(etf3)
## [1] "e50" "e52" "e56"
md = 50
i = 'e50'
for(i in names(etf3)) {
data$prices = data$weight = data$execution.price = etf3[, i]
data$weight[] <- 1
data$execution.price[] <- NA
model[[i]] <- bt.run(data)
sma <- SMA(data$prices, md)
data$weight[] <- iif(data$prices >= sma, 1, 0)
i <- paste(i, '.sma.cross', sep = '')
model[[i]] <- bt.run(data)
}
## Latest weights :
## e50
## 2020-04-30 100
##
## Performance summary :
## CAGR Best Worst
## 7.9 8 -7
##
## Latest weights :
## e50
## 2020-04-30 100
##
## Performance summary :
## CAGR Best Worst
## 5.8 2.3 -5.7
##
## Latest weights :
## e52
## 2020-04-30 100
##
## Performance summary :
## CAGR Best Worst
## 13.3 10 -9.2
##
## Latest weights :
## e52
## 2020-04-30 100
##
## Performance summary :
## CAGR Best Worst
## 10.6 4.3 -6.7
##
## Latest weights :
## e56
## 2020-04-30 100
##
## Performance summary :
## CAGR Best Worst
## 7.6 6.5 -6.2
##
## Latest weights :
## e56
## 2020-04-30 100
##
## Performance summary :
## CAGR Best Worst
## 6.1 2.4 -5.1
#-------------------------------------------------
strategy.performance.snapshoot(model, T)

## NULL
plotbt(model, plotX = T, log = 'y', LeftMargin = 3)
mtext('Cumulative Performance', side = 2, line = 1)
plotbt.strategy.sidebyside(model, return.table=T, make.plot = F)
## e50 e50.sma.cross e52
## Period "May2015 - Apr2020" "May2015 - Apr2020" "May2015 - Apr2020"
## Cagr "7.89" "5.83" "13.34"
## Sharpe "0.56" "0.63" "0.7"
## DVR "0.47" "0.36" "0.6"
## Volatility "16.23" "10.01" "21.67"
## MaxDD "-28.22" "-19.71" "-30.2"
## AvgDD "-2.67" "-2.52" "-3.55"
## VaR "-1.51" "-1" "-2.07"
## CVaR "-2.4" "-1.63" "-3.11"
## Exposure "99.92" "61.61" "99.92"
## e52.sma.cross e56 e56.sma.cross
## Period "May2015 - Apr2020" "May2015 - Apr2020" "May2015 - Apr2020"
## Cagr "10.63" "7.63" "6.05"
## Sharpe "0.84" "0.66" "0.8"
## DVR "0.68" "0.6" "0.62"
## Volatility "13.4" "12.68" "7.97"
## MaxDD "-19.08" "-25.15" "-10.39"
## AvgDD "-2.78" "-2.56" "-1.95"
## VaR "-1.35" "-1.22" "-0.84"
## CVaR "-2.1" "-2.06" "-1.36"
## Exposure "63.18" "99.92" "63.1"
# --------------------------------------------------
# Add equal-weighted portfolio for 3 ETFs
# --------------------------------------------------
data$prices = data$weight = data$execution.price = etf3
data$execution.price[] <- NA
prices <- data$prices
n <- ncol(prices)
data$weight <- ntop(prices, n)
model$etf3.EqWeight.bh <- bt.run(data)
## Latest weights :
## e50 e52 e56
## 2020-04-30 33.33 33.33 33.33
##
## Performance summary :
## CAGR Best Worst
## 10 7.5 -6.2
#
strategy.performance.snapshoot(model, T)


## NULL
plotbt(model, plotX = T, log = 'y', LeftMargin = 3)
mtext('Cumulative Performance', side = 2, line = 1)
plotbt.strategy.sidebyside(model, return.table=T, make.plot = F)
## e50 e50.sma.cross e52
## Period "May2015 - Apr2020" "May2015 - Apr2020" "May2015 - Apr2020"
## Cagr "7.89" "5.83" "13.34"
## Sharpe "0.56" "0.63" "0.7"
## DVR "0.47" "0.36" "0.6"
## Volatility "16.23" "10.01" "21.67"
## MaxDD "-28.22" "-19.71" "-30.2"
## AvgDD "-2.67" "-2.52" "-3.55"
## VaR "-1.51" "-1" "-2.07"
## CVaR "-2.4" "-1.63" "-3.11"
## Exposure "99.92" "61.61" "99.92"
## e52.sma.cross e56 e56.sma.cross
## Period "May2015 - Apr2020" "May2015 - Apr2020" "May2015 - Apr2020"
## Cagr "10.63" "7.63" "6.05"
## Sharpe "0.84" "0.66" "0.8"
## DVR "0.68" "0.6" "0.62"
## Volatility "13.4" "12.68" "7.97"
## MaxDD "-19.08" "-25.15" "-10.39"
## AvgDD "-2.78" "-2.56" "-1.95"
## VaR "-1.35" "-1.22" "-0.84"
## CVaR "-2.1" "-2.06" "-1.36"
## Exposure "63.18" "99.92" "63.1"
## etf3.EqWeight.bh
## Period "May2015 - Apr2020"
## Cagr "9.96"
## Sharpe "0.72"
## DVR "0.64"
## Volatility "15.12"
## MaxDD "-27.42"
## AvgDD "-2.37"
## VaR "-1.4"
## CVaR "-2.28"
## Exposure "99.92"
#=============================================================
# MVP investment strategy
#=============================================================
# monthly rebalance
# covariance matrix
# use monthly returns to compute monthly covariance matrix
etf3.m <- to.monthly(etf3, indexAt = 'lastof', OHLC = FALSE)
head(etf3.m)
## e50 e52 e56
## 2015-05-31 59.3943 35.3361 19.1312
## 2015-06-30 57.9742 33.8397 18.3418
## 2015-07-31 55.2593 31.4489 16.9875
## 2015-08-31 52.0431 28.6985 16.0820
## 2015-09-30 52.1267 29.5512 16.2832
## 2015-10-31 54.4474 31.1813 17.5373
etf3.w <- to.weekly(etf3, indexAt = 'lastof', OHLC = FALSE)
head(etf3.w)
## e50 e52 e56
## 2015-05-22 59.0602 35.1104 18.9919
## 2015-05-29 59.3943 35.3361 19.1312
## 2015-06-05 57.1806 33.7477 18.5740
## 2015-06-12 57.4730 33.7227 18.0710
## 2015-06-18 57.1388 33.6474 18.1948
## 2015-06-26 58.8513 38.2536 18.5353
#
#=================================================================
# MVP portfolio
#=================================================================
# Reset inputs to SIT bt function
data$prices = data$weight = data$execution.price = etf3.m
#data$prices <- industry.price.sample
#data$weight <- industry.price.sample
#data$execution.price <- industry.price.sample
data$execution.price[] <- NA
prices <- data$prices
n <- ncol(prices)
#*****************************************************************
# Create Constraints
#*****************************************************************
constraints = new.constraints(n, lb = 0, ub = +Inf)
# SUM x.i = 1
constraints = add.constraints(rep(1, n), 1, type = '=', constraints)
#
ret = prices / mlag(prices) - 1
weight = coredata(prices)
weight[] = NA
i = 36
for (i in 36:dim(weight)[1]) {
# using 36 historical monthly returns
hist = ret[ (i- 36 +1):i, ]
hist = na.omit(hist)
# create historical input assumptions
ia = create.historical.ia(hist, 12)
# s0 = apply(coredata(hist),2, sd)
ia$cov = cov(coredata(hist))
#ia$cov = cor(coredata(hist), use='complete.obs',method='kendall') * (s0 %*% t(s0))
# use min.risk.portfolio() to compute MVP weights
weight[i,] = min.risk.portfolio(ia, constraints)
}
## Loading required package: kernlab
##
## Attaching package: 'kernlab'
## The following object is masked from 'package:SIT':
##
## cross
#
weight
## e50 e52 e56
## [1,] NA NA NA
## [2,] NA NA NA
## [3,] NA NA NA
## [4,] NA NA NA
## [5,] NA NA NA
## [6,] NA NA NA
## [7,] NA NA NA
## [8,] NA NA NA
## [9,] NA NA NA
## [10,] NA NA NA
## [11,] NA NA NA
## [12,] NA NA NA
## [13,] NA NA NA
## [14,] NA NA NA
## [15,] NA NA NA
## [16,] NA NA NA
## [17,] NA NA NA
## [18,] NA NA NA
## [19,] NA NA NA
## [20,] NA NA NA
## [21,] NA NA NA
## [22,] NA NA NA
## [23,] NA NA NA
## [24,] NA NA NA
## [25,] NA NA NA
## [26,] NA NA NA
## [27,] NA NA NA
## [28,] NA NA NA
## [29,] NA NA NA
## [30,] NA NA NA
## [31,] NA NA NA
## [32,] NA NA NA
## [33,] NA NA NA
## [34,] NA NA NA
## [35,] NA NA NA
## [36,] 5.708131e-01 1.013557e-05 0.4291768
## [37,] 5.938460e-01 1.178948e-05 0.4061422
## [38,] 5.677347e-01 1.256961e-05 0.4322528
## [39,] 4.303263e-01 1.376488e-05 0.5696600
## [40,] 4.636123e-01 2.088299e-05 0.5363669
## [41,] 4.977120e-01 2.056603e-05 0.5022675
## [42,] 8.947075e-02 1.760397e-05 0.9105116
## [43,] 1.644829e-01 1.174734e-05 0.8355054
## [44,] 1.230427e-01 1.322863e-05 0.8769441
## [45,] 1.981367e-01 1.111005e-05 0.8018522
## [46,] 1.536536e-01 1.271208e-05 0.8463337
## [47,] 1.360303e-01 1.363474e-05 0.8639561
## [48,] 1.625490e-01 1.377061e-05 0.8374372
## [49,] 1.589876e-01 1.096594e-05 0.8410014
## [50,] 1.633204e-01 1.098421e-05 0.8366686
## [51,] 2.059597e-02 1.548506e-05 0.9793885
## [52,] 1.564765e-02 1.527667e-05 0.9843371
## [53,] 1.038049e-02 1.519358e-05 0.9896043
## [54,] 9.702991e-04 1.160429e-05 0.9990181
## [55,] 5.009475e-04 1.216192e-05 0.9994869
## [56,] 1.938941e-04 1.063642e-05 0.9997955
## [57,] 1.408883e-04 9.698083e-06 0.9998494
## [58,] 7.660880e-05 8.422007e-06 0.9999150
## [59,] 2.533141e-05 6.006477e-06 0.9999687
## [60,] 2.019810e-05 5.206983e-06 0.9999746
weight <- round(weight, digits = 2)
#format(round(weight, 2), nsmall = 2)
#apply(weight, 1, sum)
data$weight[] = weight
#capital = 100000
#data$weight[] = (capital / prices) * data$weight
model$mvp.month = bt.run(data, type = "weight")
## Latest weights :
## e50 e52 e56
## 2020-04-30 0 0 100
##
## Performance summary :
## CAGR Best Worst
## 4 12.1 -12.2
#
plotbt.strategy.sidebyside(model, return.table=T, make.plot = T)

## e50 e50.sma.cross e52
## Period "May2015 - Apr2020" "May2015 - Apr2020" "May2015 - Apr2020"
## Cagr "7.89" "5.83" "13.34"
## Sharpe "0.56" "0.63" "0.7"
## DVR "0.47" "0.36" "0.6"
## Volatility "16.23" "10.01" "21.67"
## MaxDD "-28.22" "-19.71" "-30.2"
## AvgDD "-2.67" "-2.52" "-3.55"
## VaR "-1.51" "-1" "-2.07"
## CVaR "-2.4" "-1.63" "-3.11"
## Exposure "99.92" "61.61" "99.92"
## e52.sma.cross e56 e56.sma.cross
## Period "May2015 - Apr2020" "May2015 - Apr2020" "May2015 - Apr2020"
## Cagr "10.63" "7.63" "6.05"
## Sharpe "0.84" "0.66" "0.8"
## DVR "0.68" "0.6" "0.62"
## Volatility "13.4" "12.68" "7.97"
## MaxDD "-19.08" "-25.15" "-10.39"
## AvgDD "-2.78" "-2.56" "-1.95"
## VaR "-1.35" "-1.22" "-0.84"
## CVaR "-2.1" "-2.06" "-1.36"
## Exposure "63.18" "99.92" "63.1"
## etf3.EqWeight.bh mvp.month
## Period "May2015 - Apr2020" "May2015 - Apr2020"
## Cagr "9.96" "3.99"
## Sharpe "0.72" "0.41"
## DVR "0.64" "0.23"
## Volatility "15.12" "10.9"
## MaxDD "-27.42" "-15.46"
## AvgDD "-2.37" "-7.77"
## VaR "-1.4" "-3.7"
## CVaR "-2.28" "-8.86"
## Exposure "99.92" "40"
plotbt(model)
