Use systematic investors toolbox (SIT)

Load Systematic Investor Toolbox (SIT)

#setInternet2(TRUE) # Load Systematic Investor Toolbox (SIT)

rm(list=ls())
#setInternet2(TRUE)
con = gzcon(url('https://github.com/systematicinvestor/SIT/raw/master/sit.gz', 'rb'))
source(con)
close(con)

Load historical data

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
## 
## Attaching package: 'TTR'
## The following object is masked _by_ '.GlobalEnv':
## 
##     DVI
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
library(quadprog)
library(lpSolve)
tickers = spl('SPY,QQQ,EEM,IWM,EFA,TLT,IYR,GLD')


data <- new.env()
getSymbols(tickers, src = 'yahoo', from = '2000-01-01', env = data, auto.assign = T)
## [1] "SPY" "QQQ" "EEM" "IWM" "EFA" "TLT" "IYR" "GLD"

[1] “SPY” “QQQ” “EEM” “IWM” “EFA” “TLT” “IYR” “GLD”

for(i in ls(data)) data[[i]] = adjustOHLC(data[[i]], use.Adjusted=T)

names(data)
## [1] "GLD"         "IWM"         "IYR"         "TLT"         "QQQ"        
## [6] ".getSymbols" "EEM"         "SPY"         "EFA"

[1] “GLD” “IWM” “IYR” “TLT” “QQQ”

[6] “.getSymbols” “EEM” “SPY” “EFA”

data.weekly <- new.env()
for(i in tickers) data.weekly[[i]] = to.weekly(data[[i]], indexAt='endof')

bt.prep(data, align='remove.na', dates='2000::2022')
bt.prep(data.weekly, align='remove.na', dates='2000::2022')
names(data)
##  [1] "GLD"             "prices"          "IWM"             "dates"          
##  [5] "IYR"             "TLT"             "weight"          "QQQ"            
##  [9] ".getSymbols"     "symbolnames"     "execution.price" "EEM"            
## [13] "SPY"             "EFA"
#*****************************************************************
# Code Strategies
#****************************************************************** 
prices = data$prices   
n = ncol(prices)
n
## [1] 8
# find week ends
week.ends = endpoints(prices, 'weeks')
week.ends = week.ends[week.ends > 0]     


# Equal Weight 1/N Benchmark
data$weight[] = NA
data$weight[week.ends,] = ntop(prices[week.ends,], n)       

#capital = 100000
#data$weight[] = (capital / prices) * data$weight
equal.weight = bt.run(data)
## Latest weights :
##             EEM  EFA  GLD  IWM  IYR  QQQ  SPY  TLT
## 2022-12-30 12.5 12.5 12.5 12.5 12.5 12.5 12.5 12.5
## 
## Performance summary :
##  CAGR    Best    Worst   
##  8.3 10.3    -8.8    
names(equal.weight)
## [1] "weight"      "type"        "ret"         "best"        "worst"      
## [6] "equity"      "cagr"        "dates.index"
head(equal.weight$equity)
##                 EEM
## 2004-11-18 1.000000
## 2004-11-19 1.000000
## 2004-11-22 1.006032
## 2004-11-23 1.008216
## 2004-11-24 1.014851
## 2004-11-26 1.016392
#*****************************************************************
# 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(prices)
weight[] = NA

for( i in week.ends[week.ends >= (63 + 1)] ) {
  # one quarter is 63 days
  hist = ret[ (i- 63 +1):i, ]
  
  # create historical input assumptions
  ia = create.historical.ia(hist, 252)
  #s0 = apply(coredata(hist),2,sd)     
  #ia$cov = cor(coredata(hist), use='complete.obs',method='pearson') * (s0 %*% t(s0))
  
  weight[i,] = min.risk.portfolio(ia, constraints)
}

tail(weight,1)
##               EEM        EFA       GLD        IWM          IYR        QQQ
## [4561,] 0.3109796 -0.4501837 0.3773814 -0.8443584 -0.004984299 -0.9045819
##              SPY       TLT
## [4561,] 2.218969 0.2967782
# Minimum Variance
data$weight[] = weight      
capital = 100000
data$weight[] = (capital / prices) * data$weight
min.var.daily = bt.run(data, type='share', capital=capital)
## Latest weights :
##              EEM    EFA   GLD    IWM  IYR    QQQ    SPY   TLT
## 2022-12-30 34.25 -51.19 48.19 -82.82 7.65 -93.89 217.12 20.69
## 
## Performance summary :
##  CAGR    Best    Worst   
##  7.9 4.1 -5.2    
names(min.var.daily)
##  [1] "weight"      "type"        "share"       "capital"     "ret"        
##  [6] "best"        "worst"       "equity"      "cagr"        "dates.index"
# Code Strategies: Weekly
#******************************************************************     
retw = data.weekly$prices / mlag(data.weekly$prices) - 1
weightw = coredata(prices)
weightw[] = NA
week.ends<-week.ends[ -length(week.ends) ]
for( i in week.ends[week.ends >= (63 + 1)] ) {   
  # map
  j = which(index(ret[i,]) == index(retw))
  
  # one quarter = 13 weeks
  hist = retw[ (j- 13 +1):j, ]
  
  # create historical input assumptions
  ia = create.historical.ia(hist, 52)
  #s0 = apply(coredata(hist),2,sd)     
  #ia$cov = cor(coredata(hist), use='complete.obs',method='pearson') * (s0 %*% t(s0))
  
  weightw[i,] = min.risk.portfolio(ia, constraints)
}   

data$weight[] = weightw     
capital = 100000
data$weight[] = (capital / prices) * data$weight
min.var.weekly = bt.run(data, type='share', capital=capital)
## Latest weights :
##               EEM    EFA    GLD    IWM   IYR     QQQ    SPY  TLT
## 2022-12-30 -25.91 -93.66 138.66 -70.47 17.57 -108.08 238.22 3.65
## 
## Performance summary :
##  CAGR    Best    Worst   
##  9.8 7.1 -13.9   
# Create Report
#****************************************************************** 
plotbt.custom.report.part1(min.var.daily, equal.weight)

#
models<-list(min.var.daily, equal.weight)
models<-list("Min.var.daily" = min.var.daily, 
             "Min.var.weekly" = min.var.weekly,
             "Equal.weight" = equal.weight)
#
strategy.performance.snapshoot(models,T)

## NULL
strategy.performance.snapshoot(models, control=list(comparison=T), 
                               sort.performance = T )

plotbt.strategy.sidebyside(models,return.table = T )

##            Min.var.daily       Min.var.weekly      Equal.weight       
## Period     "Nov2004 - Dec2022" "Nov2004 - Dec2022" "Nov2004 - Dec2022"
## Cagr       "7.91"              "9.81"              "8.28"             
## Sharpe     "0.98"              "0.78"              "0.57"             
## DVR        "0.95"              "0.74"              "0.51"             
## Volatility "8.13"              "13.23"             "16.49"            
## MaxDD      "-20.54"            "-41.88"            "-44.48"           
## AvgDD      "-1.27"             "-1.85"             "-1.75"            
## VaR        "-0.76"             "-1.13"             "-1.49"            
## CVaR       "-1.19"             "-1.88"             "-2.48"            
## Exposure   "98.6"              "98.6"              "99.96"
plotbt.strategy.sidebyside(min.var.daily,return.table = T)

##            min.var.daily      
## Period     "Nov2004 - Dec2022"
## Cagr       "7.91"             
## Sharpe     "0.98"             
## DVR        "0.95"             
## Volatility "8.13"             
## MaxDD      "-20.54"           
## AvgDD      "-1.27"            
## VaR        "-0.76"            
## CVaR       "-1.19"            
## Exposure   "98.6"
# plot Daily and Weekly transition maps
layout(1:2)
plotbt.transition.map(min.var.daily$weight)
legend('topright', legend = 'min.var.daily', bty = 'n')

plotbt.transition.map(min.var.weekly$weight)
legend('topright', legend = 'min.var.weekly', bty = 'n')