Dear quantstrat developers and users,

how would you go about designing a rotational trading strategy in 
quantstrat?
For example, hold top three instruments from selected universe ranked 
according to highest momentum (or any other arbitrary indicator) and 
reshuffle monthly as they exchange ranks.

My initial attempt is coded below, taking 'faber' demo as a starting 
point.

Not perfectly rotational, it works as follows:
1. buy 100 shares of the instrument from the universe of nine ETFs that 
has at least 3rd highest momentum among the nine. 
2. sell all of the holding if the instrument ranks lowest 3 inside the 
universe in terms of momentum.
(code can of course be polished, for example nevermind for now the 100 
share pyramiding each time the instrument crosses Top 3 threshold)

Main problem: applyStrategy wrapper
My main concern is how would you wrap the thing inside the applyStrategy. 
As you can see, my far-from-ideal design resorts to external loop over 
symbols. 
I tried passing symbol = quote(symbol) as an argument to add.signal, but 
this throws error from within sigRank (argument 'signal' is missing)

Note that for this particular design to work, I need to pass symbol 
argument explicitly:     applySignals(..............., symbol=symbol)
There is a loop over symbols built inside applyStrategy itself, but it 
unfortunately doesn't pass the symbol as an argument further down to the 
applySignals for the sigRank to utilize.

Another inefficiency in my code is the passing around of huge object 
called 'rankingdata' for each symbol when performing merge with mktdata. 
This can be a performance problem in a universe of 500 instruments. 
Perhaps better solution?

If you happen to have elegant design , rotational trading strategy can be 
a wonderful addition to demos. 
Rank-based strategies then naturally lead to screen-based strategies. I am 
wondering if quantstrat can be used as a versatile screen-based 
backtester. Commercial stock-picking backtesters such as Factset cost tens 
of thousands of dollars.

Gratefully,
Daniel Krizian
_________________________________________________________________________
require(quantstrat)

suppressWarnings(rm("account.faber","portfolio.faber",pos=.blotter))
# suppressWarnings(rm("ltaccount", "ltportfolio", "ClosePrice", 
"CurrentDate", "equity", 
#                     "GSPC", "stratFaber", "initDate", "initEq", "Posn", 
"UnitSize", "verbose"))
suppressWarnings(rm("order_book.faber",pos=.strategy))

# options(device = "windows")
currency('USD')
symbols = c("XLF", "XLP", "XLE", "XLY", "XLV", "XLI", "XLB", "XLK", "XLU")
for(symbol in symbols){ stock(symbol, currency="USD",multiplier=1) }
getSymbols(symbols, src='yahoo', 
index.class=c("POSIXt","POSIXct"),from='2004-01-25')

for(symbol in symbols) {
x<-get(symbol)
x<-to.monthly(x,indexAt='lastof',drop.time=TRUE)
colnames(x)<-gsub("x",symbol,colnames(x))
assign(symbol,x)
}

initPortf('faber', symbols=symbols, initDate='2005-12-31')
initAcct('faber', portfolios='faber', initDate='2005-12-31')
initOrders(portfolio='faber', initDate='2005-12-31')

# prepare price data to a common frame for ranking
rankingdata <- Cl( cbind( XLF, XLP, XLE, XLY, XLV, XLI , XLB , XLK , XLU) 
)
colnames(rankingdata) <- symbols

# indicator function to take x and align it with mktdata for future merge 
within applyIndicators
indMerge <- function(mktdata=quote(mktdata),x){
  if (!is.xts(x)) x <- getSymbols(x, auto.assign = FALSE)
  x <- cbind(mktdata, x[paste(first(index(mktdata)) , last(index(mktdata)) 
, sep='/')], fill = na.locf, retside=c(FALSE,TRUE))
  x
}

# new indicator function to rank symbols according to an indicator
Rank <- function( x , percentile = FALSE ) 
{
  if (percentile) 
    as.xts(t( apply( x , 1, function(r) {
      r <- as.numeric(r)
      if(all(is.na(r))) rep(NA,length(r)) else ecdf(r)(r)
    })))
  else
    as.xts(rollapply( x , 1, rank , na.last = 'keep', ties.method="min" , 
by.column=FALSE))
}

# new signal function to create signals based on rank
sigRank <- function (label, data = mktdata, symbol, indicator, 
threshold=3, relationship = c("gt","lt", "eq", "gte", "lte"), cross=TRUE)
{
  column = paste(indicator,symbol, sep = '.')
  ret_sig <- sigThreshold (label=label, data = data, column,  threshold = 
threshold, relationship = relationship[1], cross = cross)
  colnames(ret_sig) <- label
  return(ret_sig)
}

s <- strategy("faber")
s <- add.indicator (strategy = s, name="indMerge", 
                    arguments = list( mktdata=quote(mktdata),
                                      x=quote( Rank( ROC( rankingdata , n= 
1 , type="discrete" ), percentile=FALSE ) ) ), 
                    label= "momentum")
s <- add.signal(s, name="sigRank", arguments = list(data=quote(mktdata), 
                                                    indicator = 
'momentum',
                                                    relationship="lte",
                                                    threshold=3,
                                                    cross=TRUE), 
label="Lowest3.Rank")
s <- add.signal(s, name="sigRank", arguments = list(data=quote(mktdata), 
                                                    indicator = 
'momentum',
                                                    relationship="gte",
                                                    threshold=7,
 cross=TRUE),label="Highest3.Rank")
s <- add.rule(s, name='ruleSignal', arguments = list(data=quote(mktdata),
 sigcol="Highest3.Rank", 
                                                     sigval=TRUE, 
                                                     orderqty=100, 
                                                     ordertype='market'), 
type='enter')
s <-add.rule(s, name='ruleSignal', arguments = list(data=quote(mktdata),
                                                    sigcol="Lowest3.Rank", 

                                                    sigval=TRUE, 
                                                    orderqty='all', 
                                                    ordertype='market'), 
type='exit')

for (symbol in symbols) {
  ret_signals <- applySignals(strategy=s, mktdata= 
applyIndicators(strategy=s, mktdata=get(symbol)), symbol=symbol)
  applyRules(portfolio='faber', symbol=symbol, strategy=s, 
mktdata=ret_signals, path.dep=TRUE)
}



____________________________________________________________________
Informacie obsiahnute v tomto  dokumente su urcene vylucne pre
potreby jeho adresata. Dokument moze obsahovat informacie chranene
ako bankove alebo obchodne tajomstvo, pripadne informacie
podliehajuce ochrane podla inych pravnych predpisov. Preto Vas v
pripade, ak Vam bol  mylne doruceny, vyzyvame, aby ste sa zdrzali
jeho odtajnenia ci jeho pouzitia pre vlastne potreby. Zaroven si Vas
dovolujeme poziadat, aby ste nas o takomto pripade bez zbytocneho
odkladu informovali a dokument nasledne zlikvidovali.

Information stated in this document is intended only for needs of proper
addressees of this document. This document can contain information
protected as a bank or business secret, or information protected by 
other legal regulations. Thus in case of receiving the document by error,  
we kindly ask you not to disclose, or use the document for your own 
needs. Likewise we kindly ask you to notify us immediately upon such 
a case by sending an email message to the sender's address, and 
subsequently delete the document.

Tatra banka, a.s.
http://www.tatrabanka.sk
Hodzovo namestie 3,  811 06 Bratislava 1 
ICO: 00 686 930
Zapisana v obchodnom registri Okresneho sudu Bratislava I
Oddiel: Sa, vlozka cislo: 71/B
	[[alternative HTML version deleted]]

