3 weak days in a row
Recently, Trading the odds posted one of many flavors of mean reverting strategies and I decided to get my hands dirty by writing R code and testing it.
You can find full description of the strategy by following latter link above. Long story short – if SPY shows lower open, high and close 3 days in a row, then buy on the close of third day and sell it 1 days later.
Let’s do simple test:
require('xts') require('quantmod') getSymbols('SPY',from='1995-01-01',index.class=c("POSIXt","POSIXct")) dividends=getDividends('SPY',from='1995-01-01',index.class=c("POSIXt","POSIXct")) temp=cbind(dividends,SPY) temp[,1][is.na(temp[,1])]=0 SPY=cbind(temp[,2],temp[,3],temp[,4],temp[,1]+temp[,5]) colnames(SPY)=c("Open","High","Low","Close") #one day before lag1=lag((SPY),1) #two days defore lag2=lag((SPY),2) signal=ifelse( (Cl(lag2)>Cl(lag1) & Cl(lag1)>Cl(SPY))& (Hi(lag2)>Hi(lag1) & Hi(lag1)>Hi(SPY)) & (Op(lag2)>Op(lag1) & Op(lag1)>Op(SPY)), 1,0 ) #one day later lag3=lag(Cl(SPY),-1) profit=(lag3/Cl(SPY)-1)*signal profit[is.na(profit)]=0 png(file='first.png',width=500) plot(cumprod(profit+1),main='Profit 1995-2010') dev.off() |
The code above supposed to produce something similar:
Nice curve, isn’t it? But neither commissions nor slippage were taken into account. So, let’s run more complicated test. For that purpose I utilized blotter package. Here’s the code:
require('xts') require('quantmod') require('blotter') require('PerformanceAnalytics') require('FinancialInstrument') getSymbols('SPY',from='1995-01-01',index.class=c("POSIXt","POSIXct")) dividends=getDividends('SPY',from='1995-01-01',index.class=c("POSIXt","POSIXct")) temp=cbind(dividends,SPY) temp[,1][is.na(temp[,1])]=0 SPY=cbind(temp[,2],temp[,3],temp[,4],temp[,1]+temp[,5]) colnames(SPY)=c('Open','High','Low','Close') #one day before lag1=lag((SPY),1) #two days defore lag2=lag((SPY),2) signal=ifelse( (Cl(lag2)>Cl(lag1) & Cl(lag1)>Cl(SPY))& (Hi(lag2)>Hi(lag1) & Hi(lag1)>Hi(SPY)) & (Op(lag2)>Op(lag1) & Op(lag1)>Op(SPY)), 1,0 ) #one day later lag3=lag(Cl(SPY),-1) symbols=c('SPY') initDate=index(get(symbols)[1]) initEq=10000 rm(list=ls(envir=.blotter),envir=.blotter) ltportfolio='3days' ltaccount='3days' initPortf(ltportfolio,symbols, initDate=initDate) initAcct(ltaccount,portfolios=c(ltportfolio), initDate=initDate,initEq=initEq) currency("USD") stock("SPY",currency="USD",multiplier=1) signal[is.na(signal)]=0 counter<-0 for(i in 2:length(signal)) { currentDate= time(signal)[i] equity = 10000 #getEndEq(ltaccount, currentDate) #print(paste("equity ",equity)) position = getPosQty(ltportfolio, Symbol=symbols[1], Date=currentDate) print(currentDate) if(position==0) { #open a new position if signal is >0 if(signal[i]>0 &counter ==0) { print('open position') closePrice<-as.double(Cl(SPY[currentDate])) unitSize = as.numeric(trunc((equity/closePrice))) commssions=-unitSize*closePrice*0.0003 addTxn(ltportfolio, Symbol=symbols[1], TxnDate=currentDate, TxnPrice=closePrice, TxnQty = unitSize , TxnFees=commssions, verbose=T) counter<-1 } } else { #position is open. If signal is 0 - close it. if(position>0 &counter>=1) { print('close position>>>>') position = getPosQty(ltportfolio, Symbol=symbols[1], Date=currentDate) closePrice<-as.double((Cl(SPY[currentDate])))#as.double(get(symbols[1])[i+100]) commssions=-position*closePrice*0.0003 addTxn(ltportfolio, Symbol=symbols[1], TxnDate=currentDate, TxnPrice=closePrice, TxnQty = -position , TxnFees=commssions, verbose=T) counter<-0 } else counter<-counter+1 } #print(equity) updatePortf(ltportfolio, Dates = currentDate) updateAcct(ltaccount, Dates = currentDate) updateEndEq(ltaccount, Dates = currentDate) #equity = getEndEq(ltaccount, currentDate) #print(paste("equity ",equity)) } result=rez1$symbols$SPY$txn[,7] result=result[result!=0] png(file='second.png',width=500) #fix commission rate 2*3 plot(cumsum(result-6)) #next line will allow you to compare the performace with and without commissions #chart.CumReturns(cbind((result)/10000,(result-6)/10000)) dev.off() |
Nice curve, but let’s look beyond that. First of all, here’s nice function in PerformanceAnalytics package, AnnulizedReturns:
table.AnnualizedReturns((result-6)/10000)
Gross.Txn.Realized.PL
Annualized Return 0.0265
Annualized Std Dev 0.0494
Annualized Sharpe (Rf=0%) 0.5366
Well, Sharpe ratio is not impressive. The profit percentage of this strategy is 57% and mean of profitable return is 111$ against 98$ loss. Profit factor is ~1.55.
I think, this strategy can be as one of the parameter or vote in another system, but alone it is weak.


kafka said,
December 6, 2010 @ 23:04
Plugin for R code doesn’t work properly and I will work on that tomorrow, meantime you can check the code here: https://github.com/kafka399/Rproject/blob/master/3lowDays.R
kafka said,
December 7, 2010 @ 8:45
The code is fixed – let me know if you have some difficulties to run it.
A Few Posts - Quantitative Finance - said,
December 8, 2010 @ 19:00
[...] testing the performance of 3 days in a row trading strategy with & without commission in R, http://www.investuotojas.eu/?p=409;2, writing nicer R codes with Notepad++ and NppToR, http://robjhyndman.com/researchtips/npptor/;3, [...]
John said,
January 21, 2011 @ 4:34
Hi,
I’m trying to find out what the “>” and “&” in the ifelse code mean. I keep getting an error at that point of the script.
From my Rgui:
> signal=ifelse( (Cl(lag2)>Cl(lag1) & Cl(lag1)>Cl(SPY))&
Error: unexpected ‘;’ in “signal=ifelse( (Cl(lag2)>”
> (Hi(lag2)>Hi(lag1) & Hi(lag1)>Hi(SPY)) &
Error: unexpected ‘;’ in ” (Hi(lag2)>”
> (Op(lag2)>Op(lag1) & Op(lag1)>Op(SPY)),
Error: unexpected ‘;’ in ” (Op(lag2)>”
> 1,0
Error: unexpected ‘,’ in ” 1,”
> )
Error: unexpected ‘)’ in “)”
I tried Rseek for answer but came up with nothing useful.
John
Dzidorius Martinaitis said,
January 21, 2011 @ 11:38
John,
I suspect, that when you copied the code you took html interpretation of > and &. Click on View code and make a copy of source code from there.
jim green said,
May 23, 2012 @ 16:39
52c52
stock(symbols,currency=”USD”,multiplier=1)
there seems to be a little bug.