0% found this document useful (0 votes)
14 views

RPackage QuantMod

The quantmod package allows users to download stock price data, create charts of stock prices and technical indicators, and construct simple trading strategies to evaluate performance. It downloads data from Yahoo Finance by default and allows charting of prices as lines, bars, and candlesticks along with adding common technical indicators to the charts.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views

RPackage QuantMod

The quantmod package allows users to download stock price data, create charts of stock prices and technical indicators, and construct simple trading strategies to evaluate performance. It downloads data from Yahoo Finance by default and allows charting of prices as lines, bars, and candlesticks along with adding common technical indicators to the charts.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 46

Package: Quantmod

Quantmod stands for quantitative financial modelling framework’’. It has three main
functions:

1. download data,
2. charting, and
3. technical indicator.

Then we can conduct simple test on trading strategies. We will learn how to test more
complicated strategies.

Before we start, let us use the following code install and load quantmod.
library(quantmod)
install.packages("quantmod")
library(quantmod)
Learning Objectives:

 Use quantmod package to download stock prices

 create chart of stock prices and add technical indicators

 construct simple trading indicator and apply it into trading

 evaluate the performance of a trading rule based on return data

1 Downloading data
Use getSymbols to get data from yahoo or Google (default is yahoo)
getSymbols("AAPL")
Let see what is inside the data.
head(AAPL)
## AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume
## 2019-03-05 175.94 176.00 174.54 175.53 19737400
## 2019-03-06 174.67 175.49 173.94 174.52 20810400
## 2019-03-07 173.87 174.44 172.02 172.50 24760900
## 2019-03-08 170.32 173.07 169.50 172.91 23999400
## 2019-03-11 175.49 179.12 175.35 178.90 32011000
## 2019-03-12 180.00 182.67 179.37 180.91 32467600
## AAPL.Adjusted
## 2019-03-05 175.53
## 2019-03-06 174.52
## 2019-03-07 172.50
## 2019-03-08 172.91
## 2019-03-11 178.90
## 2019-03-12 180.91
To extract columns, we use Op, Hi, Lo, Cl, Vo and Ad
Open <- Op(AAPL) #Open Price
High <- Hi(AAPL) # High price
Low <- Lo(AAPL) # Low price
Close<- Cl(AAPL) #Close Price
Volume <- Vo(AAPL) #Volume
AdjClose <- Ad(AAPL) # Adjusted close
If you wish to only import at a certain date e.g.,. 2000-01-01 to 2015-09-25, we can restrict
the set the data to download.
getSymbols("AAPL", from='2000-01-01',to='2015-09-25')
## [1] "AAPL"
Alternatively, we can load the whole series and restrict using xts function last()
getSymbols("AAPL")
## [1] "AAPL"
AAPL <- last(AAPL,'1 year')
head(AAPL)
## AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume
## 2019-01-02 154.89 158.85 154.23 157.92 37039700
## 2019-01-03 143.98 145.72 142.00 142.19 91244100
## 2019-01-04 144.53 148.55 143.80 148.26 58607100
## 2019-01-07 148.70 148.83 145.90 147.93 54777800
## 2019-01-08 149.56 151.82 148.52 150.75 41025300
## 2019-01-09 151.29 154.53 149.63 153.31 45099100
## AAPL.Adjusted
## 2019-01-02 157.2456
## 2019-01-03 141.5828
## 2019-01-04 147.6268
## 2019-01-07 147.2983
## 2019-01-08 150.1062
## 2019-01-09 152.6553
Alternatively, we can take the first 3 years by using first():
getSymbols("AAPL")
## [1] "AAPL"
AAPL <- first(AAPL,'3 years')
head(AAPL)
## AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume
## 2007-01-03 12.32714 12.36857 11.70000 11.97143 309579900
## 2007-01-04 12.00714 12.27857 11.97429 12.23714 211815100
## 2007-01-05 12.25286 12.31428 12.05714 12.15000 208685400
## 2007-01-08 12.28000 12.36143 12.18286 12.21000 199276700
## 2007-01-09 12.35000 13.28286 12.16429 13.22429 837324600
## 2007-01-10 13.53571 13.97143 13.35000 13.85714 738220000
## AAPL.Adjusted
## 2007-01-03 7.982585
## 2007-01-04 8.159763
## 2007-01-05 8.101658
## 2007-01-08 8.141665
## 2007-01-09 8.817995
## 2007-01-10 9.239983
We can also import three stocks at the same time by using a vector.
getSymbols(c("AAPL","GOOG"))
## [1] "AAPL" "GOOG"
Alternatively, we can assign a vector of stocks and import based on the vector.
stocklist <- c("AAPL","GOOG")
getSymbols(stocklist)
The package can also import non-US stocks.
getSymbols("0941.hk")
#If error, try instead the following:
#getSymbols("0941.HK",src="yahoo", auto.assign=FALSE)
head(`0941.HK`)
## 0941.HK.Open 0941.HK.High 0941.HK.Low 0941.HK.Close
## 2007-01-02 67.25 70.00 67.10 69.6
## 2007-01-03 69.90 71.80 69.50 70.7
## 2007-01-04 70.60 70.95 67.30 68.2
## 2007-01-05 67.50 69.50 66.30 69.5
## 2007-01-08 67.50 68.40 67.45 67.7
## 2007-01-09 68.00 68.60 65.55 66.3
## 0941.HK.Volume 0941.HK.Adjusted
## 2007-01-02 35293388 46.17351
## 2007-01-03 41163203 46.90325
## 2007-01-04 37286533 45.24471
## 2007-01-05 24502496 46.10715
## 2007-01-08 15584163 44.91301
## 2007-01-09 17861491 43.98424
Besides prices, very often we are interested in the trading volume. Moreover, we would like to
find volume over time: weekly, monthly, quarterly and yearly. We can use apply and sum to
calculate the rolling sum of volume to each distinct period.
WeekVoYa<- apply.weekly(Vo(AAPL),sum)
# sum from Monday to Friday
MonthVoYa <- apply.monthly(Vo(AAPL),sum)
# sum to month
QuarterVoYa <- apply.quarterly(Vo(AAPL),sum)
# sum to quarter
YearVoYa <- apply.yearly(Vo(AAPL),sum)
# sum to year
In some case, we are interested in average than the sum. Then we can use apply and mean.
WeekAveVoClYa<- apply.weekly(Vo(AAPL),mean)
# weekly average volume

2 Charting
Quantmod draw nice charts of following common types:

1. line
2. bars
3. candlesticks
We can use chartSeries() and specify the types directly.

The line chart displays stock price of AAPL in 2007 by using the subset option. The
option theme is set to be chartTheme(‘white’) as the default option chartTheme(‘black’) is
not printer-friendly.
chartSeries(AAPL,
type="line",
subset='2007',
theme=chartTheme('white'))

The bar chart displays stock price of AAPL in May to June 2007 by using the subset option.
chartSeries(AAPL,
type="bar",
subset='2007-05::2007-06',
theme=chartTheme('white'))
The following candle stick chart displays stock price of AAPL in May only.
chartSeries(AAPL,
type="candlesticks",
subset='2007-05',
theme=chartTheme('white'))
Finally The following candle stick chart displays stock price of AAPL a few days in May.
chartSeries(AAPL,
type="auto",
subset='2007-05-10::2007-05-30',
theme=chartTheme('white'))
3 Technical Indicators
Technical trading rule (TTR) package is loaded when we load quantmod package.

If you want to use it separately, then just load the package as usual:
install.packages("TTR")
library(TTR)

3.1 Simple Moving Average


sma <-SMA(Cl(AAPL),n=20)
tail(sma,n=5)
## SMA
## 2019-04-09 190.7990
## 2019-04-10 191.7445
## 2019-04-11 192.5055
## 2019-04-12 193.1430
## 2019-04-15 193.7035
3.2 Exponential moving average
ema <-EMA(Cl(AAPL),n=20)
tail(ema,n=5)
## EMA
## 2019-04-09 190.5737
## 2019-04-10 191.5305
## 2019-04-11 192.2371
## 2019-04-12 192.8688
## 2019-04-15 193.4747

3.3 Bollinger band


bb <-BBands(Cl(AAPL),s.d=2)
tail(bb,n=5)
## dn mavg up pctB
## 2019-04-09 180.8742 190.7990 200.7238 0.9383450
## 2019-04-10 181.8604 191.7445 201.6286 0.9489799
## 2019-04-11 182.8662 192.5055 202.1448 0.8342832
## 2019-04-12 183.5912 193.1430 202.6948 0.7997868
## 2019-04-15 184.1045 193.7035 203.3025 0.7878678

3.4 Momentum
We calculate 2-day momentum based on closing price of AAPL.
M <- momentum(Cl(AAPL), n=2)
head (M,n=5)
## AAPL.Close
## 2007-01-03 NA
## 2007-01-04 NA
## 2007-01-05 0.178571
## 2007-01-08 -0.027143
## 2007-01-09 1.074286

3.5 ROC
ROC <- ROC(Cl(AAPL),n=2)
# 2-day ROC
head(ROC,n=5)
## AAPL.Close
## 2007-01-03 NA
## 2007-01-04 NA
## 2007-01-05 0.014806276
## 2007-01-08 -0.002220547
## 2007-01-09 0.084725818

6 MACD
macd <- MACD(Cl(AAPL), nFast=12, nSlow=26,
nSig=9, maType=SMA)
tail(macd,n=5)
## macd signal
## 2019-04-09 2.993448 3.539602
## 2019-04-10 2.991384 3.441817
## 2019-04-11 3.015484 3.350873
## 2019-04-12 2.921857 3.255855
## 2019-04-15 2.835048 3.159183

3.7 RSI
rsi = RSI(Cl(AAPL), n=14)
tail(rsi,n=5)
## rsi
## 2019-04-09 74.58639
## 2019-04-10 75.74467
## 2019-04-11 70.57922
## 2019-04-12 70.33177
## 2019-04-15 70.82741

4 Charting with Indicators


4.1 Charting SMA
We use the function addSMA() to put
chartSeries(AAPL,
subset='2007-05::2009-01',
theme=chartTheme('white'))
addSMA(n=30,on=1,col = "blue")
addSMA(n=200,on=1,col = "red")
4.2 Charting EMA
chartSeries(AAPL,
subset='2007-05::2009-01',
theme=chartTheme('white'))
addEMA(n=30,on=1,col = "blue")
addEMA(n=200,on=1,col = "red")
4.3 Charting Bollinger band
chartSeries(AAPL,
subset='2007-05::2009-01',
theme=chartTheme('white'))
addBBands(n=20,sd=2)
4.4 Charting Momentum
chartSeries(AAPL,
subset='2007-05::2009-01',
theme=chartTheme('white'))
addMomentum(n=1)
4.5 Charting ROC
chartSeries(AAPL,
subset='2007-05::2008-01',
theme=chartTheme('white'))
addROC(n=7)
4.6 Charting MACD
chartSeries(AAPL,
subset='2007-05::2008-01',
theme=chartTheme('white'))
addMACD(fast=12,slow=26,signal=9,type="EMA")
4.7 Charting RSI
chartSeries(AAPL,
subset='2007-05::2009-01',
theme=chartTheme('white'))
addRSI(n=14,maType="EMA")
4.8 Charting Custom TA
sma <- SMA(Cl(AAPL),n=14)
chartSeries(AAPL,
subset='2007-05::2009-01',
theme=chartTheme('white'))
addTA(sma, on=1, col="red")
5 Charting Price changes of two stocks
To compare prices fo different stocks, we need to calculat the price change:
NS <- function(xdat) xdat / coredata(xdat)[1]
a <- NS(Cl(AAPL))-1
g <- NS(Cl(GOOG))-1
m <- NS(Cl(MSFT))-1
chartSeries(a,
subset = '2007',
theme=chartTheme('white'))
addTA(g, on=1, col="red", lty="dotted")
addTA(m, on=1, col="blue", lty="dashed")
The option lty is to make the line becomes other line styles where dotted means dotted line
and dashed means dashed line.

6 Performance Evaluation
The package is a collection of econometric functions for performance and risk analysis.
We first install and load PerformanceAnalytics package.
install.packages("PerformanceAnalytics")
library(PerformanceAnalytics)

7 Evaluating Trading Rules


To simplify, we first evaluate several trading rules based on day trading:

1. buy signal based on simple filter rule


2. buy and sell signals based on simple filter rule
3. buy signal based on RSI
4. buy signal based on EMA and sell signal based on RSI
5. buy signal based on RSI but trading size depends on price history
Finally, we consider the rule that does non-day trading. In this case, we need to keep track of both cash and
stock holdings.

7.1 Simple filter Buy


Here we create trading signal based on simple filter rule. Recall that simple filter rule suggests buying
when the price increases a lot compared to the yesterday price:

Buy:PtPt−1>1+δ
where Pt is the closing price at time t and δ>0is an arbitrary threshold
We illustrate using Microsoft with ticker MSFT.

We first download the data using getSymbols(“MSFT”).


library(quantmod)
getSymbols("MSFT")
## [1] "MSFT"
We first will use closing price to perform calculation. We calculate the percentage price change by
dividing the current close price by its own lag and then minus 1.

Now we generate buying signal based on filter rule:


price <- Cl(MSFT) # close price
r <- price/Lag(price) - 1 # % price change
delta <-0.005 #threshold
signal <-c(0) # first date has no signal

#Loop over all trading days (except the first)


for (i in 2: length(price)){
if (r[i] > delta){
signal[i]<- 1
} else
signal[i]<- 0
}
Note that signal is just a vector without time stamp. We use the function reclass to convert it into
an xts object.
# Each data is not attached with time
head(signal, n=3)
## [1] 0 0 0
# Assign time to action variable using reclass;
signal<-reclass(signal,price)

# Each point is now attached with time


tail(signal, n=3)
## [,1]
## 2019-04-11 0
## 2019-04-12 1
## 2019-04-15 0
We are now ready to chart the trading indicators:
# Charting with Trading rule
chartSeries(MSFT,
type = 'line',
subset="2009-08::2009-09-15",
theme=chartTheme('white'))
addTA(signal,type='S',col='red')
We consider trading based on yesterday indicator:
trade <- Lag(signal,1) # trade based on yesterday signal
To keep it simple, we evaluate using day trading:

 buy at open
 sell at close
 trading size: all in

Then daily profit rate is dailyReturn=Close−Openopen


ret<-dailyReturn(MSFT)*trade
names(ret)<-"filter"
Based on daily return, we can see the summary of performance using charts.PerformanceSummary() to
evaluate the performance.
#Performance Summary
charts.PerformanceSummary(ret, main="Naive Buy Rule")
7.2 Simple fiter buy-sell
Here we create trading signal based on simple filter rule. Recall that simple filter rule suggests buying
when the price increases a lot compared to the yesterday price and selling when price decreases a lot:

Buy:PtPt−1>1+δ
Sell:PtPt−1<1−δ
where Pt is the closing price at time t and δ>0 is an arbitrary threshold
We first download the data:
library(quantmod)
getSymbols("MSFT")
## [1] "MSFT"
price <- Cl(MSFT)
r <- price/Lag(price) - 1
delta<-0.005
signal <-c(NA) # first signal is NA

for (i in 2: length(Cl(MSFT))){
if (r[i] > delta){
signal[i]<- 1
} else if (r[i]< -delta){
signal[i]<- -1
} else
signal[i]<- 0
}
signal<-reclass(signal,Cl(MSFT))

trade1 <- Lag(signal)


ret1<-dailyReturn(MSFT)*trade1
names(ret1) <- 'Naive'
charts.PerformanceSummary(ret1)

Exercise
Test the following strategy based on EMA: - Buy/Sell signal based on EMA rule. - Day trading based on
yesterday signal: - buy at open and - sell at close on the same day

7.7.3 An example using RSI


Consider following day-trading strategy based on 14-day RSI:

 buy one unit if RSI <30 and


 otherwise no trade.

Evaluate this based on day trading and compare it with simple filter rule:
day <-14
price <- Cl(MSFT)
signal <- c() #initialize vector
rsi <- RSI(price, day) #rsi is the lag of RSI
signal [1:day+1] <- 0 #0 because no signal until day+1

for (i in (day+1): length(price)){


if (rsi[i] < 30){ #buy if rsi < 30
signal[i] <- 1
}else { #no trade all if rsi > 30
signal[i] <- 0
}
}
signal<-reclass(signal,Cl(MSFT))
trade2 <- Lag(signal)

#construct a new variable ret1


ret1 <- dailyReturn(MSFT)*trade1
names(ret1) <- 'Naive'
# construct a new variable ret2
ret2 <- dailyReturn(MSFT)*trade2
names(ret2) <- 'RSI'
Now compare strategies with the filter rule:
retall <- cbind(ret1, ret2)
charts.PerformanceSummary(retall,
main="Naive v.s. RSI")
7.4 More efficient code
In the RSI code above, we have written that:
signal [1:day+1] <- 0

for (i in (day+1): length(price)){


if (rsi[i] < 30){
signal[i] <- 1
}else {
signal[i] <- 0
}
}
A more efficient but less readable code is to avoid counting:
for (i in 1:length(price)){
signal[i] <- 0
if (isTRUE(rsi[i] < 30)){
signal[i] <- 1
}
}

8 Combining two indicators: EMA and RSI


Test the following strategy using EMA and RSI based on day trading:

 Buy signal based on EMA rule.


 Sell signal based on RSI rule.
 Tie-breaking: buy-signal has priority
 We use 14-day RSI and use 70 as threshold for selling.
n <- 14
delta<-0.005
price <- Cl(MSFT)
r <- price/Lag(price) - 1
rsi <- RSI(price, n)
signal <-c() # first signal is NA
signal[1:n] <-0

# Generate Trading Signal


for (i in (n+1):length(price)){
if (r[i] > delta){
signal[i]<- 1
} else if (rsi[i] > 70){
signal[i]<- -1
} else
signal[i]<- 0
}
signal<-reclass(signal,price)

## Apply Trading Rule


trade3 <- Lag(signal)
ret3<-dailyReturn(MSFT)*trade3
names(ret3) <- 'Combine'
retall <- cbind(ret1, ret2, ret3)
To draw trade performance summary with different colors, we use the option colorset.
Common options includes redfocus, bluefocus, greenfocus, rainbow4equal andrich12equal.
charts.PerformanceSummary(
retall, main="Naive v.s. RSI v.s. Combine",
colorset=bluefocus)

Exercise
Test the following strategy based on EMA and RSI

 Buy signal based on EMA rule.


 Sell signal based on RSI rule
 Day trading based on yesterday signal: buy at open and sell at close

9 Trading Size
Wealth: 1 million

Trade unit: 1000 stocks per trade


Test the following strategy based on 14-day RSI :

 Buy one more unit if RSI <30.


 Keep buying the same if 30 < RSI < 50
 Stop trading if RSI >= 50

Evaluate based on day trading

To take trade size into account, we need to keep track of wealth:


qty <-1000
day <-14

signal <- c() #trade signal with size


signal[1:(day+1)] <- 0

price <- Cl(MSFT)

wealth <-c()
wealth[1:(day+1)] <- 1000000

return<-c()
return[1:(day+1)] <- 0

profit <-c()
profit[1:(day+1)] <- 0
We now generate trading signal with size:
rsi <- RSI(price, day) #rsi is the lag of RSI
for (i in (day+1): length(price)){
if (rsi[i] < 30){ #buy one more unit if rsi < 30
signal[i] <- signal[i-1]+1
} else if (rsi[i] < 50){ #no change if rsi < 50
signal[i] <- signal[i-1]
} else { #sell if rsi > 50
signal[i] <- 0
}
}
signal<-reclass(signal,price)
Now we are ready to apply Trade Rule
Close <- Cl(MSFT)
Open <- Op(MSFT)
trade <- Lag(signal)
for (i in (day+1):length(price)){
profit[i] <- qty * trade[i] * (Close[i] - Open[i])
wealth[i] <- wealth[i-1] + profit[i]
return[i] <- (wealth[i] / wealth[i-1]) -1
}
ret3<-reclass(return,price)

charts.PerformanceSummary(ret3, main="Trade Size")


10 Non-Day Trading
Trading signal:

 Buy signal arises if 14-day RSI < 30


 Sell signal arises if 14-day RSI > 50
Trading Rule

 Buy 300 units under buy signal


 Sell all when sell signal appears

Initial wealth: 10,000

Note that we need to keep track of both cash and stock holdings.
qty <-300
day <-14

signal <- c() #trade signal


signal[1:(day+1)] <- 0

price <- Cl(MSFT)


stock <- c() #stock holding
stock[1:(day+1)] <-0

cash <-c()
cash[1:(day+1)] <- 10000
Trading signal is based on simple RSI:
rsi <- RSI(price, day) #rsi is the lag of RSI
for (i in (day+1): length(price)){
if (rsi[i] < 30){ #buy one more unit if rsi < 30
signal[i] <- 1
} else if (rsi[i] < 50){ #no change if rsi < 50
signal[i] <- 0
} else { #sell if rsi > 50
signal[i] <- -1
}
}
signal<-reclass(signal,price)
Assume buying at closing price. We keep track of how cash and stock changes:
trade <- Lag(signal) #rsi is the lag of RSI
for (i in (day+1): length(price)){
if (trade[i]>=0){
stock[i] <- stock[i-1] + qty*trade[i]
cash[i] <- cash[i-1] -
qty*trade[i]*price[i]
} else{
stock[i] <- 0
cash[i] <- cash[i-1] +
stock[i-1]*price[i]
}
}
stock<-reclass(stock,price)
cash<-reclass(cash,price)
To evaluate performance, we calculate equity using cash and stock holdings.
equity <-c()
equity[1:(day+1)] <- 10000

return<-c()
return[1:(day+1)] <- 0

for (i in (day+1): length(price)){


equity[i] <- stock[i] * price[i] + cash[i]
return[i] <- equity[i]/equity[i-1]-1
}
equity<-reclass(equity,price)
return<-reclass(return,price)
Performance Charts
charts.PerformanceSummary(return,
main="Non-Day-Trading")
We can plot the equity line showing how the performance of the strategy:
chart_Series(equity, main="equity line")
We can check the cash account over time:
chart_Series(cash, name="Cash Holding")
Finall, We can stock holdings:
chart_Series(stock, name="Stock Holding")
Exercise
Trading signal:

 Buy signal arises if RSI < 30


 Sell signal arises if RSI >50

Trading Rule

 Buy 1000 units under buy signal


 Sell 1000 units under sell signal

You might also like