Here is an example of a multi-timeframe strategy I'm working on with quantstrat. Is this the correct way of doing a multi-timeframe strategy or am I doing it all wrong? I haven't come across any other examples doing multi-timeframe in the quantstrat demos or from googling.
To keep the strategy part simple (this is not a strategy that someone would trade) and keep the focus on the multi-timeframe aspect, I will demonstrate a simple strategy that uses tick data and 5 minute OHLC data. The strategy logic is to buy when the tick data crosses above the 30-period SMA of the 5-minute data and close the position when the tick data crosses below the same SMA.
For example: if the strategy is flat, the time is 13:02 and the previous observed 30-period SMA of the 5-minute data is 90.55 (for the period of 12:55- ending 13:00), and the tick data crosses from below 90.55 to above it (90.56) it's a buy, and when the tick data closes below it again, it exits the position.
To achieve this, I need to get both the tick data and 5-minute, 30-period SMA into the same object for quantstrat to process. I get the 5-minute OHLC xts and calculate a 30-period SMA of it. Then I merge this into the tick data xts object, which will give me an object with all the tick data and then every 5 mins I will get a row with for the last observed 5-minute, 30-period SMA.
If there is a 30-period SMA value at 13:00, this is for the 5 mins 12:55-13:00. Since the next update to the SMA is 5 minutes later, I need to fill-down the rows until the next value is observed (at 13:05) and so on.
Here's the head
of the tick data (the tick data I have doesn't include milliseconds, but I've made the rows unique using make.index.unique(clemtick)
:
head(clemtick)
Price Volume
2013-01-15 09:00:00 93.90 1
2013-01-15 09:00:00 93.89 1
2013-01-15 09:00:00 93.89 1
2013-01-15 09:00:00 93.88 2
2013-01-15 09:00:00 93.89 1
2013-01-15 09:00:00 93.89 2
Here's the head
of the 1 min data (each minute represents the previous minute of data, e.g. time stamp 09:01:00 == data from 09:00:00 - 09:01:00):
head(clemin)
Open High Low Close Volume
2013-01-15 09:01:00 93.90 94.04 93.87 93.97 1631
2013-01-15 09:02:00 93.97 93.98 93.90 93.91 522
2013-01-15 09:03:00 93.91 93.97 93.90 93.96 248
2013-01-15 09:04:00 93.95 93.98 93.93 93.95 138
2013-01-15 09:05:00 93.95 93.96 93.91 93.92 143
2013-01-15 09:06:00 93.93 93.97 93.91 93.91 729
Convert the 1 minute data to 5 minute data:
cle5min <- to.minutes5(clemin)
clemin.Open clemin.High clemin.Low clemin.Close clemin.Volume
2013-01-15 09:04:00 93.90 94.04 93.87 93.95 2539
2013-01-15 09:09:00 93.95 93.97 93.81 93.89 2356
2013-01-15 09:14:00 93.90 94.05 93.86 93.89 4050
2013-01-15 09:19:00 93.90 94.03 93.84 94.00 2351
2013-01-15 09:24:00 93.99 94.21 93.97 94.18 3261
2013-01-15 09:29:00 94.18 94.26 94.18 94.19 1361
You will notice the first OHLC is 09:04:00, this is due to the way that to.minutes5
function works, which is discussed in this thread. Essentially the first time stamp 09:04:00 == the OHLC 4 minutes of data from 09:00:00 - 09:04:00. the 09:09:00 time stamp is the next full 5 mins from 09:04:00 - 09:09:00. Ideally I would like each time stamp to be 5, 10, 15 etc but I haven't worked out how to do this yet.
To get the 30 SMA of the 5min data into the tick data
clemtick$sma30 <- SMA(cle5min$clemin.Close, 30)
This creates a new column with with the SMA. The SMA needs 30 periods to calculate the first value and the SMA will only appear for every 5 minutes time stamp (11:29:00, 11:34:00, 11:39, ...). It looks like:
clemtick["2013-01-15 11:28:59::2013-01-15 11:29:00"]
Price Volume SMA30
2013-01-15 11:28:59 93.87 1 NA
2013-01-15 11:28:59 93.87 1 NA
2013-01-15 11:28:59 93.88 1 NA
2013-01-15 11:29:00 93.87 1 93.92633
2013-01-15 11:29:00 93.87 1 NA
2013-01-15 11:29:00 93.88 1 NA
2013-01-15 11:29:00 93.88 1 NA
Now I need to fill-down the SMA30
column with a repeating value. The value for SMA30
at 11:29:00 is for the OHLC from 11:24:00 - 11:29:00. The next update of this value won't be until 11:34:00, so I need to fill down the rows until the next value, since this is what the strategy will reference when processing row by row.
clemtick <- na.locf(clemtick)
Now if I query that object again,
clemtick["2013-01-15 11:33:58::2013-01-15 11:34:01"]
Price Volume SMA30
2013-01-15 11:33:58 93.84 1 93.92633
2013-01-15 11:34:00 93.84 1 93.92267
2013-01-15 11:34:00 93.85 1 93.92267
2013-01-15 11:34:01 93.84 1 93.92267
Now that we have the final object here is running the strategy:
require(quantstrat)
options("getSymbols.warning4.0"=FALSE)
rm(list=ls(.blotter), envir=.blotter)
Sys.setenv(TZ="UTC")
symbols <- "clemtick"
currency('USD')
stock(symbols, currency="USD", multiplier=1)
account.st <- 0
strategy.st <- portfolio.st <- account.st <- "multi"
rm.strat(portfolio.st)
rm.strat(strategy.st)
initDate <- "1980-01-01"
tradeSize <- 1000
initEq <- tradeSize*length(symbols)
initPortf(portfolio.st, symbols=symbols, initDate=initDate, currency='USD')
initAcct(account.st, portfolios=portfolio.st,
initDate=initDate, currency='USD', initEq=initEq)
initOrders(portfolio.st, initDate=initDate)
strategy(strategy.st, store=TRUE)
add.signal(strategy.st, name="sigCrossover",
arguments=list(columns=c("Price", "sma30"), relationship="gt"),
label="golong")
add.signal(strategy.st, name="sigCrossover",
arguments=list(columns=c("Price", "sma30"), relationship="lt"),
label="exitlong")
#enter rule
add.rule(strategy.st, name="ruleSignal",
arguments=list(sigcol="golong",
sigval=TRUE,
ordertype="market",
orderside="long",
replace=TRUE,
prefer="Price",
orderqty=1),
type="enter", path.dep=TRUE, label="long")
#exit rule
add.rule(strategy.st, name = "ruleSignal",
arguments=list(sigcol="exitlong",
sigval=TRUE,
ordertype="market",
orderside="long",
replace=TRUE,
prefer="Price",
orderqty=-1),
type="exit", path.dep=TRUE, label="exitlong")
#apply strategy
t1 <- Sys.time()
out2 <- applyStrategy(strategy=strategy.st, portfolios=portfolio.st, debug=TRUE)
t2 <- Sys.time()
print(t2-t1)
head(mktdata)
nrow(mktdata)
So to sum up is the this best way to do multi time frame strategies?