RPackage QuantMod
RPackage 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:
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.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
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)
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.
buy at open
sell at close
trading size: all in
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))
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
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
Exercise
Test the following strategy based on EMA and RSI
9 Trading Size
Wealth: 1 million
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)
Note that we need to keep track of both cash and stock holdings.
qty <-300
day <-14
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
Trading Rule