ContextBase Logo


Synopsis

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



Working Directory, and Required Packages

# 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)


Strategy 1A:

Systematic Trading - Dollar Cost Averaging, (DCA)

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")


Strategy 1B:

Systematic Trading - Dollar Cost Averaging, (DCA)

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


Conclusion (Strategies 1A and 1B):

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



Strategy 2:

Swing Trading with Active Technical Indicators using inverted ETFs

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


Conclusion (Strategy 2)

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.