Algotrading with R — Quantstrat

Boniface Yogendran
4 min readMar 19, 2018

--

I wrote about this before thinking that I knew the basics of Quantstrat. That was not true. I was probably at “Mt.Stupid” on Dunning-Kruger curve when I posted it.

Dunning-Kruger

I will keep posting new things as I learn. Now I want to get to the basics of how to do a simple trading strategy using Quantsrtat. Whats quantstrat?

Description:

quantstrat provides a generic infrastructure to model and backtest signal-based quantitative strategies. It is a high-level abstraction layer (built on xts, FinancialInstrument, blotter, etc.) that allows you to build test strategies in very few lines of code.

Shout out to Peter Carl, Brian Peterson and Jeffrey Ryan for creating such an awesome library!

We need the following before we get started on backtesting our strategy:

  1. Data
  2. Instruments/Tools
  3. Strategy

Data

For this exercise we will be using data from Yahoo. However, if you have other dataset, feel free to upload to the workspace. Ensure that the data is xts format. Without data, we will not be able to do any work!

Instruments/Tools

You can install the library using install.packages("quantstrat") , but I highly recommend downloading the raw materials from github for blotter and quanstrat, then compiling the package. This allows me to make minor modifications to the package or track the error message. Instruction can be found here.

Strategy

First we need to pick a strategy. For this exercise we will be using Simple Moving Average (SMA) strategy on SPY. Basically, we enter long when fast moving average is crossover slow moving average. Exit long when slow moving average crossover fast moving average. Trading systems by Emilio Tomasini and Urban Jaekle is a great resource to study this strategy.

Souce: Investopedia

Basic strategy backtesting workflow for quantstrat is provided below:

souce: Guy Yollin — Introduction to Trading Systems

Initialization

The code is located in my Github repo. Lets go line by line to setup the strategy.

###Setup library
library("quantstrat")

blotter, PerformanceAnalytics, TTR, foreach, FinancialInstruments, xts, quantmod, Defaults and zoo will be automatically loaded with quantstrat.

quantstart automatically initiates .strategy and .blotter environments. We will talk about the importance in the upcoming blogs.

#set the currency and the stock we are interested
currency("USD")
stock("SPY",currency="USD",multiplier=1)
Sys.setenv(TZ="UTC") #setting up the timezone

Set parameters

#Set the parameters
initDate <- "2007-01-02" #Date of initiation
from <- "2007-01-03" #Start date of the data set
to <- "2018-03-18" #End date of the data set
initEq <- 1000 #Initial equity

Time to load the data. getSymbol() by default imports data from Yahoo. We can change it if we want (FYI). If we dont add the from and to dates, it will import the data from 2007 to current date.

# read in data ---------------------------------------------------
getSymbols("SPY", from = from, to = to)

Now we initialize strategy, portfolio and account.

#-------------Initiate portfolio and account-----------
strategy.st <- "luxor" #Name the strategy
account.st <- "luxor"
portfolio.st <- "luxor"
#Initiate portfolio
initPortf(qs.strategy, "SPY", initDate = initDate)
#Initiate account
initAcct(qs.strategy, portfolios = qs.strategy, initDate = initDate, initEq = initEq)
#Initiate account
initOrders(portfolio = qs.strategy, initDate = initDate)
#Store all the events in the strategy
strategy(strategy.st, store = TRUE)

Define strategy

Indicators — Calculate fast and slow moving average for the closing price. Call it nFast and nSlow. The argument name in the add.indicator requires the name of the technical trading rule. More of this can be found in the package TTR. The arguments contains all the argument that needs to be supplied to the SMA function. We can use args(SMA) to find this.

### indicatorsadd.indicator(strategy.st, name = "SMA",
arguments = list(
x = quote(Cl(mktdata)[,1]),
n = nfast
),
label="nFast"
)
add.indicator(strategy.st, name="SMA",
arguments = list(
x = quote(Cl(mktdata)[,1]),
n = nslow
),
label="nSlow"
)

Signals — When nFast is greater than nSlow, long = 1. When nFast is lower than nSlow, short = 1. sigComparison, sigFormula, sigThreshold and sigPeakare options available in add.signal. We can also create our own signals if we like (FYI).

add.signal(strategy.st, name='sigCrossover',
arguments = list(
columns=c("nFast","nSlow"),
relationship="gte"
),
label='long'
)
add.signal(strategy.st, name='sigCrossover',
arguments = list(
columns=c("nFast","nSlow"),
relationship="lt"
),
label='short'
)

Rules — When long = 1, enter. When short = 1, exit. args(ruleSignal) will reveal all the value we need to supply to the arguments. Important arguments:

  1. orderside — this defines whether we are trading on the short or long side.
  2. replace — only for exit we set this as TRUE. I still dont understand. My mentor tried to explain, but I still dont understand. So he told me to set this as TRUE only for exit.
### rulesadd.rule(strategy.st, name='ruleSignal',
arguments=list(sigcol='short', sigval=TRUE,
orderside='long' ,
ordertype='market',
orderqty='all',
replace=TRUE
),
type='exit',
label='Exit2SHORT'
)
add.rule(strategy.st, name='ruleSignal',
arguments=list(sigcol='long' , sigval=TRUE,
orderside='long' ,
ordertype='market',
orderqty=orderqty,
replace=FALSE
),
type='enter',
label='EnterLONG'
)

Bar by Bar Processing

applyStrategy(strategy.st, portfolio.st)

Update

Update portfolio, account and equity all at once

#update
updatePortf(strategy.st)
updateAcct(strategy.st)
updateEndEq(strategy.st)

Reporting

This is a subject on its own. We will discuss this later. For now we will go with simple PL and Drawdown chart.

Thats all for now. I will go more in the upcoming blogs!

--

--