Milktrader

Iterating Until Convergence

Tuesday, April 26, 2011

Bug Collector

Most are quite unamused to find an ant infestation in their kitchen around this time of year. Time to start spraying that stuff that's not supposed to be harmful to humans but that you always wonder if it is anyway. Some bugs, such as ant attacks or software glitches, are bad. But I've got a growing collection of good bugs. Trading bugs written in R.

Below is the R code for the gnat algorithm. It is a simple moving-average crossover system, set with the golden-cross default settings of 50 and 200. You can simply copy it into your R console to play with it. It returns a new object into your global environment (fancy talk for your workspace). The object will be named by whatever symbol you pass into the function, appended with .gnat. So if you leave the parameters alone, you'll get GLD.gnat in your workspace. After running the program, you can check thus:

> gnat()
> ls()
> "GLD.gnat" "gnat" "/previously_loaded_objects/"

If you don't like GLD.gnat because it's awkward to type, you can change it to something more exciting such as this:

> a <- GLD.gnat

And perhaps you want to get a dozen markets in your workspace and you forgot what you assigned to the letter "k". Well, I've got you covered here my friend. I do this sort of thing all the time so I threw in a little comment attachment wizardry in the code. Simply type the following:

> comment(k)
[1] "This is the gnat algorithm for TLT with parameters of 50 and 200"

This is the cool part. To see what the equity curve looks like, type"

> plot(a$equity)


To see how daily returns look like, type:

> hist(exp(a$log_ret))



If you are a gentleman, you compute quick-and-dirty expected return like this:

> mean(exp(a$log_ret)

If this number is bigger than 1, you have something to work with.

Once you see the code below, you'll understand why I'm adding the exp() function to the returns. If you're a PhD in statistics, you already know. If you're not, well I'll just tell you. They're log returns, so this requires a switch-a-roo reversal exercise for them to become simple returns again. 

Here is the code. Any suggestions are welcome. My plans are to create an R package comprised of a bunch of these "quote" -- bugs, sometime soon.

gnat <- function(sym="GLD", fast=50, slow=200){
    
    require("quantmod")
    
    x               <- getSymbols(sym, auto.assign=FALSE)
    x$fast          <- SMA(Cl(x), n=fast)                                         
    x$slow          <- SMA(Cl(x), n=slow)                                      
    x$signal        <- Lag(ifelse (x$fast > x$slow, 1, -1))
   
    x               <- na.omit(x)
    x$log_ret       <- dailyReturn(Cl(x), type="log")*x$signal                            
    x$equity        <- exp(cumsum(x$log_ret))     

    comment(x)      <- paste("This is the gnat algorithm for", sym, 
                             "with parameters of", fast, "and", slow)                              
    bug             <- paste(sym,"gnat", sep=".")    

    assign(bug, x, envir=.GlobalEnv)
}

4 comments:

  1. I love that, using "global environment" instead of workspace. Suits me perfectly, since I work with a virtual office malaysia setup right now.

    ReplyDelete
  2. What would you do if you don't use getSymbols()? The data I use is not found on Yahoo, or any of the other sites. I download the tick data then I transform it in OHLC format.

    If I change,

    x <- getSymbols(sym, auto.assign=FALSE)

    TO

    x <- sym

    I get the error:

    "Warning message:
    In assign(bug, x, envir = .GlobalEnv) :
    only the first element is used as variable name"

    ReplyDelete
  3. Hmm, getSymbols is a wrapper for Yahoo data but it also converts the data into an xts object. If you have a csv, you need to cast it to zoo/xts first

    ReplyDelete
  4. Yes, I already converted it to xts object. After I download the ticker csv file I transform the data by:

    ohlc <- function(ttime,tprice,tvolume,fmt)
    {
    ttime.int <- format(ttime,fmt)
    data.frame(time = ttime[tapply(1:length(ttime),ttime.int,function(x) {head(x,1)})],
    .Open = tapply(tprice,ttime.int,function(x) {head(x,1)}),
    .High = tapply(tprice,ttime.int,max),
    .Low = tapply(tprice,ttime.int,min),
    .Close = tapply(tprice,ttime.int,function(x) {tail(x,1)}),
    .Volume = tapply(tvolume,ttime.int,function(x) {sum(x)}),
    .Adjusted = tapply(tprice,ttime.int,function(x) {tail(x,1)}))
    }

    data=ohlc(data$time,data$price,data$volume,"%Y%m%d")
    data <- xts(data[,-1], order.by=data[,1])
    data <- as.xts(data)

    That gives me an xts object in the OHLC format. But still when I try to run the data through your gnat function it goes splat with that error. As the error shows that it is occurring in the assign. I will play with this a bit and post any solutions I have here.

    Thanks for the site, I am coding some indicators after reading here.

    ReplyDelete