The Average Investor's Blog

A software developer view on the markets

Pre-computing a trading plan in parallel

Posted by The Average Investor on Nov 11, 2011

R version 2.14 introduced a new package, called parallel. This new package combines the functionality from two previous packages: snow and multicore. Since I was using multicore to parallelise my computations, I had to migrate to the new package and decided to publish some code.

Often trading strategies are tested using the daily closing price both to determine the position and to perform the trading. Since we need to pre-compute an action plan, parallelisation may be necessary if the computations are heavy.

The code at the end of this post is pre-computing the actions for the CSS Analytics’ DVI indicator. The entry point in the code is as follows:

library( quantmod )
library( parallel )

# Load the code at the end of this post

# Get the SPY ETF from Yahoo
getSymbols( "SPY", from="1900-01-01" )

# Compute the actions
computeDVIActionPar( Cl( SPY ), range=10, cores=8 )

This basically requests to compute the position for all possible closing prices between -10% and +10%, parallelising the work 8 fold. The output of the command is something like:

   Price    Pct Position
1 111.59 -10.00        1
2 127.97   3.21       -1
3 136.38  10.00       -1

This output tells us that if the SPY doesn’t advance more than 3.21%, closing above $127.97, we should establish a long position at the close, otherwise – short. With that knowledge, and depending on the current position, what is left to do is to go to our Interactice Broker account and to put a limit on-close order. The complete code for the missing functions follows.

computeOneDVIAction = function( close, x )
{
   x[tail( index( x ), 1 )] = close
   dvi = DVI( x )
   val = as.numeric( tail( dvi$dvi, 1 ) )

   # Short if DVI > 0.5, long otherwise
   if( is.na( val ) )
   {
      return( 0 )
   }
   else if( val > 0.5 )
   {
      return( -1 )
   }

   return( 1 )
}

computeDVIActionPar = function( x, step=0.01, range=5, cores )
{
   require( quantmod, quietly=TRUE )
   require( parallel, quietly=TRUE )

   prices = c( )
   positions = c( )

   latestClose = as.numeric( coredata( last( x ) ) )

   # Shift to the left to use the last entry as the "guessed" close
   yy = lag( x, -1 )

   # range is percentages
   range = range / 100

   # Compute the vector with all closing prices within the range
   close = latestClose * ( 1 - range )
   lastClose = latestClose * ( 1 + range )

   close = round( close / step ) * step
   numSteps = ( close - latestClose ) / step + 1

   close = round( close, 2 )
   lastClose = ceiling( lastClose * 100 ) / 100

   closes = close

   repeat
   { 
      if( close >= lastClose ) break

      close = round( latestClose + step*numSteps, 2 )

      numSteps = numSteps + 1

      closes = c( closes, close )
   }

   # Detect the cores if not supplied
   if( missing( cores ) )
   {
      cores = parallel:::detectCores()
   }

   res = mclapply( closes,
                   computeOneDVIAction,
                   x = yy,
                   mc.cores = cores )

   # Summarize the positions
   prices = c()
   pcts = c()
   positions = c()

   # Impossible position
   lastPosition = -1e9

   len = length( closes )
   for( ii in 1:(len - 1) )
   {
      if( res[[ii]] != lastPosition )
      {
         positions = append( positions, res[[ii]] )
         prices = append( prices, closes[ii] )
         pcts = append( pcts, round( ( closes[ii] - latestClose ) /
                                     latestClose * 100, 2 ) )
         lastPosition = res[[ii]]
      }
   }

   positions = append( positions, res[[len]] )
   prices = append( prices, closes[ii] )
   pcts = append( pcts, round( ( closes[len] - latestClose ) /
                               latestClose * 100, 2 ) )

   df = data.frame( prices, pcts, positions )
   colnames( df ) = c( "Price", "Pct", "Position" )
   return( df )
}
Advertisements

Posted in R, Strategies | 5 Comments »

Covered Call ETF Performance

Posted by The Average Investor on Nov 1, 2011

Covered call ETFs have become quite popular lately. Living in Canada, I have been holding a couple Canadian members of this family for the last few months. When I purchased them, I liked the benefits and since I wasn’t expecting any bull markets on the horizon, I bought some. These were new products back them, so I promised myself to do some more detailed analysis at a later point.

Today was that later point. I took Horizons HXT and HEX ETFs. There are more details on the web site, but in general, HXT is a TSX60 ETF with re-invested dividends, while HEX is the covered called version, paying dividends on monthly basis. HEX was introduced in April and I made my purchase a few months later. Before jumping to the results let’s try to state my expectations. I was expecting after dividends HEX to outperform HXT. Seriously, weren’t the last few months the “best” by definition environment for covered call ETFs?

Now, here is the performance chart:

HXT vs HEX

HXT vs HEX

This chart was created using the following code:

library( quantmod )
library( ggplot2 )

# Get the symbols
getSymbols( c("HXT.TO", "HEX.TO"), from="1900-01-01")

# Align the dates
mm = merge( Ad( HXT.TO ), Ad( HEX.TO ), all=F )

# Compute the returns
hxtRets = dailyReturn( mm[,1] )
hexRets = dailyReturn( mm[,2] )

# Compute the growth
hxtGrowth = cumprod( 1 + hxtRets )
hexGrowth = cumprod( 1 + hexRets )

# Build a data frame for ggplot
df = data.frame(
            time(hxtGrowth),
            hxtGrowth,
            hexGrowth,
            row.names=seq(1, length(time(hxtGrowth))))
colnames(df) = c("Date", "HXT", "HEX")

# Plot
gg = ggplot( df, aes( Date ) )
gg = gg + geom_line( aes( y=HXT, color="HXT" ) )
gg = gg + geom_line( aes( y=HEX, color="HEX" ) )
gg = gg + opts( title="HXT vs HEX" )
gg = gg + xlab( "Date" ) + ylab( "Growth" )
gg = gg + scale_color_manual( name="ETFs", values=c("HXT"="blue", "HEX"="red"))
gg

Let’s put it this way – I am disappointed by this chart. Not only the covered call ETF performed worse, it did so with the same level of volatility (just eyeballing the chart). There is even more to it – the above chart assumes perfect dividend re-investment. While there is DRIP in Canada, there are no fractional shares. It’s probably insignificant, but certainly something to keep in mind for products that yield 10-20% annually. Last but not least, HXT does not pay any dividends – they are reinvested and as of recently, its trading is free if your stock broker is Scotia iTrade.

The above chart is not the only tool I used for this analysis, I also maintain a spreadsheet to track the exact performance of these ETFs. Unfortunately, the results of my spreadsheet looks similar to my chart.

The moral of the story – if something looks too good be true, probably it is. The media hype is always a suspect, even from reliable sources like the venerable BNN.

Posted in R, Strategies | 4 Comments »

S&P 500 10 month MA action preview

Posted by The Average Investor on Oct 30, 2011

Monday is the last trading day of October. At the beginning of the month it was hard to foresee a position change at the end October, because the index would need to close a whopping 14.03% above the the close of September 30, 2011. Now, with one trading day to go, the impossible has become a reality, a close above $1,290.14, up only 0.39% from the close on Friday, will put the S&P 500 above its 10-month moving average.

The number on the SPY is a bit different. This ETF needs to close at or above $130.15, about 1.20% above Friday’s close, to end the month above its 10-month moving average. Not impossible, but certainly more unlikely.

Let’s see what tomorrow brings.

Posted in Market Timing | 2 Comments »

The Weekly Update

Posted by The Average Investor on Oct 30, 2011

It has been awhile since we had long positions to follow on the 20-week moving average, but here we are, with a huge single week gain, thanks to the jump after Europe promised to throw more money on a problem created by too much money … Amazing how these things work in “real” life (punt intended), isn’t it.

Helped by the huge move on Thursday, the S&P 500 ended up above its 200-day moving average.

Moving Average Position Since Gain
200 Day Long (SPY) 2011-10-27 -0.00%
20 Week Long (SPY) 2011-10-21 3.73%
10 Month Out (IEF) 2011-08-31 -0.83%

This is the first time I am using the above format, so some clarification is appropriate. First, from now on, I will be following only the S&P 500. For the long MA positions, I will be using the SPY to compute the returns, while for the neutral positions, I will be using the returns on IEF, the iShares Lehman 7-10 Year Treasury Bond ETF.

The format of the table on the right of the main article has also change. It will reflect the positions on S&P 500 based on various indicators.

Posted in Market Timing, Trades | Leave a Comment »

S&P 500 approaching the 200-day moving average

Posted by The Average Investor on Oct 27, 2011

With an agreement from Europe, backed by lots of money, tomorrow is likely to be a huge green day in the markets. In order to close above its 200-day moving average, the S&P 500 needs to close above $1,274.19, or +2.59%. Quite possible, if not tomorrow, certainly over the next few days (the breaking point is valid only for tomorrow, but it should be close to the right number anyways). From technical perspective, it starts to look more and more like we are done with the correction. Surprisingly, (tongue in chick) the fundamentals are pointing to the same conclusion.

Happy trading!

Posted in Market Timing, Strategies | 1 Comment »

The Weekly Update

Posted by The Average Investor on Oct 24, 2011

Although the mood seems to have changed, there were no major changes in the markets over the last week – the S&P 500 is the only index above its 20-week moving average.

However, as mentioned earlier, I am moving away from using exponential moving averages. For the time being I am planning to stick with simple moving average, and it was on Friday when the S&P 500 closed above its 20-week SMA (it did close above its 20-week EMA a week earlier). Thus, I will track this position using the SMA crossover.

There are a few changes coming, so stay tuned. In general, I am planning to keep track only of the S&P 500, but to extend the coverage using a few indicators on daily basis. Most of them, but not all, being moving averages. If you have any comments or suggestions – let me know.

Happy trading!

Posted in Market Timing, Trades | Leave a Comment »

R. I. P. EMA

Posted by The Average Investor on Oct 20, 2011

That’s right, I am moving away from exponential moving averages. Originally, I decided to use them somewhat arbitrary, probably because they tend to swing faster. Last night, after spending two and half hours debugging an issue which yet again turned out to be a particular property of these averages, I made my mind. I am back to simple moving averages and probably weighted moving averages for faster convergence.

What is the annoying property of exponential moving averages? They are recursive. In other words, each consecutive value is computed using the previous value. So what’s the problem? Here is an illustration:

library( quantmod )

getSymbols( "SPY", from="1900-01-01" )

spyEMA = EMA( tail( Cl( SPY ), 300 ), 200 )
print( as.numeric( last( spyEMA ) ) )

spyEMA = EMA( tail( Cl( SPY ), 400 ), 200 )
print( as.numeric( last( spyEMA ) ) )

Guess what the output is? That’s right – it’s different!

[1] 123.0065
[1] 123.4964

Not quite beneficial for trading research and since it has manifested on multiple occasions, it’s certainly time to move on.

Posted in R | 1 Comment »

The Weekly Update

Posted by The Average Investor on Oct 15, 2011

The last week lifted most markets around the world substantially. The gain on the S&P 500 was extraordinary – 5.93%. This steep advance to the upside, moved the S&P above its 20-week MA (as of the close on Friday).

S&P 500 with 20-week MA

The above chart reveals an interesting fact – the surge up was sufficient to penetrate only the fast 20-week EMA (the blue line), but not the 20-week SMA (the red line). Is it another whipsaw or a turn around? Only the future will tell, but based on the current chart, the re-entry is at a better level than the exit.

I will end the post with the code to generate the chart:

> library(quantmod)
> getSymbols("^GSPC", from="1900-01-01")
> png("~/ttt/sp500.png", width=480, height=320)
> chartSeries( to.weekly(GSPC), type="candlesticks", subset="2010/", theme="beige", name="S&P 500", TA=c(addEMA(20), addSMA(20)))
> dev.off()

Posted in Market Timing, Trades | Leave a Comment »

Schannep’s out of the market too

Posted by The Average Investor on Oct 6, 2011

According to a recent update on MarketWatch, Jack Schannep is, as of the Monday close, again out of the market according to his interpretation of the Dow Theory.

Why on Monday and not earlier – one might expect that according to his interpretation, we would had a Dow Theory sell signal on September 22:

Status Date S&P 500 % Date DJI %
High 2011-08-31 $1,218.89 2011-08-31 $11,613.53
Bounce 2011-09-09 $1,154.23 -5.30% 2011-09-09 $10,992.13 -5.35%
Pull Back 2011-09-16 $1,216.01 5.35% 2011-09-16 $11,509.09 4.70%
Sell 2011-09-22 $1,129.56 2011-09-22 $10,733.83

Why the sell on the close of October the 3th? The explanation in my opinion is that the secondary reactions should last at least three weeks (according to a statement made by Robert Rhea, one of the early Dow Theorists). In other words, we need at least 15 trading days between the recent high and the bounce. This changes the table to:

Status Date S&P 500 % Date DJI %
High 2011-08-31 $1,218.89 2011-08-31 $11,613.53
Bounce 2011-09-22 $1,129.56 -7.33% 2011-09-22 $10,733.83 -7.57%
Pull Back 2011-09-27 $1,175.38 4.06% 2011-09-27 $11,190.61 4.26%
Sell 2011-10-03 $1,099.23 2011-10-03 $10,655.30

In any case, all long term indicators which have worked fairly well historically suggest staying out of the market at this point.

Posted in Market Timing | Leave a Comment »

Configuring R via .Rprofile

Posted by The Average Investor on Oct 2, 2011

For a while I have been looking for a way to load stuff automatically in R on each start (quantmod package, some options, etc). I had given up on solving it in a straightforward way, so I was delighted to find this post on R-bloggers!

Currently my .Rprofile is a two-liner:

library( quantmod )
options( width=120 )

Posted in Uncategorized | Leave a Comment »

 
%d bloggers like this: