Generating indicators of different periodicity in quantstrat
Asked Answered
C

1

4

I would like to use indicators of timeframes different to the data I am using. I have seen this asked a few time but no solutions as of yet (at least for me anyway).

The below example uses daily stock data however the actual project uses intraday currency data. I have an easy work around for importing the intraday csv data now so the example and real-world should be interchangeable enough.

library(quantstrat)
initDate="2000-01-01"
from="2003-01-01"
to="2016-12-31"

#set account currency and system timezone
currency('USD')
Sys.setenv(TZ="UTC")

#get data
symbols <- "SPY"
getSymbols(symbols, from=from, to=to, src="yahoo", adjust=TRUE)
stock(symbols, "USD")

#trade sizing and initial equity settings
tradeSize <- 100000
initEq <- tradeSize*length(symbols)

#set up the portfolio, account and strategy
strategy.st <- portfolio.st <- account.st <- "mtf.strat"
rm.strat(strategy.st)
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)

#SMA length
nSMA <- 14

Adding the SMA as, in this case a daily indicator works a treat

add.indicator(strategy.st, name="SMA",
              arguments=list(x=quote(Cl(mktdata)), n=nSMA, maType = "SMA"),
              label="SMA")
test <- applyIndicators(strategy.st, mktdata=OHLC(SPY))

Yet trying to add, in this case a weekly SMA

add.indicator(strategy.st, name="SMA",
              arguments=list(x=quote(to.period(Cl(mktdata), period = "weeks", k = 1, indexAt = "startof")), n=nSMA, maType = "SMA"),
              label="SMAw1")
## Or this    
add.indicator(strategy.st, name="SMA",
              arguments=list(x=quote(to.weekly(Cl(mktdata))), n=nSMA, maType = "SMA"),
              label="SMAw1")
test <- applyIndicators(strategy.st, mktdata=OHLC(SPY))
# Error in runSum(x, n) : ncol(x) > 1. runSum only supports univariate 'x'

Calling the Close column directly without Cl(x) results in the same error. I did this as TTR:::runSum will throw the above error if given more than one column of data.

I'm not entirely sure what the problem is so some assistance would be great.

Catto answered 29/11, 2016 at 4:5 Comment(0)
L
2

The problem is that to.period (and therefore to.weekly) return OHLC objects, not a univariate series like TTR::SMA expects. So you need to wrap the output of to.period in Cl.

add.indicator(strategy.st, name="SMA",
              arguments=list(x=quote(Cl(to.weekly(Cl(mktdata)))), n=nSMA, maType = "SMA"),
              label="SMAw1")
test <- applyIndicators(strategy.st, mktdata=OHLC(SPY))

Now that code runs, but it may still be a problem for your strategy. There will be a lot of NA when that indicator is merged with the daily mktdata.

R> tail(merge(SPY, test$SMA))
           SPY.Open SPY.High SPY.Low SPY.Close SPY.Volume SPY.Adjusted SMA.SMAw1
2016-11-25   221.10   221.56  221.01    221.52   37861800       221.52  215.0720
2016-11-28   221.16   221.48  220.36    220.48   70284100       220.48        NA
2016-11-29   220.52   221.44  220.17    220.91   67079400       220.91        NA
2016-11-30   221.63   221.82  220.31    220.38   99783700       220.38        NA
2016-12-01   220.73   220.73  219.15    219.57   77230500       219.57        NA
2016-12-02   219.67   220.25  219.26    219.68   70863400       219.68  215.3207

So it's a good idea to create your own SMA wrapper function to handle all these steps. Then call add.indicator using your wrapper function.

mySMA <- function(x, on = "days", k = 1, n = 10) {
  agg <- x[endpoints(x, on, k)]
  sma <- SMA(agg, n)
  # merge with zero-width xts object w/original index, filling NA
  result <- merge(sma, xts(,index(x)), fill = na.locf)
  return(result)
}
add.indicator(strategy.st, name = "mySMA",
              arguments = list(x = quote(Cl(mktdata)),
                               on = "weeks",
                               n = nSMA),
              label = "SMAw1")
test <- applyIndicators(strategy.st, mktdata = OHLC(SPY))

Now the indicator will have a value for every observation in mktdata when it's merged.

> tail(merge(SPY, test$SMA))
           SPY.Open SPY.High SPY.Low SPY.Close SPY.Volume SPY.Adjusted SMA.SMAw1
2016-11-25   221.10   221.56  221.01    221.52   37861800       221.52  215.0720
2016-11-28   221.16   221.48  220.36    220.48   70284100       220.48  215.0720
2016-11-29   220.52   221.44  220.17    220.91   67079400       220.91  215.0720
2016-11-30   221.63   221.82  220.31    220.38   99783700       220.38  215.0720
2016-12-01   220.73   220.73  219.15    219.57   77230500       219.57  215.0720
2016-12-02   219.67   220.25  219.26    219.68   70863400       219.68  215.3207
Livingston answered 3/12, 2016 at 14:20 Comment(5)
thanks for dropping by. I like your solution, however I wish to use standard foreign exchange periods such as 15 minutes or 4 hours. This is why I was using to.period(). Is there a way to use endpoints() either these periods or would it be easier to modify your solution to use to.period()Catto
mySMA <- function(x, t.period, k, n = 7) { agg = to.period(x, period = t.period, k = k, indexAt = "startof") sma <- SMA(Cl(agg), n) # merge with zero-width xts object w/original index, filling NA result <- merge(sma, xts(,index(x)), fill = na.locf) return(result) } add.indicator(strategy.st, name = "mySMA", arguments = list(x = quote(mktdata), t.period = "hours", n = 7, k = 4), label = "h4SMA")Catto
^^Sorry about the above. I can't nut out how to enter code in comments with proper formatting :/ So I replaced endpoints() with to.period and it works but it's a little messy. As you indicated to.period() & co return an OHLC object meaning that this now has to be dealt with within the wrapper (as Cl(agg)). To try and reduce overhead I now pass the all of x into mySMA and let the wrapper deal with it. Is there a better way? This is the best solution I can come up with as my custom indicator requires HLC and not just C; that and I need to work with non-calander periods as per aboveCatto
@user3180258: to.period uses endpoints internally. If you want a 8-period SMA at 15 minute intervals, use mySMA(x, "minutes", 15, 8), where mySMA is the version I wrote. You cannot block-format code in comments, because comments aren't the place for large blocks of code. :)Livingston
Damn, I got blind sided by the endpoints() documentation and didn't even read your code properly with respect to standard period multiplication (despite how obvious it is now that it's been pointed out). Thank you for your help Joshua. Despite the size of the problem, you have shown me a lot here. Big Ups :)Catto

© 2022 - 2024 — McMap. All rights reserved.