Tuesday, July 5, 2011

A Quantstrat to Build On Part 6

THIS IS NOT INVESTMENT ADVICE.  ACTING ON THIS MAY LOSE LOTS OF MONEY.

In A Quantstrat to Build on Part 5, I promised some performance reporting on quantstrat portfolios, but then in REIT Momentum in Quantstrat, I discovered it is not nearly as easy as I thought.  With some help from experts (please tell me if you would like me to mention you by name), I found a couple of ways to accomplish this crucial component of systems development.  We’ll compare the original simple CUD system with buy and hold but this time using the osFUN option in our entry rule to buy an amount equal to the proceeds from the previous trade.  Minimizing drawdown on the way down allows potentially larger trade quantities on the way back up.

From TimelyPortfolio
From TimelyPortfolio
From TimelyPortfolio
From TimelyPortfolio
From TimelyPortfolio
From TimelyPortfolio

R code (click to download):

#thanks so much to the developers of quantstrat
#99% of this code comes from the demos in the quantstrat package   #in this I use osFun to size orders to ending equity
#for a more appropriate comparison to buy hold   #takes longer than I would like but is acceptable
#another way to accomplish testing and reporting
#is use 1 for orderqty and then generate return series
#with this as signal   #however despite extra time I like to see growth in order size
#with performance
#makes a very valid point for drawdown reduction     require(quantstrat)
require(PerformanceAnalytics)   #now let's define our silly countupdown function
CUD <- function(price,n) {
#CUD takes the n-period sum of 1 (up days) and -1 (down days)
temp <- runSum(ifelse(ROC(price,1,type="discrete") > 0,1,-1),n)
colnames(temp) <- "CUD"
temp
}   BuyHold <- function(price,periodtobuy) {
#just enter true (1) the period specified as buy and hold
#for the remainder
temp <- as.xts(rep(0,NROW(price)),order.by=index(price))
colnames(temp) <- "BuyHold"
temp[periodtobuy,1]<-1
temp
}   osFillErUp <- function (data, timestamp, orderqty, ordertype, orderside, portfolio, symbol, ruletype, ..., orderprice)
{   #get date in usable xts format
datePos <- format(timestamp,"%Y-%m-%d")
#update the portfolio to date of trade rule
updatePortf(Portfolio=portfolio,Symbol=symbol,Dates=paste('::',datePos,sep=''))
portf <- getPortfolio(portfolio)
#get price of symbol for the date of trade rule
price <- getPrice(get(symbol))[datePos]
#get amount generated from the last trade
#best way for me to overcome lack of cumulative p/l for portfolio by symbol
#all this logic is at the account level
trades <- getOrderBook(portfolio)[[portfolio]][[symbol]]
#if first trade, just use order quantity specified
#if not get order quantity equal to
#last trade proceeds divided by price of symbol at trade date
if(NROW(trades)>1) {
trades <- trades[NROW(trades)]
endEq <- as.numeric(trades$Order.Qty) * as.numeric(trades$Order.Price)
# orderqty <- abs(endEq/price)
orderqty <- abs(floor(endEq/price))
}
#return the new orderqty
osFillErUp <- orderqty
}     try(rm("order_book.CUD",pos=.strategy),silent=TRUE)
try(rm("order_book.BuyHold",pos=.strategy),silent=TRUE)
try(rm("account.CUD","portfolio.CUD",pos=.blotter),silent=TRUE)
try(rm("account.BuyHold","portfolio.BuyHold",pos=.blotter),silent=TRUE)
try(rm("port.st","symbols","symbol","stratCUD","initDate","initEq",
'start_t','end_t','num_periods'),silent=TRUE)   #specify this for the rolling periods to use for our signal
num_periods=50   # Initialize a strategy object
stratCUD <- strategy("CUD")   # Add an indicator
stratCUD <- add.indicator(strategy = stratCUD, name = "CUD",
arguments = list(price = quote(Cl(mktdata)),n=num_periods),
label="CUD")   # enter when CUD > 0
stratCUD <- add.signal(strategy = stratCUD, name="sigThreshold",
arguments = list(threshold=0, column="CUD",relationship="gte", cross=TRUE),
label="CUD.gte.0")
# exit when CUD < 0
stratCUD <- add.signal(strategy = stratCUD, name="sigThreshold",
arguments = list(threshold=0, column="CUD",relationship="lt",cross=TRUE),
label="CUD.lt.0")   stratCUD <- add.rule(strategy = stratCUD, name='ruleSignal',
arguments = list(sigcol="CUD.gte.0", sigval=TRUE, orderqty=100, ordertype='market',
orderside='long', pricemethod='market', replace=FALSE, osFUN='osFillErUp'), type='enter', path.dep=TRUE)
stratCUD <- add.rule(strategy = stratCUD, name='ruleSignal',
arguments = list(sigcol="CUD.lt.0", sigval=TRUE, orderqty='all',
ordertype='market', orderside='long', pricemethod='market', replace=FALSE),
type='exit', path.dep=TRUE)   #Initialize a buy/hold strategy object
stratBuyHold <- strategy("BuyHold")
stratBuyHold <- add.indicator(strategy = stratBuyHold, name = "BuyHold",
arguments = list(price = quote(Cl(mktdata)),periodtobuy=num_periods),
label = "BuyHold")
stratBuyHold <- add.rule(strategy=stratBuyHold, name='ruleSignal',
arguments = list(sigcol="BuyHold",sigval=TRUE,orderqty=100,ordertype='market',
orderside='long', pricemethod='market', replace=FALSE), type='enter', path.dep=TRUE)     currency("USD")
symbols = c("GSPC","GDAXI")
for (symbol in symbols) {
stock(symbol, currency="USD",multiplier=1)
#use paste with ^ to get index data
getSymbols(paste("^",symbol,sep=""),adjust=T,from="1900-12-31")
assign(symbol,to.weekly(get(symbol)))
}   initDate='1949-12-31'
initEq=1000000
port.st<-'CUD' #use a string here for easier changing of parameters and re-trying
port.buyhold <- 'BuyHold'   initPortf(port.st, symbols=symbols, initDate=initDate)
initAcct(port.st, portfolios=port.st, initDate=initDate, initEq=initEq)
initOrders(portfolio=port.st, initDate=initDate)   initPortf(port.buyhold, symbols=symbols, initDate=initDate)
initAcct(port.buyhold, portfolios=port.buyhold, initDate=initDate,, initEq=initEq)
initOrders(portfolio=port.buyhold, initDate=initDate)   print("setup completed")   # Process the indicators and generate trades
start_t<-Sys.time()
out<-try(applyStrategy(strategy=stratCUD , portfolios=port.st ) )
end_t<-Sys.time()
print("Strategy Loop:")
print(end_t-start_t)   # Process buy and hold strategy
start_t<-Sys.time()
out<-try(applyStrategy(strategy=stratBuyHold , portfolios=port.buyhold ) )
end_t<-Sys.time()
print("Strategy Loop:")
print(end_t-start_t)   start_t<-Sys.time()
updatePortf(Portfolio=port.st,Dates=paste('::',as.Date(Sys.time()),sep=''))
updatePortf(Portfolio=port.buyhold,Dates=paste('::',as.Date(Sys.time()),sep=''))
end_t<-Sys.time()
print("trade blotter portfolio update:")
print(end_t-start_t)   # hack for new quantmod graphics, remove later
themelist<-chart_theme()
themelist$col$up.col<-'lightgreen'
themelist$col$dn.col<-'pink'   for(symbol in symbols){
#dev.new()
#chart.Posn(Portfolio=port.st,Symbol=symbol,theme=themelist)
#add the CUD indicator to the bottom of the chart
#jpeg(filename=paste(symbol," Reconcile.jpg",sep=""),quality=100,
# width=6.5, height = 6.5, units="in",res=96)
chart.Reconcile(port.buyhold,port.st,symbol)
plot(add_TA(CUD(get(symbol)[,4],n=num_periods)))
#dev.off()
}   #tradeStats(port.st)   #backwards way to get returns
#again to bypass account p/l logic
port <- getPortfolio(port.st)
for(symbol in symbols) {
#get posPL for the symbol in the portfolio
posPLTable <- port$symbols[[symbol]][["posPL"]]
#easier this way to get ROC for each day when position is held (Pos.Qty > 0)
#rets <- lag(ifelse(posPLTable$Pos.Qty>0,1,0),k=1)*ROC(get(symbol)[,4],type="discrete",n=1)
#the previous commented method is not exactly correct
#since we can only hold integer positions
#to account for this difference we can get
rets <- posPLTable$Gross.Trading.PL/lag(posPLTable$Pos.Value,k=1)
rets[is.na(rets)] <- 0
rets[which(rets[,1]==Inf)] <- 0
rets[which(rets[,1]==-Inf)] <- 0
retCompare <- merge(rets,ROC(get(symbol)[,4],type="discrete",n=1))
colnames(retCompare) <- c(paste(symbol," CUD System",sep=""),symbol)
#jpeg(filename=paste(symbol," Performance.jpeg",sep=""),quality=100,width=6.5, height = 6.5,
# units="in",res=96)
charts.PerformanceSummary(retCompare,ylog=TRUE,
colorset=c("black","gray70"),
main = paste(symbol," CUD System and Index
Performance Summary"
,sep=""))
#dev.off()
#jpeg(filename=paste(symbol," Capture.jpeg",sep=""),quality=100,width=6.5, height = 6.5,
# units="in",res=96)
chart.CaptureRatios(retCompare[,1],retCompare[,2],
main = paste(symbol," CUD System and Index
Capture Ratios"
,sep=""))
#dev.off()
}

Created by Pretty R at inside-R.org

1 comment:

  1. Another very nice example...

    osFillErUp only works for long trades?

    Cordially,

    -DD-

    ReplyDelete