Shiny with PerformanceAnalytics Example

The folks at Rstudio have done some amazing work with the shiny package. From the shiny homepage, “Shiny makes it super simple for R users like you to turn analyses into interactive web applications that anyone can use.” Developing web applications has always appealed to me, but hosting, learning javascript, html, etc. made me put this pretty low on my priority list. With shiny, one can write web applications in R.

This example uses the managers dataset with calls to charts.PerformanceSummary and table.Stats from the PerformanceAnalytics package to display a plot and table in the shiny application.

Below is a screenshot of the application.
Screen Shot 2013-03-04 at 6.37.34 AM

You need to have shiny and Performance Analytics packages installed to run the application. Once those are installed, open your R prompt and run:

shiny::runGist("https://gist.github.com/rbresearch/5081906")

There is a great shiny tutorial from Rstudio as well as examples from SystematicInvestor for those interested in learning more.

 

Momentum in R: Part 4 with Quantstrat

The past few posts on momentum with R focused on a relatively simple way to backtest momentum strategies. In part 4, I use the quantstrat framework to backtest a momentum strategy. Using quantstrat opens the door to several features and options as well as an order book to check the trades at the completion of the backtest.

I introduce a few new functions that are used to prep the data and compute the ranks. I won’t go through them in detail, these functions are available in my github repo in the rank-functions folder.

This first chunk of code just loads the necessary libraries, data, and applies the ave3ROC function to rank the assets based on averaging the 2, 4, and 6 month returns. Note that you will need to load the functions in Rank.R and monthly-fun.R.

library(quantstrat)
library(PerformanceAnalytics)

currency("USD")
symbols <- c("XLY", "XLP", "XLE", "AGG", "IVV")
stock(symbols, currency="USD")

# get data for the symbols
getSymbols(symbols, from="2005-01-01", to="2012-12-31")

# create an xts object of monthly adjusted close prices
symbols.close <- monthlyPrices(symbols)

# create an xts object of the symbol ranks
sym.rank <- applyRank(x=symbols.close, rankFun=ave3ROC, n=c(2, 4, 6))

Created by Pretty R at inside-R.org

The next chunk of code is a critical step in preparing the data to be used in quantstrat. With the ranks computed, the next step is to bind the ranks to the actual market data to be used with quantstrat. It is also important to change the column names to e.g. XLY.Rank because that will be used as the trade signal column when quantstrat is used.

# this is an important step in naming the columns, e.g. XLY.Rank
# the "Rank" column is used as the trade signal (similar to an indicator)
# in the qstratRank function
colnames(sym.rank) <- gsub(".Adjusted", ".Rank", colnames(sym.rank))

# ensure the order of order symbols is equal to the order of columns 
# in symbols.close
stopifnot(all.equal(gsub(".Adjusted", "", colnames(symbols.close)), symbols))

# bind the rank column to the appropriate symbol market data
# loop through symbols, convert the data to monthly and cbind the data
# to the rank
for(i in 1:length(symbols)) {
  x <- get(symbols[i])
  x <- to.monthly(x,indexAt='lastof',drop.time=TRUE)
  indexFormat(x) <- '%Y-%m-%d'
  colnames(x) <- gsub("x",symbols[i],colnames(x))
  x <- cbind(x, sym.rank[,i])
  assign(symbols[i],x)
}

Created by Pretty R at inside-R.org

Now the backtest can be run. The function qstratRank is just a convenience function that hides the quantstrat implementation for my Rank strategy.

For this first backtest, I am trading the top 2 assets with a position size of 1000 units.

# run the backtest
bt <- qstratRank(symbols=symbols, init.equity=100000, top.N=2,
                  max.size=1000, max.levels=1)

# chart of returns
charts.PerformanceSummary(bt$returns[,"total"], geometric=FALSE, 
                          wealth.index=TRUE, main="Total Performance")

Created by Pretty R at inside-R.org

Rplot1

Changing the argument to max.levels=2 gives the flexibility of “scaling” in a trade. In this example, say asset ABC is ranked 1 in the first month — I buy 500 units. In month 2, asset ABC is still ranked 1 — I buy another 500 units.

# run the backtest
bt <- qstratRank(symbols=symbols, init.equity=100000, top.N=2,
                  max.size=1000, max.levels=2)

# chart of returns
charts.PerformanceSummary(bt$returns[,"total"], geometric=FALSE, 
                          wealth.index=TRUE, main="Total Performance")

Created by Pretty R at inside-R.org

Rplot2

Full code available here: quantstrat-rank-backtest.R

Strategy Diversification in R – follow up

The strategies used in Strategy Diversification in R were labeled as Strategy1 and Strategy2.

Strategy1

  • Indicator: 52 week Simple Moving Average
  • Entry Rule: Buy 1000 shares when price crosses and closes above 52 week Simple Moving Average
  • Exit Rule: Exit all positions when prices crosses and closes below 52 week Simple Moving Average
  • Classification: Long term trend following strategy

Strategy 2

  • Indicator: RSI(2) on weekly data
  • Entry Rule: Buy 100 shares when RSI(2) is less than 20 (Note that if RSI(2) is below 20 for N days, then you will have accumulated N * 100 shares)
  • Exit Rule: Exit all positions when RSI(2) is greater than 50
  • Classification: Short-Medium term reversal (dip buying) strategy

What did we diversify?

  1. Symbols? – No, the exact same instruments were used in the strategy.
  2. Markets? – No, see #1.
  3. Timeframe? Sort of, Strategy1 is a long term strategy and Strategy2 is a shorter term strategy, but both are on the weekly timeframe. We could diversify further by trading even shorter timeframes (i.e. Daily, Hourly, minute, tick, etc.)
  4. Strategy? Yes, Strategy1 is a trend following strategy and Strategy2 is a reversal strategy.
  5. Risk Levels? Yes, Strategy2 trades more often, but in smaller increments.

We achieved fairly low correlations by achieving only three “levels” of diversification. Think what we could do by using a “kitchen sink” portfolio with grains, softs, metals, currencies, stocks, fixed income, international stocks, international fixed income, style ETFs, etc.

Three R script files were used in the last post.

strategy1.R, strategy2.R, and correlation chart.R

The R scripts are pretty self explanatory so I won’t go into much detail. However, I do want to call attention to 2 lines of code from strategy1.R. The code for strategy2.R is virtually identical.

# logarithmic returns of the equity curve of strategy1.
strategy1_eclogret <- ec$logret

# write the logarithmic returns of strategy 1 to a csv file with the filename "strategy1.csv"
# you will have to change the file where you want to save it
write.zoo(strategy1_eclogret, file = "~/R/strats_for_cor/strategy1.csv", sep=",")

Created by Pretty R at inside-R.org

Here is the code to make the correlation chart.

#Load the packages used
require(PerformanceAnalytics)

# load the strategy 1 returns
strat1 <- as.xts(read.zoo(file = "~/R/strats_for_cor/strategy1.csv", header = TRUE, sep=","))
colnames(strat1) <- "strat1"

# load the strategy 2 returns
strat2 <- as.xts(read.zoo(file = "~/R/strats_for_cor/strategy2.csv", header = TRUE, sep=","))
colnames(strat2) <- "strat2"

suppressWarnings(chart.RollingCorrelation(strat1, strat2, width = 52, xaxis = TRUE, 
                                          colorset = rich8equal, legend.loc = "bottomright",
                                          main = "Rolling 52 Week Correlation"))

Created by Pretty R at inside-R.org

And that is all there is to it. (run strategy1.R, run strategy2.R, then run correlation chart.R – don’t forget to change the file directory!)

I listed 5 “levels” or ways to achieve diversification… what are other ways we can diversify? – post your ideas in the comments

Strategy Diversification in R

In my last post, I looked at the correlations of different instruments. Understanding the correlations of instruments is important when developing a strategy and selecting the assets to include. In theory, selecting highly correlated instruments for a portfolio or strategy will be more volatile than a portfolio or strategy with several uncorrelated instruments. This sounds great in theory, but can be difficult to apply in real life. Why? – correlations change over time and just diversifying among instruments is not enough. Just take a look at the graph below from my post on correlations as well as Systematic Investor’s analysis of Cross Sectional Correlation.

Correlations are changing over time and markets are becoming more correlated in recent times. As the correlations between markets and instruments increases, the impact of diversification decreases. You may be asking yourself (like I am), “If I can’t diversify among assets, what else can I do to diversify?” My answer to this is to diversify in as many ways as you can – trade multiple strategies, multiple timeframes, multiple risk levels, multiple markets, multiple instruments, etc.

To demonstrate this, I will take two strategies:

  • Strategy1 – longer term strategy
  • Strategy2 – shorter term strategy

(Yes… I realize that I am being very vague about the strategies at this point, more on the strategy details later in the post.)

Here are the outcomes of each strategy using quantstrat to backtest.

Strategy 1

CAGR maxDD MAR
6.599 -36.358 0.182

rbresearch

Strategy 2

CAGR maxDD MAR
2.637 -9.637 0.274

rbresearch

How does each strategy correlate to eachother?

rbresearch

The chart above shows that Strategy 1 is not very strongly correlated with Strategy 2.

Now for more information on the strategies.

  • Strategy 1 and Strategy 2 both trade the same universe of instruments (“XLY”, “XLP”, “XLE”, “XLF”, “XLV”, “XLI”, “XLK”, “XLB”, “XLU”)
  • Strategy 1 is a 52 week moving average strategy and trades 1000 contracts per trade*
  • Strategy 2 is a RSI(2) on weekly data strategy and trades 100 contracts per trade*
  • *Note on position sizing. Normally I would do a volatility based position sizing, but the RSI(2) strategy took about 20 minutes to complete the test because of the looping in the order sizing function. So for brevity and testing purposes I used fixed contract sizes as stated above for each strategy.

Are you surprised that two strategies that trade the exact same set of instruments would not have a higher correlation? I was!

This example reinforces how diversification can be achieved in more ways than one.

In follow-up posts, I will share the R code for the strategies and show how I plotted the correlations.

Low Volatility with R

Low volatility and minimum variance strategies have been getting a lot of attention lately due to their outperformance in recent years. Let’s take a look at how we can incorporate this low volatility effect into a monthly rotational strategy with a basket of ETFs.

Performance Summary from Low Volatility Test in quantstrat

Starting Equity: 100,000
Ending Equity: 114,330
CAGR: 1.099%
maxDD: -38.325%
MAR:  0.0287

Not the greatest performance stats in the world. There are some things we can do to improve this strategy. I will save that for later. The purpose of this post was an exercise using quantstrat to implement a low volatility ranking system.

We can see from the chart that the low volatility strategy does what it is supposed to do… the drawdown is reduced compared to a buy and hold strategy on SPY. This is by no means a conclusive test. Ideally, the test would cover 20, 40, 60+ years of data to show the “longer” term performance of both strategies.

Here is a step by step approach to implement the strategy in R

The first step is fire up R and require the quantstrat package.

require(quantstrat)

This test will use nine of the Select Sector SPDR ETFs.
XLY – Consumer Discretionary Select Sector SPDR
XLP – Consumer Staples Select Sector SPDR
XLE – Energy Select Sector SPDR
XLF – Financial Select Sector SPDR
XLV – Health Care Select Sector SPDR
XLI – Industrial Select Sector SPDR
XLK – Technology Select Sector SPDR
XLB – Materials Select Sector SPDR
XLU – Utilities Select Sector SPDR

#Symbol list to pass to the getSymbols function
symbols = c("XLY", "XLP", "XLE", "XLF", "XLV", "XLI", "XLK", "XLB", "XLU")
#Load ETFs from yahoo
currency("USD")
stock(symbols, currency="USD",multiplier=1)
getSymbols(symbols, src='yahoo', index.class=c("POSIXt","POSIXct"), from='2000-01-01')

#Data is downloaded as daily data
#Convert to monthly
for(symbol in symbols) {
  x<-get(symbol)
  x<-to.monthly(x,indexAt='lastof',drop.time=TRUE)
  indexFormat(x)<-'%Y-%m-%d'
  colnames(x)<-gsub("x",symbol,colnames(x))
  assign(symbol,x)
}

Here is what the data for XLB looks like after it is downloaded

> tail(XLB)
           XLB.Open XLB.High XLB.Low XLB.Close XLB.Volume XLB.Adjusted
2011-11-30    33.10    35.73   31.41     34.52  290486300        34.15
2011-12-31    34.34    35.01   31.86     33.50  233453200        33.37
2012-01-31    34.24    37.73   34.23     37.18  171601400        37.04
2012-02-29    37.48    37.97   36.40     36.97  179524000        36.83
2012-03-31    37.19    37.65   35.80     36.97  201651000        36.97
2012-04-30    36.92    37.63   35.10     35.59   85846600        35.59

The measure of volatility that I will use is a rolling 12 period standard deviation of the 1 period ROC. The 1 period ROC is taken on the Adjusted Close prices. My approach for the ranking system is to first apply the standard deviation to the market data and then assign a rank of 1, 2, …9 for the instruments. There may be a more elegant way to do this in R, so if you have an alternative way to implement this I am all ears.

#Calcuate the ranking factors for each symbol and bind to its symbol
#This loops through the list of symbols and adds a "RANK" column
for(symbol in symbols) {
  x <- get(symbol)
  x1 <- ROC(Ad(x), n=1, type="continuous", na.pad=TRUE)
  colnames(x1) <- "ROC"
  colnames(x1) <- paste("x",colnames(x1), sep =".")
  #x2 is the 12 period standard deviation of the 1 month return
  x2 <- runSD(x1, n=12)
  colnames(x2) <- "RANK"
  colnames(x2) <- paste("x",colnames(x2), sep =".")
  x <- cbind(x,x2)
  colnames(x)<-gsub("x",symbol,colnames(x))
  assign(symbol,x)
}

Now the XLB data has an extra column of the 12 period SD of the 1 period ROC named “RANK”

> tail(XLB)
           XLB.Open XLB.High XLB.Low XLB.Close XLB.Volume XLB.Adjusted   XLB.RANK
2011-11-30    33.10    35.73   31.41     34.52  290486300        34.15 0.08300814
2011-12-31    34.34    35.01   31.86     33.50  233453200        33.37 0.07752127
2012-01-31    34.24    37.73   34.23     37.18  171601400        37.04 0.08425784
2012-02-29    37.48    37.97   36.40     36.97  179524000        36.83 0.08381949
2012-03-31    37.19    37.65   35.80     36.97  201651000        36.97 0.08360368
2012-04-30    36.92    37.63   35.10     35.59   85846600        35.59 0.08367737
#Bind each symbols's "RANK" column into a single xts object
rank.factors <- cbind(XLB$XLB.RANK,
                      XLE$XLE.RANK,
                      XLF$XLF.RANK,
                      XLI$XLI.RANK,
                      XLK$XLK.RANK,
                      XLP$XLP.RANK,
                      XLU$XLU.RANK,
                      XLV$XLV.RANK,
                      XLY$XLY.RANK)

Here is what our rank.factors object looks like.

> tail(rank.factors)
             XLB.RANK   XLE.RANK   XLF.RANK   XLI.RANK   XLK.RANK   XLP.RANK   XLU.RANK   XLV.RANK   XLY.RANK
2011-11-30 0.08300814 0.08837101 0.07381782 0.06492454 0.04169398 0.02930909 0.01532320 0.03559538 0.04946373
2011-12-31 0.07752127 0.08522966 0.06612174 0.06136258 0.03898518 0.02811202 0.01555798 0.03451478 0.04843218
2012-01-31 0.08425784 0.08291821 0.07063470 0.06389852 0.04171582 0.02806211 0.02160217 0.03502983 0.05052721
2012-02-29 0.08381949 0.08192191 0.07192495 0.06410781 0.04552402 0.02863641 0.02164171 0.03451369 0.04946965
2012-03-31 0.08360368 0.08223880 0.07536219 0.06385518 0.04589758 0.02914123 0.02158078 0.03581751 0.05032237
2012-04-30 0.08367737 0.08291464 0.07608845 0.06423188 0.04573648 0.02728300 0.02114430 0.03341575 0.05064814

Now we need to apply a “RANK” of 1 through 9 (because there are 9 symbols).

#ranked in order such that the symbol with the lowest volatility is given a rank of 1
r <- as.xts(t(apply(rank.factors, 1, rank)))
Here is what the r object looks like with each symbol being ranked by volatility
> tail(r)
           XLB.RANK XLE.RANK XLF.RANK XLI.RANK XLK.RANK XLP.RANK XLU.RANK XLV.RANK XLY.RANK
2011-11-30        8        9        7        6        4        2        1        3        5
2011-12-31        8        9        7        6        4        2        1        3        5
2012-01-31        9        8        7        6        4        2        1        3        5
2012-02-29        9        8        7        6        4        2        1        3        5
2012-03-31        9        8        7        6        4        2        1        3        5
2012-04-30        9        8        7        6        4        2        1        3        5
#Set the symbol's market data back to its original structure so we don't have 2 columns named "RANK"
for (symbol in symbols){
  x <- get(symbol)
  x <- x[,1:6]
  assign(symbol,x)
}
#Bind the symbol's rank to the symbol's market data
XLB <- cbind(XLB,r$XLB.RANK)
XLE <- cbind(XLE,r$XLE.RANK)
XLF <- cbind(XLF,r$XLF.RANK)
XLI <- cbind(XLI,r$XLI.RANK)
XLK <- cbind(XLK,r$XLK.RANK)
XLP <- cbind(XLP,r$XLP.RANK)
XLU <- cbind(XLU,r$XLU.RANK)
XLV <- cbind(XLV,r$XLV.RANK)
XLY <- cbind(XLY,r$XLY.RANK)

Now we can see that each symbol has an extra “RANK” column

> tail(XLB)
           XLB.Open XLB.High XLB.Low XLB.Close XLB.Volume XLB.Adjusted XLB.RANK
2011-11-30    33.10    35.73   31.41     34.52  290486300        34.15        8
2011-12-31    34.34    35.01   31.86     33.50  233453200        33.37        8
2012-01-31    34.24    37.73   34.23     37.18  171601400        37.04        9
2012-02-29    37.48    37.97   36.40     36.97  179524000        36.83        9
2012-03-31    37.19    37.65   35.80     36.97  201651000        36.97        9
2012-04-30    36.92    37.63   35.10     36.56   99089100        36.56        9

Now that the market data is “prepared”, we can easily implement the strategy using quantstrat. Note that the signal is when the “RANK” column is less than 3. This means that the strategy buys the 3 instruments with the lowest volatility. See end of post for quantstrat code.

#Market data is prepared with each symbols rank based on the factors chosen
#Now use quantstrat to execute the strategy

#Set Initial Values
initDate='1900-01-01' #initDate must be before the first date in the market data
initEq=100000 #initial equity

#Name the portfolio
portfolio.st='RSRANK'

#Name the account
account.st='RSRANK'

#Initialization
initPortf(portfolio.st, symbols=symbols, initPosQty=0, initDate=initDate, currency = "USD")
initAcct(account.st,portfolios=portfolio.st, initDate=initDate, initEq=initEq)
initOrders(portfolio=portfolio.st,initDate=initDate)

#Initialize strategy object
stratRSRANK <- strategy(portfolio.st)

# There are two signals:
# The first is when Rank is less than or equal to N (i.e. trades the #1 ranked symbol if N=1)
stratRSRANK <- add.signal(strategy = stratRSRANK, name="sigThreshold",arguments = list(threshold=3, column="RANK",relationship="lte", cross=TRUE),label="Rank.lte.N")
# The second is when Rank is greater than N
stratRSRANK <- add.signal(strategy = stratRSRANK, name="sigThreshold",arguments = list(threshold=3, column="RANK",relationship="gt",cross=TRUE),label="Rank.gt.N")

# There is one rule:
# The first is to buy when the Rank crosses above the threshold
stratRSRANK <- add.rule(strategy = stratRSRANK, name='ruleSignal', arguments = list(sigcol="Rank.lte.N", sigval=TRUE, orderqty=1000, ordertype='market', orderside='long', pricemethod='market', replace=FALSE), type='enter', path.dep=TRUE)

#Exit when the symbol Rank falls below the threshold
stratRSRANK <- add.rule(strategy = stratRSRANK, name='ruleSignal', arguments = list(sigcol="Rank.gt.N", sigval=TRUE, orderqty='all', ordertype='market', orderside='long', pricemethod='market', replace=FALSE), type='exit', path.dep=TRUE)

#Apply the strategy to the portfolio
start_t<-Sys.time()
out<-try(applyStrategy(strategy=stratRSRANK , portfolios=portfolio.st))
end_t<-Sys.time()
print(end_t-start_t)

#Update Portfolio
start_t<-Sys.time()
updatePortf(Portfolio=portfolio.st,Dates=paste('::',as.Date(Sys.time()),sep=''))
end_t<-Sys.time()
print("trade blotter portfolio update:")
print(end_t-start_t)

#Update Account
updateAcct(account.st)

#Update Ending Equity
updateEndEq(account.st)

#get ending equity
getEndEq(account.st, Sys.Date()) + initEq

#View order book to confirm trades
getOrderBook(portfolio.st)

tstats <- tradeStats(Portfolio=portfolio.st, Symbol=symbols)

chart.Posn(Portfolio=portfolio.st,Symbol="XLF")

#Trade Statistics for CAGR, Max DD, and MAR
#calculate total equity curve performance Statistics
ec <- tail(cumsum(getPortfolio(portfolio.st)$summary$Net.Trading.PL),-1)
ec$initEq <- initEq
ec$totalEq <- ec$Net.Trading.PL + ec$initEq
ec$maxDD <- ec$totalEq/cummax(ec$totalEq)-1
ec$logret <- ROC(ec$totalEq, n=1, type="continuous")
ec$logret[is.na(ec$logret)] <- 0

Strat.Wealth.Index <- exp(cumsum(ec$logret)) #growth of $1
write.zoo(Strat.Wealth.Index, file = "E:\\a.csv")

period.count <- NROW(ec)
year.count <- period.count/12
maxDD <- min(ec$maxDD)*100
totret <- as.numeric(last(ec$totalEq))/as.numeric(first(ec$totalEq))
CAGR <- (totret^(1/year.count)-1)*100
MAR <- CAGR/abs(maxDD)

Perf.Stats <- c(CAGR, maxDD, MAR)
names(Perf.Stats) <- c("CAGR", "maxDD", "MAR")
#tstats
Perf.Stats

#Benchmark against a buy and hold strategy with SPY
require(PerformanceAnalytics)
getSymbols("SPY", src='yahoo', index.class=c("POSIXt","POSIXct"), from='2001-01-01')
SPY <- to.monthly(SPY,indexAt='lastof',drop.time=TRUE)

SPY.ret <- Return.calculate(Ad(SPY), method="compound")
SPY.ret[is.na(SPY.ret)] <- 0
SPY.wi <- exp(cumsum(SPY.ret))

write.zoo(SPY.wi, file = "E:\\a1.csv")

Created by Pretty R at inside-R.org

Disclaimer: Past results do not guarantee future returns. Information on this website is for informational purposes only and does not offer advice to buy or sell any securities.