Interesting volatility measurement, part 2
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
A few weeks ago I have mentioned about an interesting volatility prediction. It is based on two periods of historical volatility (standard deviation). The remaining question was – does it really works? I could not give the answer, because I didn’t have VIX futures data at that time. Later on, I was contacted by Brian G. Peterson, who provided necessary data to finish this test. By the way, I just found, that CBOE shares VIX futures data on its website.
Now I want you to show, what are returns of VIX futures for the next 3 days, then historical volatility ratio of 3 days vs 10 days is less than 0.25:
Sys.setenv(TZ="GMT") require('xts') require('quantmod') require('blotter') require('PerformanceAnalytics') tmp<-as.matrix(read.table('tickers/various_day_close/VIXc1.csv',sep=',',header=TRUE)) vix<-as.xts(as.double(tmp[,9]),order.by=as.POSIXct(strptime(tmp[,2],'%d-%b-%Y'),tz='GMT')) vix<-(vix[!is.na(vix)]) colnames(vix)<-c('Close') tmp<-as.matrix(read.table('tickers/various_day_close/ESc1.csv',sep=',',header=TRUE)) es<-as.xts(as.double(tmp[,9]),order.by=as.POSIXct(strptime(tmp[,2],'%d-%b-%Y'))) es<-(es[!is.na(es)]) colnames(es)<-c('Close') #-----------------data end----------------- #-----------------signal------------------- es.delta<-Delt(Cl(es)) delta<-Delt(Cl(vix))#Front contract #Historical volatility during 3 and 10 days short.vol<-as.xts(rollapply(es.delta,3,sd,align='right')) long.vol<-as.xts(rollapply(es.delta,10,sd,align='right')) past.vol<-short.vol/long.vol future.vol<-lag(past.vol,-3) future.delta<-lag(vix,-3)/vix-1 signal<-ifelse(past.vol<0.25,1,0) #here we see, increase in historical volatility summary(as.double(future.vol[index(signal[signal!=0])]))/summary(as.double(past.vol[index(signal[signal!=0])])) #-----------------signal end------------------- #--------------blotter code------------------ symbols<-c('vix') initDate=time(get(symbols)[1]) initEq=50000 rm(list=ls(envir=.blotter),envir=.blotter) ltportfolio='volatility' ltaccount='volatility' initPortf(ltportfolio,symbols, initDate=initDate) initAcct(ltaccount,portfolios=c(ltportfolio), initDate=initDate,initEq=initEq) currency("USD") stock(symbols[1],currency="USD") signal<-signal[index(vix)] signal[is.na(signal)]<-0 counter<-0 #date counter - exit on 3th day for(i in 2:length(signal)) { currentDate= time(signal)[i] equity = initEq #getEndEq(ltaccount, currentDate) position = getPosQty(ltportfolio, Symbol=symbols[1], Date=currentDate) print(position) print(currentDate) if(position==0 &counter==0) { #open a new position if signal is >0 if(signal[i]>0) { print('open position') closePrice<-as.double(get(symbols[1])[currentDate]) print(closePrice) unitSize = as.numeric(trunc((equity/closePrice))) print(unitSize) 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 & as.integer(signal[i])==0 &counter>=3) { position = getPosQty(ltportfolio, Symbol=symbols[1], Date=currentDate) closePrice<-as.double(get(symbols[1])[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('>>>>>>>>>>>>') updatePortf(ltportfolio, Dates = currentDate) updateAcct(ltaccount, Dates = currentDate) updateEndEq(ltaccount, Dates = currentDate) } rez1<-(getPortfolio(ltaccount)) #--------------blotter code end------------------ #----------------results------------------------ png('vix_front.png',width=650) #net profit - commissions, slipage excluded chart.TimeSeries(cumsum(rez1$symbols$vix$txn[,7]),main='VIX front contract') dev.off() #----------------results end------------------------ |
The graph shows, that this strategy is pure random or just follows VIX index. Now let’s see, what are returns of this strategy, if S&P500 futures are used instead of VIX.
signal<-ifelse(past.vol<0.25,1,0) #signal<-signal[index(es)] #------------------------blotter code----------------------- symbols<-c('es') initDate=time(get(symbols)[1]) initEq=15000 rm(list=ls(envir=.blotter),envir=.blotter) ltportfolio='volatility' ltaccount='volatility' initPortf(ltportfolio,symbols, initDate=initDate) initAcct(ltaccount,portfolios=c(ltportfolio), initDate=initDate,initEq=initEq) currency("USD") future(symbols[1],currency="USD",multiplier=50,1/4) signal[is.na(signal)]<-0 counter<-0 for(i in 2:length(signal)) { currentDate= time(signal)[i] equity = initEq #getEndEq(ltaccount, currentDate) position = getPosQty(ltportfolio, Symbol=symbols[1], Date=currentDate) print(position) print(currentDate) if(position==0 &counter==0) { #open a new position if signal is >0 if(signal[i]>0) { print('open position') closePrice<-as.double(get(symbols[1])[currentDate]) print(closePrice) unitSize = 1#as.numeric(trunc((equity/closePrice))) print(unitSize) commssions=-2 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 & as.integer(signal[i])==0 &counter>=3) { position = getPosQty(ltportfolio, Symbol=symbols[1], Date=currentDate) closePrice<-as.double(get(symbols[1])[currentDate])#as.double(get(symbols[1])[i+100]) commssions=-2 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) } rez1<-(getPortfolio(ltaccount)) #-------------------------results--------------------- #net profit png('vix.png',width=650) chart.TimeSeries(cumsum(rez1$symbols$es$txn[,9]),main='ES future contract') dev.off() |
Well, that is exact opposite of expectations – if we expect volatility increase, as it was described in the first post, then the returns of S&P index have to be negative in long run.
From the beginning I suspected, that it has more to do with standard deviation formula and less with forecast.
Now funny part – I generated 2500 random returns and got median 0.9930 and mean 1.6360 for all days. Then I took all days, when buy signal suppose to be generated and guess what mean did I get? Median was 4.3170 and mean 6.3450. Once again, significant difference but on random data.
Source code on github
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.