An ETF, (Exchange Traded Fund), is an investment fund of stocks, commodities, or bonds that are traded on stock exchanges. Many ETFs track a stock index, or bond index. ETFs have low costs, are tax efficient, and resemble company stock investment. ETFs have increased in popularity in recent years.
This document utilizes the QuantMod and PerformanceAnalytics R packages for backtesting of two Systematic “Dollar Cost Averaging” ETF strategies versus a Technical Indicators Swing Trading ETF strategy. The objective is to determine which trading strategy has the best Return Rate, via comparison of yearly ROI %.
Reference:
http://news.morningstar.com/articlenet/article.aspx?id=777726
# First set the Working Directory
# setwd(" ")
# Required Packages
# install.packages("quantmod")
# install.packages("PerformanceAnalytics")
# install.packages("FinCal")
# install.packages("TTR")
library(quantmod)
library(PerformanceAnalytics)
library(FinCal)
library(TTR)
library(ggplot2)
Dollar-cost averaging (DCA) is an investment technique of buying a fixed dollar amount of a particular investment on a regular schedule, regardless of the share price. The investor purchases more shares when prices are low and fewer shares when prices are high. The premise is that DCA lowers the average share cost over time, increasing the opportunity to profit. The DCA technique does not guarantee that an investor won’t lose money on investments. Rather, it is meant to allow investment over time instead of investment as a lump sum.
For this document, 5 ETFs are selected, with Diversified Portfolio Category/Country, and Morningstar ratings of 4-5 stars.
The DCA Entry Strategy is to buy every month into a preselected ETF for $100.
The Exit Strategy specifies each time an ETF/Fund reaches between +15% - 20% sell, then re-screen for the next fund meeting criteria above, and continue Dollar Cost Averaging every month. When the ETF price is above 15%, apply stop loss at 15%. When the ETF price is above 20%, apply stop loss at 20%. Then, continue stop loss incrementation every 5% above 15%.
# Get symbols
symbols <- c("IJH","SCHB","SCHX","VGK","VXF")
getSymbols(symbols, from="2012-01-01")
## [1] "IJH" "SCHB" "SCHX" "VGK" "VXF"
# Create prices dataframe
prices <- list()
for(i in 1:length(symbols)) {
prices[[i]] <- Ad(get(symbols[i]))
}
prices <- do.call(cbind, prices)
colnames(prices) <- gsub("\\.[A-z]*", "", colnames(prices))
# Calculate returns
returns <- na.omit(Return.calculate(prices))
# Create a chart of returns
charts.PerformanceSummary(returns, main = "ETF Returns Chart")
# Print Statistics
stats <- rbind(table.AnnualizedReturns(returns),
maxDrawdown(returns), CalmarRatio(returns),
SortinoRatio(returns) * sqrt(252))
print(round(stats, 3))
## IJH SCHB SCHX VGK VXF
## Annualized Return 0.090 0.072 0.073 0.007 0.072
## Annualized Std Dev 0.147 0.123 0.120 0.183 0.156
## Annualized Sharpe (Rf=0%) 0.608 0.590 0.608 0.040 0.459
## Worst Drawdown 0.160 0.146 0.140 0.197 0.204
## Calmar Ratio 0.559 0.495 0.523 0.037 0.353
## Sortino Ratio (MAR = 0%) 0.927 0.883 0.907 0.170 0.722
# Entry Strategy
# Percent change between start to end
q <- function(start, end) (end-start) / start
x <- Op(to.monthly(prices$IJH))
x <- as.vector(x)
n <- length(x)
final_price <- x[n]
x <- x[-n]
purchased <- ceiling(100 / x) # monthly shares purchased
invested <- purchased * x # monthly expense
sum(invested - 100) # Total amount extra spent above $100 each month
## [1] 3168.84
sum(invested) # Total invested (without changes)
## [1] 9668.84
sum(purchased) # Total shares after period
## [1] 76
result <- c(
'dca_result' = sum(q(x, final_price) * invested),
'lump_result' = sum(invested) * q(x[1], final_price),
'avg_result' = mean(q(x, final_price)) * sum(invested))
result / sum(invested) * 100 # proportion gained
## dca_result lump_result avg_result
## 37.20942 97.13156 36.10466
# Exit Strategy:
IJHsell <- returns$IJH*1000 > 15 & returns$IJH*1000 < 20
SCHBsell <- returns$SCHB*1000 > 15 & returns$SCHB*1000 < 20
SCHXsell <- returns$SCHX*1000 > 15 & returns$SCHX*1000 < 20
VGKsell <- returns$VGK*1000 > 15 & returns$VGK*1000 < 20
VXFsell <- returns$VXF*1000 > 15 & returns$VXF*1000 < 20
plot(as.numeric(IJHsell), type="n", xlab="Time", ylab="",
main="ETF Sell Signals")
lines(as.numeric(IJHsell))
lines(as.numeric(returns$IJH*10))
lines(as.numeric(SCHBsell), col="red")
lines(as.numeric(SCHXsell), col="blue")
lines(as.numeric(VGKsell), col="green")
lines(as.numeric(VXFsell), col="yellow")
The DCA Entry Strategy is to buy every month into a preselected ETF for $100.
The Exit Strategy specifies selecting the ETF with the most upward potential through the 52 Week high/low. When a new ETF exceeds the 52 week high/low of the current ETF, sell the current ETF, buy the new ETF, and continuing re-investing every month.
# Entry Strategy:
# Determine the ETF with the greatest range of 52W high/low:
diffIJH <- diff(range(min(returns$IJH), max(returns$IJH)))
diffSCHB <- diff(range(min(returns$SCHB), max(returns$SCHB)))
diffSCHX <- diff(range(min(returns$SCHX), max(returns$SCHX)))
diffVGK <- diff(range(min(returns$VGK), max(returns$VGK)))
diffVXF <- diff(range(min(returns$VXF), max(returns$VXF)))
FundTrends <- matrix(ncol=1, nrow=5)
rownames(FundTrends) <- c("IJH", "SCHB", "SCHX", "VGK", "VXF")
FundTrends[1,] <- diffIJH
FundTrends[2,] <- diffSCHB
FundTrends[3,] <- diffSCHX
FundTrends[4,] <- diffVGK
FundTrends[5,] <- diffVXF
FundTrends <- FundTrends[order(FundTrends, decreasing = T),]
print("52 week high/low of ETFs")
## [1] "52 week high/low of ETFs"
FundTrends
## VGK IJH VXF SCHB SCHX
## 0.14943136 0.07214551 0.07209696 0.06033273 0.05989548
UpwardFund <- FundTrends[1]
paste("The Fund with the greatest 52 week high/low is", names(UpwardFund))
## [1] "The Fund with the greatest 52 week high/low is VGK"
# Exit Strategy:
# Percent change between start to end
q <- function(start, end) (end-start) / start
x <- Op(to.monthly(prices$VGK))
x <- as.vector(x)
n <- length(x)
final_price <- x[n]
x <- x[-n]
# monthly shares purchased
purchased <- ceiling(100 / x)
# monthly expense
invested <- purchased * x
# Total amount extra spent above $100 each month
sum(invested - 100)
## [1] 1545.03
# Total invested (without changes)
sum(invested)
## [1] 8045.03
# Total shares after period
sum(purchased)
## [1] 160
result <- c(
'dca_result' = sum(q(x, final_price) * invested),
'lump_result' = sum(invested) * q(x[1], final_price),
'avg_result' = mean(q(x, final_price)) * sum(invested))
# proportion gained
result / sum(invested) * 100
## dca_result lump_result avg_result
## 12.56639 32.21209 11.81555
In the tests of DCA with ETF above, the first strategy, (1A), of buying into every month at $100 produce better results than strategy 1B, selecting the fund with the greatest 52 week high/low and then applying DCA. Therefore, incresed upward range of ETFs seems to not have an effect on the DCA strategy.
The average yearly return of Strategy 1A was 36.8, and the average yearly return of Strategy 1B was 7.0
The Entry Strategy involves Signal Line Crossing of the EMA7 with EMA14, upwards crossing with an uptrend, downward crossing with a downtrend. The “Relative Strength Indictor” jumps until > 70 or goes down to < 30, and should always be moving upward. Slow Stochastic (50,2), raises through 20-line or start, above the 20-line, an upward motion. The MACD(12,26,9) > 0. Gets close to the crossing point of the signal line, horizontal high above the zero line, or facing upward. MACD(12,26,9) should be convergent with graph : same trend as ETF graph. M50 position from the graph of the ETF, above M50 and going upward). Select ETFs with an average Volume above > 200k.
The Exit Strategy involves the signal line crossing the EMA7 with EMA14, crossing downtrend. The RSI(5) crosses downtrend. The slow stochastic(50,2) crosses downtrend. Descending MACD(12,26,9) goes towards a crossing of the Signal line, starting downward convergence between graph and MACD(12,26,9). The upward long trend MACD(12,26,9) > 0, and graph above M50. The RSI(5) > 70, and Slow Stochastic (50,2) goes uptrend at the 20-line. The Downward trends, (Inverse-Short), are; MACD(12,26,9) < 0, and graph under M50, RSI(5) < 30, Slow Stochastic (50,2) goes crosses downward at the 80-line.
# Entry Strategy:
# Our signal is a simple adjusted price over 200 day SMA.
signal <- prices > xts(apply(na.omit(prices), 2, SMA, n = 200),
order.by=index(na.omit(prices)))
# equal weight all assets with price above SMA200
weights <- signal/(rowSums(signal)+1e-16)
# With Return.portfolio, need all weights to sum to 1
weights$zeroes <- 1 - rowSums(weights)
returns$zeroes <- 0
monthlyWeights <- na.omit(weights[endpoints(weights, on = 'months'),])
weights <- na.omit(weights)
returns <- na.omit(returns)
# Exit Strategy:
macd <- MACD(na.omit(prices$IJH), nFast=12, nSlow=26,
nSig=9,maType=SMA,percent = FALSE)
signal <- Lag(ifelse(macd$macd < macd$signal, -1, 1))
portfolioReturns <- ROC(na.omit(prices$IJH))*signal
plot(portfolioReturns, main="Portfolio Returns")
table.Drawdowns(portfolioReturns, top=10)
## From Trough To Depth Length To Trough Recovery
## 1 2014-12-17 2016-11-10 <NA> -0.4306 618 479 NA
## 2 2012-07-25 2013-01-08 2013-08-19 -0.1405 268 114 154
## 3 2013-10-10 2014-01-06 2014-08-26 -0.0989 221 60 161
## 4 2012-03-07 2012-05-14 2012-07-02 -0.0919 82 48 34
## 5 2014-10-14 2014-10-20 2014-10-28 -0.0362 11 5 6
## 6 2012-07-06 2012-07-12 2012-07-24 -0.0325 13 5 8
## 7 2013-09-03 2013-09-09 2013-09-18 -0.0297 12 5 7
## 8 2013-08-20 2013-08-26 2013-08-27 -0.0178 6 5 1
## 9 2014-11-20 2014-11-25 2014-12-01 -0.0167 7 4 3
## 10 2013-09-19 2013-10-04 2013-10-08 -0.0162 14 12 2
charts.PerformanceSummary(portfolioReturns, main="Technical Indicators Performance")
# Print Statistics
portfolioStats <- rbind(table.AnnualizedReturns(portfolioReturns),
maxDrawdown(portfolioReturns),
CalmarRatio(portfolioReturns),
SortinoRatio(portfolioReturns) * sqrt(252))
print(round(portfolioStats, 3))
## IJH
## Annualized Return -0.046
## Annualized Std Dev 0.144
## Annualized Sharpe (Rf=0%) -0.318
## 4 0.431
## Calmar Ratio -0.106
## Sortino Ratio (MAR = 0%) -0.357
The average yearly return % of Strategy 2, during the 5 years, was -0.043. Therefore, the backtests of the 3 strategies seems to determine that DCA is as an effective strategy as use of Technical Indicators for trading ETFs.