3 weak days in a row

December 6, 2010
By

(This article was first published on Quantitative thoughts » EN, and kindly contributed to R-bloggers)

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:

Photobucket

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()

Photobucket

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.

To leave a comment for the author, please follow the link and comment on his blog: Quantitative thoughts » EN.

R-bloggers.com offers daily e-mail updates about R news and tutorials on topics such as: visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...



If you got this far, why not subscribe for updates from the site? Choose your flavor: e-mail, twitter, RSS, or facebook...

Tags: , , ,

Comments are closed.