Tuesday, December 27, 2011

Mean Reversion: What changed in 1987?

Since 8 months I am actively trading some mean reversion strategies as a great diversifier to my intraday trading approach. Until now it worked out quite well.
However to diversify also within the strategy set of mean reversion I use different indicators as entry signals like RSI, DV, CCI and Simple vs. Exponential Moving Averages. To improve Draw Down, Hit Ratio and overall system stability I use multiple filters like trend direction, trend strength and the volatility level.
Last week I spoke with Joachim (has also a German blog) about my approach and he showed me long term chart about a common mean reversion strategy posted in a German forum some time ago. I was quite shocked, as I wasn't aware of these very different time periods for mean reversion before and after the crash of 1987. I don't know if this phenomenon is commonly known.

I trade also the eMini S&P, but was only testing back to 1997 for this market. In order to find out how my current setup would have suffered in former times I have tested my S&P mean reversion 'composite' (consisting of 8 different strategies, no leverage here) back to 1963 with index data from Yahoo. It's 1963 because untill '62 the history has no OHLC data, which I need for some indicators and filters.


S&P 500 Index - Mean reversion composite

The results are horrible till the early '90s. From 1963 until 1973 the equity line drops constantly for ten years and is then building a bottom for almost twenty years. Interesting indeed is that since the crash in 1987 the results are much better. It seems that the market has changed somehow dramatically after these two crash days . For futher analysis I have divided the single trades in two parts before and after the market crash end of october 1987.

Looking at the distributions....

S&P 500 Index - Mean reversion composite / Distribution of returns

.... and the statistics:



After the crash '87 the mean reversion composite shows almost no skew while the returns of the back tested trades before '87 are negatively skewed. However, because of the market offering more opportunities for mean reversion after '87 the back test shows clearly more trades, while having less return volatility. The two periods show a totally different market environment for mean reversion approaches.

So what changed in 1987, leading to an overall great market environment for mean reversion trades? In the forum -I mentioned above- members were discussing about Alan Greenspan taking the Fed office in early 1987. Mr. Greenspan had for sure a huge impact on the equities markets and may be responsible for the long term bull market between 1987 and 2002. But in my opinion this is to simple. In addition the forum members were talking about the existence of a Plunge Protection Team, buying huge equity in heavily falling markets (and selling them later in rising, I guess) leading to more reversion than before. It would be an almost perfect explanation of this phenomenon. However this is a conspiracy theory....

When I think about what changed in the crash 1987, the black scholes option pricing formula comes to my mind. Before 1987 options were priced with a flat implied volatility by mistake. This changed afterwards. And this might have had huge impact on the behaviour of the hedging of option market makers in the underlying stock markets. But I have no clue how this could work out exactly....

So would do you think? Has anyone a proper explanation for this phenomenon?

So I learned that trading mean reversion style systems shows some nice and stable results, but obviously there is evidence to be very careful in monitoring the market changes that might be coming.





Disclaimer

The information on this site is provided for statistical and informational purposes only. Nothing herein should be interpreted or regarded as personalized investment advice or to state or imply that past results are an indication of future performance. The author of this website is not a licensed financial advisor and will not accept liability for any loss or damage, including without limitation to, any loss of profit, which may arise directly or indirectly from use of or reliance on the content of this website(s).  


Under no circumstances does this information represent an advice or recommendation to buy, sell or hold any security.


Tuesday, December 13, 2011

EOM Momentum Stocks Strategy with R

Currently I am learning how to use R for my research. I have found a lot of great sites and blogs giving me a lot of insight into the language as well as useful resources like toolboxes and packages for R.

As I was investigating the turn/end of month (EOM) effekt in some former posts I will now use the R-code and great toolbox from Systematic Investor to show how a momentum stocks strategy may be combined with an EOM strategy. The original code was used to test this effect with sector ETFs. 
Thus I simply changed the code in order to test my idea to use high momentum stocks (see code) for a 2 days holding period from closing of the last day of the month. In addition to the momentum selection criteria, only stocks are chosen if the closing was above the 89 day moving average. This idea has been taken from the sector strategy of the Quanting Dutchman blog.

As the total return stocks data of the current NASDAQ 100 components from Yahoo is used, the results show a huge systematic survivourship bias. Just look at the green equal weight portfolio results. But the possible edge of the strategy can be observed by the comparison of the EOM equal weight (red line) and the EOM Top 3 momentum ranked stocks (black line).    


The results are not very promising as there is somehow a positive edge for the momentum selection (eom.top.rank1 vs eom.equal.weight) but not for the EOM strategy (eom.equal.weight vs. equal weight).
So I decided to apply the WMA filter in a different way. Now trades will only be made when the index is above the 89 period WMA. Something I use in a quite similar way for filtering my seasonal trading.





The results improve dramatically. On the one hand performance is much better and even more interesting the max draw down is only -11% vs -32,6% before.
The R-code using the Systematic Investor Toolbox:  

###############################################################################
# maQuant Rotational Trading EOM : 
# based on work of
# http://www.etfscreen.com/sectorstrategy.php (Strategy)
# Quanting Dutchman: http://quantingdutchman.wordpress.com/2010/06/30/strategy-2-monthly-end-of-the-month-meom/ (Strategy)
# Systematic Investor: http://systematicinvestor.wordpress.com/2011/12/09/simple-and-profitable/ (R-code and Toolbox SIT!)
###############################################################################
# Load Systematic Investor Toolbox (SIT)
 setInternet2(TRUE)
 con = gzcon(url('https://github.com/systematicinvestor/SIT/raw/master/sit.gz', 'rb'))
     source(con)
 close(con)
 
 #*****************************************************************
 # Load components & historical data
 #****************************************************************** 
 load.packages('quantmod')
 
 source="yahoo"
 index="^NDX"
 start='2000-01-01'
 
 # Components from NASDAQ Website
 url = paste('http://www.nasdaq.com/markets/indices/nasdaq-100.aspx',sep="")
 txt = join(readLines(url)) 
 
 # extract tables from this pages
 temp = extract.table.from.webpage(txt, 'Symbol', hasHeader = T)
 temp[,2]
 
 # Symbols
 symbols = c(temp[,2])[2:101]
 
 data = new.env() # Stock Data
 data2 = new.env() # Index
 getSymbols(c(index), src=source, from=start, env = data2, auto.assign=T, warnings=FALSE)
 getSymbols(symbols, src=source, from=start,  env = data, auto.assign=T, warnings=FALSE) 
        for(i in ls(data)) data[[i]] = adjustOHLC(data[[i]], use.Adjusted=T)
 bt.prep(data, align='keep.all', dates='2000::2011')
 bt.prep(data2, align='keep.all', dates='2000::2011')
 
 #*****************************************************************
 # Begin code strategies
 #****************************************************************** 
 prices = data$prices   
 prices2 = data2$prices 
 
 n = ncol(prices)
 nperiods = nrow(prices)
 
 #*****************************************************************
 # FOR COMPARISON: 
 #*****************************************************************
 
 # Equal Weight for Comparison !Survivorship Bias!
 data$weight[] = ntop(prices, n)
 equal.weight = bt.run(data) 
 
 # find month ends, entry and exit dates
 holding.period=2 
 month.ends = endpoints(prices, 'months')
  month.ends = month.ends[month.ends > 0]  
 month.ends2 = iif(month.ends + holding.period > nperiods, nperiods, month.ends + holding.period)
 
 # EOM INDEX Strategy
 data2$weight[] = NA
  data2$weight[month.ends,] =  ntop(prices2, 1)[month.ends,]
  data2$weight[month.ends2,] = 0
  capital = 100000
  data2$weight[] = (capital / prices2) * data2$weight
 eom.index = bt.run(data2, type='share')
 
 # EOM Equal Weight Strategy 
 data$weight[] = NA
  data$weight[month.ends,] = ntop(prices, n)[month.ends,] 
  data$weight[month.ends2,] = 0
 
  capital = 100000
  data$weight[] = (capital / prices) * data$weight
 eom.equal.weight = bt.run(data, type='share')
 
 #*****************************************************************
 # MOMENTUM EOM STRATEGY: 
 #*****************************************************************
 
 # BuyRule = C > WMA(C, WMA.period)
 WMA.period=89 # Apply x day average for Index
 buy.rule = prices2 > bt.apply.matrix(prices2, function(x) { WMA(x, WMA.period) } )  
  buy.rule = ifna(buy.rule, F)
 buy.rule2=prices
  buy.rule2[,1:n]=buy.rule
 
 lag.period=20 # Apply x day momentum for Stocks
 ret2 = ifna(prices / mlag(prices, lag.period), 0)
 
 # Rank1 = MA( C/Ref(C,-lag.period), 5 ) * MA( C/Ref(C,-lag.period), 40 ) / Simply taken from original Systematic Investor Post
 position.score = bt.apply.matrix(ret2, SMA, 5) * bt.apply.matrix(ret2, SMA, 40) 
  position.score[!buy.rule2] = NA
 
 pos.number=3 # Number of Stocks choosen 
 # Strategy EOM - top X    
 data$weight[] = NA;
  data$weight[month.ends,] = ntop(position.score[month.ends,], pos.number)  
  data$weight[month.ends2,] = 0  
 
  capital = 100000
  data$weight[] = (capital / prices) * data$weight
 eom.top.rank1 = bt.run(data, type='share', trade.summary=T)
 
 #*****************************************************************
 # Create Report
 #****************************************************************** 
 
 report.name=paste('EOM2', start, index, 'WMA', WMA.period, 'lag',lag.period, 'posnum',pos.number, 'hold',holding.period, sep=" ")
 
 # put all reports into one pdf file
 pdf(file = paste(report.name,'.pdf',sep=""), width=8.5, height=11)
  plotbt.custom.report(eom.top.rank1, eom.equal.weight, equal.weight, eom.index, trade.summary=T)
 dev.off() 
 
 png(filename =  paste(report.name,' 1.png',sep=""), width = 600, height = 500, units = 'px', pointsize = 12, bg = 'white')          
  plotbt.custom.report.part1(eom.top.rank1, eom.equal.weight, equal.weight, eom.index,trade.summary=T)
 dev.off() 
 
 png(filename = paste(report.name,' 2.png',sep=""), width = 1200, height = 800, units = 'px', pointsize = 12, bg = 'white') 
  plotbt.custom.report.part2(eom.top.rank1, eom.equal.weight, equal.weight, eom.index,trade.summary=T)
 dev.off() 
 
 png(filename = paste(report.name,' 3.png',sep=""), width = 1200, height = 2000, units = 'px', pointsize = 12, bg = 'white') 
  plotbt.custom.report.part3(eom.top.rank1, eom.equal.weight, equal.weight, eom.index,trade.summary=T)
 dev.off()

I am sure that there is a lot of room for further improvement. Some of the selected stocks might be too heavily overbought. The holding period of the first two trading days of the month seems to be optimal for the EOM strategy but some systematic reaction to the performance of the single trades (stops, targets, holding period) might be useful in order to improve the overall results. Please keep in mind that the results are hypothetical not reflecting any costs of trading. 


Disclaimer

The information on this site is provided for statistical and informational purposes only. Nothing herein should be interpreted or regarded as personalized investment advice or to state or imply that past results are an indication of future performance. The author of this website is not a licensed financial advisor and will not accept liability for any loss or damage, including without limitation to, any loss of profit, which may arise directly or indirectly from use of or reliance on the content of this website(s).  

Under no circumstances does this information represent an advice or recommendation to buy, sell or hold any security.


Saturday, December 10, 2011

Switching to english and what the heck I do for a living

Almost all blogs I follow (see blogroll) and most of the news I read are in english. Last week I spoke with Frank from Engineering Returns and found out that he is a German, too. So I finally decided to switch to the english in my posts. It is the language of the quant traders community.  I hope that I won't make too many mistakes.

In the near future I plan some posts about my current research regarding rotational stock and ETF-trading (Yes, Delta 1 products, ask UBS...) . I will use R as I currently learn that script language and I will use very usefull stuff and ideas from other blogs, especially the oustanding SIT (toolbox for backtests and charting in R) from Systematic Investor. I will focus more on the European ans Asian markets as I have a home bias as well. However because of a lag of accurate long term total return stock and ETF quotes I will also use US data.

My expierence and my current quantitative systems in live trading are more tilted to short term Futures. When someone asks me what the heck I am doing for a living I automatically remember this video. I like it, because it exactly describes my mixed feelings about my 'investments'.