Tuesday, June 7, 2011

A Quantstrat to Build on Part 2

As I explore additional functionality of quantstrat and make changes to my original post A Quantstrat to Build On, I will write multiple posts, and hopefully, the finished product will not be so overwhelming to comprehend.  Also, it might highlight how I build a system, or how like Pixar, I go "from suck to not suck,” highlighted in a great Fast Company article.  I’ll make 5 changes here:

  1. Add another index GDAXI (German Dax) for additional testing with USD as currency (I always separate currency from the asset class), and I’ll save others for out of sample testing
  2. Change the number of periods (in this case weeks) to 50 from 20 so we have less signals and enjoy life more.  I also added this as a variable early, so we only have to change once to apply across the system and charts
  3. Change the gt(>) –0.5 that I hacked originally to the more correct gte (>=) 0 relationship provided by quantstrat
  4. Added the CUD indicator to the chart.Posn with add_TA (note add_TA works and TA=”addTA..” does not) and removed the log=TRUE option which does not work

I learned that there are 5 (as of 6/7/2011) signal types that can be implemented with the 5 relationships gte, gt, eq, lt, or lte (>=,>,==,<,or<=) :

sigComparison is the generic comparison of up to two columns which returns TRUE or FALSE in each period a condition (>=,>,==,<,or<=) is met.  With some hacking this could be used in our scenario if we specified a column with all zeros as our comparison, but this is not recommended and only mentioned to stimulate additional learning (hopefully not confusion).

sigCrossover is a limited sigComparison that only returns TRUE in the period in which a crossover occurs between two columns and NA for all other periods.  This would be used in a moving average type system.  With some hacking this could be used in our scenario if we specified a column with all zeros as our comparison, but this is not recommended and only mentioned to stimulate additional learning (hopefully not confusion).

sigPeak returns TRUE when a single column experiences a local peak or bottom.  This is hard coded to only allow for an analysis of the lag 2 (2 periods ago), lag 1 (1 period ago), and current period, so for instance if a stock closes at 50, 49, and then 49.5, TRUE will be returned.

sigThreshold which is what I use in this example where TRUE is returned if a column moves >=,>,==,<, or <= a specified threshold.  An argument is offered called cross to specify whether TRUE (cross=TRUE) is returned only on the period in which the condition is first matched or TRUE (cross=FALSE) is returned in every period in which the condition is met.  In this example, I use cross=TRUE which works much efficiently later in the addRule portion for in/out long-only type systems.

sigFormula which could be adapted to almost anything.  In the source they mention Vijay Vaidyanthan, past CEO and founder of Return Metrics now at EDHEC, who gave some good presentations at http://www.siliconvalleyaaii.org/archives/archives20072008.html.  I hope to provide some examples of this later, since none of the package demos show this.

From TimelyPortfolio
From TimelyPortfolio

R code:

#thanks so much to the developers of quantstrat
#99% of this code comes from the demos in the quantstrat package  
#in this I make 4 changes to that posted 6/2/2011
#1.Add another index GDAXI (German Dax) for additional testing;
# for now use USD but see faberMC demo for currency fun;
# I'll save more for out of sample testing
#2.Change the number of periods (in this case weeks) to 50 from 20
# so we have less signals and enjoy life more. I also added this as
# variable early in the code, so we only have to change once to apply
# across the system and charts
#3.Change the gt(>) –0.5 that I hacked originally to the more correct
# gte (>=) 0 relationship provided by quantstrat
#4.Added the CUD indicator to the chart.Posn with add_TA
# (note add_TA works and TA=”addTA..” does not) and removed
# the log=TRUE option which does not work  
#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
}  
require(quantstrat)
try(rm("order_book.CUD",pos=.strategy),silent=TRUE)
try(rm("account.CUD","portfolio.CUD",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=1000, ordertype='market',
orderside='long', pricemethod='market', replace=FALSE), 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)   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='1950-12-31'
initEq=100000
port.st<-'CUD'
#use a string here for easier changing of parameters and re-trying   
initPortf(port.st, symbols=symbols, initDate=initDate)
initAcct(port.st, portfolios=port.st, initDate=initDate)
initOrders(portfolio=port.st, 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)   start_t<-Sys.time()
updatePortf(Portfolio=port.st,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
plot(add_TA(CUD(get(symbol)[,4],n=num_periods)))
}

Created by Pretty R at inside-R.org

6 comments:

  1. Hi Kent,

    just my 2c. notes/questions:

    1. I had to slightly change the code alignment since a simple copy/paste wasn't working

    2. still not clear where to find info like signal types and relationship (gte, gt, etc)

    3. some warnings..I know they are not an issue since they are shown for demo scripts too but I'm also very sceptical when I get such verbose and unclear messages

    4. currency for GDAX should be EUR

    5. I've been toying with faberMC.R demo in order to come up with a combined strategy but definitely requires more effort on my side than expected :-)

    Paolo

    ReplyDelete
  2. Thanks so much.
    1) added link to Google Docs to download the code on R code and will attempt to get a github repository
    2) there are 5 relationships provided as of now: gte(>=), gt(>),eq(==),lt(<), or lte(<=)
    3) sorry about the warnings, but they come from the source
    4) changed my post to say USD is used, since I do not I always try to isolate the currency element in my system building; faberMC gives very good illustration of multiple currency but could have more history if it used http://research.stlouisfed.gov/fred2 for currency pricing
    5) since the code is still under heavy development, it will require much more work on the part of the user. Although somewhat strenuous, learning quantstrat has been much easier than many of my other learning alpha/beta projects. Thanks to all the guys who have worked so hard on this.

    ReplyDelete
  3. I fixed of all of the unnecessary warnings (at least for the demos.) You'll need to update both quantstrat and blotter to at least Rev. 621 and 622, respectively. If you can't check it out with svn checkout, I think R-Forge will build it tomorrow around 3 p.m Central time.

    ReplyDelete
  4. almost there! but still getting this error in the output which isn't generating the P&L/Pos indicators.

    > out <- try(applyStrategy(strategy=stratCUD , portfolios=port.st ) )
    Error in if (getPosQty(Portfolio = portfolio, Symbol = symbol, Date = timestamp) == :
    argument is of length zero

    so something in the stratCUD function spitting out the getPosQty error..
    any ideas?

    ReplyDelete
  5. do not know immediately what might cause that even though I have had an error similar to that before; let me think about it more; did you download the code or copy/paste? I have had issues with the copy/paste so I added a link on R code to download from Google Docs.

    ReplyDelete
  6. i retyped it myself, figured out there was negative zeros in the original signals. works all good now, very cool example looking forward to messing around with it. thanks!

    ReplyDelete