3 weak days in a row
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
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 } updatePortf(ltportfolio, Dates = currentDate) updateAcct(ltaccount, Dates = currentDate) updateEndEq(ltaccount, Dates = currentDate) } 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.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.