## Q1. Download the data file 'hist_prices_df.rds' as your data set. This data set includes daily closing prices for all listed stocks in Taiwan stock market from 1999 to 2017.
stock <- readRDS("~/hist_prices_df.rds")
#install SIT
con = gzcon(url('https://github.com/systematicinvestor/SIT/raw/master/sit.gz', 'rb'))
source(con)
close(con)
library(xts)
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
## Registered S3 method overwritten by 'xts':
## method from
## as.zoo.xts zoo
library(quantmod)
## Loading required package: TTR
##
## Attaching package: 'TTR'
## The following object is masked _by_ '.GlobalEnv':
##
## DVI
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
## Version 0.4-0 included new data defaults. See ?getSymbols.
library(kernlab)
##
## Attaching package: 'kernlab'
## The following object is masked _by_ '.GlobalEnv':
##
## cross
#install.packages('reshape2')
library(reshape2)
## Q2. You have to select at least 10 stocks from the data set. To avoid selecting all stocks from one specific industry, you should select stocks with ticker numbers starting with '1', '2', '3', '4', '5' and '6'.
stock10 <- stock[,c("date","1110","1201","1713","2031", "6005","6191","2030","9937", "9902","9919")]
sum(is.na(stock10))
## [1] 0
stock.xts <- xts(stock10[,-1], order.by= as.Date(as.character(stock10[,1]),
format = '%Y%m%d'))
## Q3. Construct equal-weighted portfolio starting from 2007 to 2017. You can use monthly returns to generate the backtesting results.
#convert data into monthly
stock.monthly <- to.monthly(stock.xts, indexAt = 'lastof', OHLC=F)
monthlydata <- stock.monthly["2007/2017"]
#to create equal weight
#we need 5 inputs :
data <- new.env()
data$prices <- monthlydata
data$weight <- monthlydata
data$execution.price <- monthlydata
data$execution.price[] <- NA
data$symbolnames <- colnames(data$prices)
prices = data$prices
n = ncol(prices)
data$weight <- ntop(prices, n)
#1
model <- list()
model$equal.weight <- bt.run(data, trade.summary = T)
## Latest weights :
## 1110 1201 1713 2031 6005 6191 2030 9937 9902 9919
## 2017-12-31 10 10 10 10 10 10 10 10 10 10
##
## Performance summary :
## CAGR Best Worst
## 5.5 24.6 -30.1
#2
capital = 100000
data$weight[] = (capital / prices) * data$weight
equal.weight = bt.run(data, type='share')
## Latest weights :
## 1110 1201 1713 2031 6005 6191 2030 9937 9902 9919
## 2017-12-31 10 10 10 10 10 10 10 10 10 10
##
## Performance summary :
## CAGR Best Worst
## 5.5 24.6 -30.1
head(equal.weight$ret)
## 1110
## 2007-01-31 0.00000000
## 2007-02-28 0.03707025
## 2007-03-31 0.02699263
## 2007-04-30 0.06698060
## 2007-05-31 0.01999322
## 2007-06-30 0.11529022
bt.detail.summary(model$equal.weight)
## $System
## $System$Period
## [1] "Jan2007 - Dec2017"
##
## $System$Cagr
## [1] 5.46
##
## $System$Sharpe
## [1] 0.34
##
## $System$DVR
## [,1]
## 1110 0.11
##
## $System$Volatility
## [1] 24.36
##
## $System$MaxDD
## [1] -54.32
##
## $System$AvgDD
## [1] -21.72
##
## $System$VaR
## 5%
## -10.45
##
## $System$CVaR
## [1] -14.92
##
## $System$Exposure
## [1] 99.24
##
##
## $Trade
## $Trade$Win.Percent
## [1] 70
##
## $Trade$Avg.Trade
## [1] 4.8
##
## $Trade$Avg.Win
## [1] 7.6
##
## $Trade$Avg.Loss
## [1] -1.9
##
## $Trade$Best.Trade
## [1] 17.77
##
## $Trade$Worst.Trade
## [1] -4.69
##
## $Trade$WinLoss.Ratio
## [1] 4.12
##
## $Trade$Avg.Len
## [1] 131
##
## $Trade$Num.Trades
## [1] 10
##
##
## $Period
## $Period$Win.Percent.Day
## [1] 55.3
##
## $Period$Best.Day
## [1] 24.6
##
## $Period$Worst.Day
## [1] -30.1
##
## $Period$Win.Percent.Month
## [1] 55.3
##
## $Period$Best.Month
## [1] 24.6
##
## $Period$Worst.Month
## [1] -30.1
##
## $Period$Win.Percent.Year
## [1] 54.5
##
## $Period$Best.Year
## [1] 116
##
## $Period$Worst.Year
## [1] -35.1
plotbt.monthly.table(model$equal.weight$equity)

## Jan Feb Mar Apr May Jun Jul Aug Sep
## 2007 " NA" " 3.7" " 2.7" " 6.7" " 2.0" " 11.5" " 9.8" " -6.8" " 6.7"
## 2008 " -4.1" " 24.0" " 6.3" " 4.2" " -8.1" "-18.4" " -0.9" " -2.3" "-30.1"
## 2009 " -4.7" " 0.3" " 22.8" " 13.7" " 24.6" " -2.2" " 12.8" " -1.5" " 5.2"
## 2010 "-10.9" " -0.7" " 8.1" " -0.9" "-11.3" " 1.4" " 6.0" " -0.5" " 7.1"
## 2011 " -0.6" " -4.9" " 0.3" " 0.7" " -0.8" " -2.8" " 3.1" "-10.3" " -9.2"
## 2012 " 7.6" " 10.7" " -3.8" " -5.8" " -3.4" " -1.7" " 0.6" " 2.9" " 7.4"
## 2013 " 1.2" " 0.1" " 0.4" " 3.7" " 6.8" " -2.8" " 2.6" " -1.4" " 2.8"
## 2014 " -0.7" " 0.1" " -1.3" " -4.5" " 3.4" " -0.1" " 4.4" " 0.6" " -4.2"
## 2015 " -0.1" " 0.4" " -0.7" " 1.0" " -5.0" " -7.1" " -4.0" " -9.1" " 5.9"
## 2016 " -3.9" " 5.1" " 1.9" " 0.1" " -1.2" " -0.8" " 3.7" " 1.6" " 0.4"
## 2017 " -0.1" " 5.9" " 0.8" " -2.3" " -0.1" " 1.2" " 3.8" " 5.5" " -1.6"
## Avg " -1.6" " 4.1" " 3.4" " 1.5" " 0.6" " -2.0" " 3.8" " -1.9" " -0.9"
## Oct Nov Dec Year MaxDD
## 2007 "-10.6" " -8.3" " -3.8" " 11.4" "-21.5"
## 2008 "-10.1" " 4.8" " 2.7" "-35.1" "-54.3"
## 2009 " -0.3" " 2.7" " 11.1" "116.0" " -4.7"
## 2010 " -2.7" " -1.3" " 10.4" " 2.2" "-15.9"
## 2011 " 5.3" "-12.2" " 1.6" "-27.3" "-28.5"
## 2012 "-10.9" " 3.9" " 7.3" " 13.2" "-14.8"
## 2013 " 4.5" " -2.1" " 3.9" " 21.0" " -2.8"
## 2014 " -6.3" " 2.0" " 4.5" " -2.7" "-10.2"
## 2015 " 5.3" " -6.7" " 3.3" "-16.7" "-23.0"
## 2016 " 0.1" " 6.0" " 2.2" " 15.7" " -3.9"
## 2017 " 3.5" " -1.2" " 3.7" " 20.3" " -2.4"
## Avg " -2.0" " -1.1" " 4.3" " 10.7" "-16.5"
plotbt.transition.map(model$equal.weight$weight)

strategy.performance.snapshoot(model, T)

## NULL
sma.cross = bt.run(data, trade.summary=T)
## Latest weights :
## 1110 1201 1713 2031 6005 6191 2030
## 2017-12-31 71174.38 51546.39 59171.6 38167.94 87719.3 76335.88 65359.48
## 9937 9902 9919
## 2017-12-31 25316.46 99009.9 81967.21
##
## Performance summary :
## CAGR Best Worst
## -100 114544.6 -100
## Q4. Construct MVP portfolio starting from 2004-2017. Year 2004-2006 will be used as in sample data to compute covariance matrix for MVP.
data.monthly <- stock.monthly["2004/2017"]
data.monthly.1 <- stock.monthly["2004/2006"]
Sigma_monthly <- cov(data.monthly.1)
head(Sigma_monthly)
## 1110 1201 1713 2031 6005 6191 2030
## 1110 1.4811913 2.9526414 0.9320837 2.5599910 0.2077950 1.3766294 1.5821007
## 1201 2.9526414 7.0602600 1.9580214 2.4464729 0.5048214 4.1144071 3.3241100
## 1713 0.9320837 1.9580214 0.8667075 0.8199415 0.3474521 0.7908475 1.0728036
## 2031 2.5599910 2.4464729 0.8199415 25.5479094 -1.3473907 -10.6009413 1.6084350
## 6005 0.2077950 0.5048214 0.3474521 -1.3473907 0.4505850 1.0522607 0.5238679
## 6191 1.3766294 4.1144071 0.7908475 -10.6009413 1.0522607 15.6384847 1.3755379
## 9937 9902 9919
## 1110 -0.03836484 1.72698817 0.77693524
## 1201 0.40682143 2.18419000 1.89146571
## 1713 0.28893897 1.12644151 0.37708381
## 2031 -3.81664706 9.43056373 0.83046190
## 6005 0.53722643 -0.08482786 -0.02085714
## 6191 1.35344468 -1.14811563 1.45554667
ones = rep(1,10)
one.vec = matrix(ones, ncol=1)
a = inv(Sigma_monthly)%*%one.vec
b = t(one.vec)%*%a
mvp.w.monthly =a / as.numeric(b)
mvp.w.monthly
## [,1]
## 1110 0.355437346
## 1201 -0.196158142
## 1713 -0.074645212
## 2031 -0.004758405
## 6005 0.474764303
## 6191 -0.054887278
## 2030 -0.200969768
## 9937 0.092154782
## 9902 0.002625952
## 9919 0.606436422
mvp.ret<-sum((mvp.w.monthly)*colMeans(data.monthly.1))
mvp.ret
## [1] 6.886455
hist(mvp.w.monthly)

## Q5. Similar to question 4, however, you need to construct MVP portfolio using single factor model (CAPM) to compute covariance matrix and generate backtesting results.
data$prices = data$weight = data$execution.price = monthlydata
data$execution.price[] <- NA
prices <- data$prices
n <- ncol(prices)
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(prices)
weight[] = NA
nrow(prices)
## [1] 132
hist <- na.omit(ret[1:36,])
cov(hist)
## 1110 1201 1713 2031 6005 6191
## 1110 0.018243806 0.012030526 0.012574063 0.015989613 0.015086846 0.006811481
## 1201 0.012030526 0.016363116 0.011593381 0.011610111 0.012064238 0.006641807
## 1713 0.012574063 0.011593381 0.015882476 0.015939212 0.013171598 0.008086392
## 2031 0.015989613 0.011610111 0.015939212 0.027504038 0.021576111 0.012902372
## 6005 0.015086846 0.012064238 0.013171598 0.021576111 0.033026821 0.011348404
## 6191 0.006811481 0.006641807 0.008086392 0.012902372 0.011348404 0.019321391
## 2030 0.013748476 0.010516726 0.013607931 0.018004663 0.016743330 0.010996121
## 9937 0.006013309 0.006149080 0.007142457 0.006573010 0.009182638 0.007118646
## 9902 0.018538958 0.014832400 0.016344588 0.017163931 0.021034044 0.009073662
## 9919 0.004737781 0.007267715 0.006948181 0.007912894 0.005967415 0.007773179
## 2030 9937 9902 9919
## 1110 0.013748476 0.006013309 0.018538958 0.004737781
## 1201 0.010516726 0.006149080 0.014832400 0.007267715
## 1713 0.013607931 0.007142457 0.016344588 0.006948181
## 2031 0.018004663 0.006573010 0.017163931 0.007912894
## 6005 0.016743330 0.009182638 0.021034044 0.005967415
## 6191 0.010996121 0.007118646 0.009073662 0.007773179
## 2030 0.018680911 0.007198008 0.018500762 0.006689200
## 9937 0.007198008 0.010752908 0.013451627 0.005474698
## 9902 0.018500762 0.013451627 0.042596166 0.008930896
## 9919 0.006689200 0.005474698 0.008930896 0.016259516
ia = create.historical.ia(hist,12)
s0 = apply(coredata(hist), 2 , sd)
ia$cov = cor(coredata(hist), use='complete.obs',method='pearson') * (s0 %*% t(s0))
weight[36,] = min.risk.portfolio(ia, constraints)
weight[36,]
## 1110 1201 1713 2031 6005 6191
## 0.32860178 0.07220353 0.04066975 -0.11344441 -0.01813304 0.04288876
## 2030 9937 9902 9919
## 0.10251581 0.57388928 -0.24879832 0.21960686
sum(weight[36,])
## [1] 1
model$min.var.monthly <- bt.run(data, trade.summary = T)
## Latest weights :
## 1110 1201 1713 2031 6005 6191 2030 9937 9902 9919
## 2017-12-31 1405 1940 1690 2620 1140 1310 1530 3950 1010 1220
##
## Performance summary :
## CAGR Best Worst
## -100 1308 -100
#data$weight[] = weight
#capital = 100000
#data$weight[] = (capital / prices) * data$weight
# to verify the default do.lag = 1 day
sum(as.numeric(weight[36,])*as.numeric(ret[37,]))
## [1] -0.11114
model$min.var.monthly$ret[37, ]
## 1110
## 2010-01-31 -1
plotbt.strategy.sidebyside(model, return.table=T, make.plot = T)
## Warning in max(mret, na.rm = T): no non-missing arguments to max; returning -Inf
## Warning in min(mret, na.rm = T): no non-missing arguments to min; returning Inf

## equal.weight min.var.monthly
## Period "Jan2007 - Dec2017" "Jan2007 - Dec2017"
## Cagr "5.46" "-100"
## Sharpe "0.34" "-1.04"
## DVR "0.11" "-0.02"
## Volatility "24.36" "699.81"
## MaxDD "-54.32" "-100"
## AvgDD "-21.72" "-100"
## VaR "-10.45" "-100"
## CVaR "-14.92" "NaN"
## Exposure "99.24" "99.24"
plotbt(model)

## Q6. Similar to question 4, however, you need to construct MVP portfolio using Fama French three factor model to compute covariance matrix and generate backtesting results.
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(prices)
weight[] = NA
#
weights = list()
# Equal Weight 1/N Benchmark
weights$equal.weight = weight
weights$equal.weight[] = ntop(prices, n)
start.i = 35
weights$equal.weight[1:start.i,] = NA
#
weights$min.var = weight
weights$min.maxloss = weight
weights$min.mad = weight
weights$min.cvar = weight
weights$min.cdar = weight
weights$min.cor.insteadof.cov = weight
weights$min.mad.downside = weight
weights$min.risk.downside = weight