1 Collecting the time series

We will consider a bivariate model with returns of W&T Offshore, Inc. and the S&P 500 index.

#install.packages("quantmod")
#install.packages("stochvol")
#install.packages("factorstochvol")
#install.packages("MTS")
library("quantmod")
## Loading required package: xts
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
## Loading required package: TTR
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
library("stochvol")
library("factorstochvol")
library("MTS")
## 
## Attaching package: 'MTS'
## The following object is masked from 'package:TTR':
## 
##     VMA
tickers = c("WTI","^GSPC")
getSymbols(tickers,from='2014-04-05',to='2023-04-04',warnings=FALSE,auto.assign=TRUE)    
## [1] "WTI"   "^GSPC"
names  = c("W&T Offshore, Inc.","S&P 500")
price   = cbind(WTI[,6],GSPC[,6])
price   = as.matrix(price)
n = nrow(price)
p = ncol(price)

1.1 Graphical summaries: prices

par(mfrow=c(1,2))
ts.plot(price[,1],ylab="Price",main=names[1])
ts.plot(price[,2],ylab="Price",main=names[2])

1.2 Graphical summaries: returns

par(mfrow=c(1,2))
return = NULL
for (i in 1:p){
  ts.plot(100*(price[2:n,i]/price[1:(n-1),i]-1),ylab="Returns (%)",main=names[i])
  return = cbind(return,100*(price[2:n,i]/price[1:(n-1),i]-1))
}

ind = !is.na(return[,1])
return = return[ind==TRUE,]
n = nrow(return)

2 Univariate SV-AR(1) models

sigmas.sv    = matrix(0,n,p)
for (i in 1:p){
  y = as.double(return[,i])
  fit.sv = svtlsample(y)
  sigmas.sv[,i] = apply(exp(fit.sv$latent[[1]]/2),2,mean)
}
## Argument 'y' (data vector) contains values very close to zero. I am applying an offset constant of size 0.000490249617855 to do the auxiliary mixture sampling. If you want to avoid this, you might consider de-meaning the returns before calling this function.
## Done!
## Summarizing posterior draws...
## Argument 'y' (data vector) contains values very close to zero. I am applying an offset constant of size 0.000115179072042785 to do the auxiliary mixture sampling. If you want to avoid this, you might consider de-meaning the returns before calling this function.
## Done!
## Summarizing posterior draws...
par(mfrow=c(1,1))
ts.plot(sigmas.sv,col=1:p,ylab="Standard deviation",main="SVLT-AR(1)")
legend("topright",legend=names,col=1:p,lty=1)

3 Factor stochastic volatility (FSV) model

fsv = fsvsample(return,factors=1,runningstore=6)
## 
## Calling 1-factor MCMC sampler for 2 series of length 2263.
## 
## 
********* Iteration    1 of 2000 (  0%) *********
********* Iteration  443 of 2000 ( 22%) *********
********* Iteration  885 of 2000 ( 44%) *********
********* Iteration 1327 of 2000 ( 66%) *********
********* Iteration 1769 of 2000 ( 88%) *********
********* Iteration 2000 of 2000 (100%) *********
## 
## Reorganizing runningstores... Done!
## Ex-post sign-identification... Done!
par(mfrow=c(1,1))
plot(density(fsv$facload[1,1,]),xlim=c(0.4,2.0),ylim=c(0,10),main="Loadings",xlab="")
lines(density(fsv$facload[2,1,]),col=2)
legend("topright",legend=c(expression(beta[11]),expression(beta[21])),col=1:2,bty="n",lty=1)

3.1 Graphical summaries - standard deviations

sd1  = sqrt(fsv$runningstore$cov[,1,1])
sd2  = sqrt(fsv$runningstore$cov[,3,1])
corr = fsv$runningstore$cov[,2,1]/(sd1*sd2)

par(mfrow=c(1,2))
ts.plot(sd1,ylab="Standard deviation",main=names[1],ylim=c(0,20))
lines(sigmas.sv[,1],col=2)
lines(0.1*abs(return[,1]),type="h",col=grey(0.7))

ts.plot(sd2,ylab="Standard deviation",main=names[2],ylim=c(0,7))
lines(sigmas.sv[,2],col=2)
lines(0.1*abs(return[,2]),type="h",col=grey(0.7))

3.2 Graphical summaries - correlation

par(mfrow=c(1,1))
ts.plot(corr,ylim=c(0,1),ylab="Correlation")
abline(h=0.2,lty=2)
abline(h=0.5,lty=2)
abline(h=0.8,lty=2)

4 Dynamic conditional correlation (DCC) model

pre = dccPre(return, include.mean = T, p = 0, cond.dist = "std")
## Sample mean of the returns:  0.06922153 0.04221578 
## Component:  1 
## Estimates:  1.298495 0.106114 0.843234 5.464443 
## se.coef  :  0.356701 0.019165 0.026749 0.620598 
## t-value  :  3.640288 5.536999 31.5245 8.805131 
## Component:  2 
## Estimates:  0.020261 0.196425 0.806509 5.600777 
## se.coef  :  0.005211 0.025366 0.021183 0.657168 
## t-value  :  3.888033 7.743504 38.07419 8.522596
pre$est
##           omega    alpha1     beta1    shape
## [1,] 1.29849458 0.1061140 0.8432337 5.464443
## [2,] 0.02026142 0.1964253 0.8065090 5.600777
return1 = pre$sresi

Vol = pre$marVol

fit = dccFit(return1)
## Estimates:  0.7017527 0.049999 6.110255 
## st.errors:  0.1838962 0.02334849 0.4161715 
## t-values:   3.816026 2.141423 14.68206
S2.t = fit$rho.t

fit1 = dccFit(return1,type="Engle")
## Estimates:  0.8703852 0.03813264 6.137094 
## st.errors:  0.05133039 0.01414681 0.4192691 
## t-values:   16.95653 2.695495 14.6376
S3.t = fit1$rho.t

MCHdiag(return1,S2.t)
## Test results:  
## Q(m) of et: 
## Test and p-value:  12.96677 0.2255356 
## Rank-based test: 
## Test and p-value:  27.4336 0.002222899 
## Qk(m) of epsilon_t: 
## Test and p-value:  37.47703 0.5844202 
## Robust Qk(m):  
## Test and p-value:  49.37191 0.1471156
MCHdiag(return1,S3.t)
## Test results:  
## Q(m) of et: 
## Test and p-value:  12.31411 0.2645841 
## Rank-based test: 
## Test and p-value:  28.04948 0.001772611 
## Qk(m) of epsilon_t: 
## Test and p-value:  37.27335 0.5936759 
## Robust Qk(m):  
## Test and p-value:  57.95281 0.03293376

4.1 Comparing SV-AR(1) and GARCH(1,1)

par(mfrow=c(2,1))
range = range(pre$marVol[,1],sd1)
ts.plot(pre$marVol[,1],xlab="",ylab="",main=names[1],ylim=range)
lines(sigmas.sv[,1],col=2)
legend("topright",legend=c("GARCH(1,1)","SV-AR(1)"),col=1:2,lty=1,bty="n")

range = range(pre$marVol[,2],sd2)
ts.plot(pre$marVol[,2],xlab="",ylab="",main=names[2],ylim=range)
lines(sigmas.sv[,2],col=2)
legend("topright",legend=c("GARCH(1,1)","SV-AR(1)"),col=1:2,lty=1,bty="n")

4.2 Comparing time-varying correlations

par(mfrow=c(1,1))
plot(fit1$rho.t[,2],type="l",ylab="Correlation",ylim=c(0,1),xlab="Time")
lines(corr,col=2)
legend("topleft",legend=c("DCC","FSV(1)"),col=1:2,lty=1,bty="n")
title(paste(names[1]," x ",names[2],sep=""),cex=0.75)
abline(h=0.2,lty=2)
abline(h=0.5,lty=2)
abline(h=0.8,lty=2)

LS0tCnRpdGxlOiAiVGltZS12YXJ5aW5nIGNvdmFyaWFuY2UgbW9kZWxzIgpzdWJ0aXRsZTogIkZhY3RvciBTViBhbmQgRHluYW1pYyBjb25kaXRpb25hbCBjb3JyZWxhdGlvbiIKYXV0aG9yOiAiSGVkaWJlcnQgRnJlaXRhcyBMb3BlcyIKZGF0ZTogIjQvNi8yMDIzIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAyCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQotLS0KICAKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgojIENvbGxlY3RpbmcgdGhlIHRpbWUgc2VyaWVzCgpXZSB3aWxsIGNvbnNpZGVyIGEgYml2YXJpYXRlIG1vZGVsIHdpdGggcmV0dXJucyBvZiBXXCZUIE9mZnNob3JlLCBJbmMuIGFuZCB0aGUgU1wmUCA1MDAgaW5kZXguCgpgYGB7cn0KI2luc3RhbGwucGFja2FnZXMoInF1YW50bW9kIikKI2luc3RhbGwucGFja2FnZXMoInN0b2Nodm9sIikKI2luc3RhbGwucGFja2FnZXMoImZhY3RvcnN0b2Nodm9sIikKI2luc3RhbGwucGFja2FnZXMoIk1UUyIpCmxpYnJhcnkoInF1YW50bW9kIikKbGlicmFyeSgic3RvY2h2b2wiKQpsaWJyYXJ5KCJmYWN0b3JzdG9jaHZvbCIpCmxpYnJhcnkoIk1UUyIpCgp0aWNrZXJzID0gYygiV1RJIiwiXkdTUEMiKQpnZXRTeW1ib2xzKHRpY2tlcnMsZnJvbT0nMjAxNC0wNC0wNScsdG89JzIwMjMtMDQtMDQnLHdhcm5pbmdzPUZBTFNFLGF1dG8uYXNzaWduPVRSVUUpICAgIApuYW1lcyAgPSBjKCJXJlQgT2Zmc2hvcmUsIEluYy4iLCJTJlAgNTAwIikKcHJpY2UgICA9IGNiaW5kKFdUSVssNl0sR1NQQ1ssNl0pCnByaWNlICAgPSBhcy5tYXRyaXgocHJpY2UpCm4gPSBucm93KHByaWNlKQpwID0gbmNvbChwcmljZSkKYGBgCgojIyBHcmFwaGljYWwgc3VtbWFyaWVzOiBwcmljZXMKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD04LCBmaWcuYWxpZ24gPSAnY2VudGVyJ30KcGFyKG1mcm93PWMoMSwyKSkKdHMucGxvdChwcmljZVssMV0seWxhYj0iUHJpY2UiLG1haW49bmFtZXNbMV0pCnRzLnBsb3QocHJpY2VbLDJdLHlsYWI9IlByaWNlIixtYWluPW5hbWVzWzJdKQpgYGAKCiMjIEdyYXBoaWNhbCBzdW1tYXJpZXM6IHJldHVybnMKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD04LCBmaWcuYWxpZ24gPSAnY2VudGVyJ30KcGFyKG1mcm93PWMoMSwyKSkKcmV0dXJuID0gTlVMTApmb3IgKGkgaW4gMTpwKXsKICB0cy5wbG90KDEwMCoocHJpY2VbMjpuLGldL3ByaWNlWzE6KG4tMSksaV0tMSkseWxhYj0iUmV0dXJucyAoJSkiLG1haW49bmFtZXNbaV0pCiAgcmV0dXJuID0gY2JpbmQocmV0dXJuLDEwMCoocHJpY2VbMjpuLGldL3ByaWNlWzE6KG4tMSksaV0tMSkpCn0KaW5kID0gIWlzLm5hKHJldHVyblssMV0pCnJldHVybiA9IHJldHVybltpbmQ9PVRSVUUsXQpuID0gbnJvdyhyZXR1cm4pCmBgYAoKIyBVbml2YXJpYXRlIFNWLUFSKDEpIG1vZGVscwoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTgsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQpzaWdtYXMuc3YgICAgPSBtYXRyaXgoMCxuLHApCmZvciAoaSBpbiAxOnApewogIHkgPSBhcy5kb3VibGUocmV0dXJuWyxpXSkKICBmaXQuc3YgPSBzdnRsc2FtcGxlKHkpCiAgc2lnbWFzLnN2WyxpXSA9IGFwcGx5KGV4cChmaXQuc3YkbGF0ZW50W1sxXV0vMiksMixtZWFuKQp9CgpwYXIobWZyb3c9YygxLDEpKQp0cy5wbG90KHNpZ21hcy5zdixjb2w9MTpwLHlsYWI9IlN0YW5kYXJkIGRldmlhdGlvbiIsbWFpbj0iU1ZMVC1BUigxKSIpCmxlZ2VuZCgidG9wcmlnaHQiLGxlZ2VuZD1uYW1lcyxjb2w9MTpwLGx0eT0xKQpgYGAKCiMgRmFjdG9yIHN0b2NoYXN0aWMgdm9sYXRpbGl0eSAoRlNWKSBtb2RlbAoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTgsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQpmc3YgPSBmc3ZzYW1wbGUocmV0dXJuLGZhY3RvcnM9MSxydW5uaW5nc3RvcmU9NikKCnBhcihtZnJvdz1jKDEsMSkpCnBsb3QoZGVuc2l0eShmc3YkZmFjbG9hZFsxLDEsXSkseGxpbT1jKDAuNCwyLjApLHlsaW09YygwLDEwKSxtYWluPSJMb2FkaW5ncyIseGxhYj0iIikKbGluZXMoZGVuc2l0eShmc3YkZmFjbG9hZFsyLDEsXSksY29sPTIpCmxlZ2VuZCgidG9wcmlnaHQiLGxlZ2VuZD1jKGV4cHJlc3Npb24oYmV0YVsxMV0pLGV4cHJlc3Npb24oYmV0YVsyMV0pKSxjb2w9MToyLGJ0eT0ibiIsbHR5PTEpCmBgYAoKIyMgR3JhcGhpY2FsIHN1bW1hcmllcyAtIHN0YW5kYXJkIGRldmlhdGlvbnMKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD04LCBmaWcuYWxpZ24gPSAnY2VudGVyJ30Kc2QxICA9IHNxcnQoZnN2JHJ1bm5pbmdzdG9yZSRjb3ZbLDEsMV0pCnNkMiAgPSBzcXJ0KGZzdiRydW5uaW5nc3RvcmUkY292WywzLDFdKQpjb3JyID0gZnN2JHJ1bm5pbmdzdG9yZSRjb3ZbLDIsMV0vKHNkMSpzZDIpCgpwYXIobWZyb3c9YygxLDIpKQp0cy5wbG90KHNkMSx5bGFiPSJTdGFuZGFyZCBkZXZpYXRpb24iLG1haW49bmFtZXNbMV0seWxpbT1jKDAsMjApKQpsaW5lcyhzaWdtYXMuc3ZbLDFdLGNvbD0yKQpsaW5lcygwLjEqYWJzKHJldHVyblssMV0pLHR5cGU9ImgiLGNvbD1ncmV5KDAuNykpCgp0cy5wbG90KHNkMix5bGFiPSJTdGFuZGFyZCBkZXZpYXRpb24iLG1haW49bmFtZXNbMl0seWxpbT1jKDAsNykpCmxpbmVzKHNpZ21hcy5zdlssMl0sY29sPTIpCmxpbmVzKDAuMSphYnMocmV0dXJuWywyXSksdHlwZT0iaCIsY29sPWdyZXkoMC43KSkKYGBgCgojIyBHcmFwaGljYWwgc3VtbWFyaWVzIC0gY29ycmVsYXRpb24KCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD02LCBmaWcuYWxpZ24gPSAnY2VudGVyJ30KcGFyKG1mcm93PWMoMSwxKSkKdHMucGxvdChjb3JyLHlsaW09YygwLDEpLHlsYWI9IkNvcnJlbGF0aW9uIikKYWJsaW5lKGg9MC4yLGx0eT0yKQphYmxpbmUoaD0wLjUsbHR5PTIpCmFibGluZShoPTAuOCxsdHk9MikKYGBgCgojIER5bmFtaWMgY29uZGl0aW9uYWwgY29ycmVsYXRpb24gKERDQykgbW9kZWwKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD04LCBmaWcuYWxpZ24gPSAnY2VudGVyJ30KcHJlID0gZGNjUHJlKHJldHVybiwgaW5jbHVkZS5tZWFuID0gVCwgcCA9IDAsIGNvbmQuZGlzdCA9ICJzdGQiKQoKcHJlJGVzdAoKcmV0dXJuMSA9IHByZSRzcmVzaQoKVm9sID0gcHJlJG1hclZvbAoKZml0ID0gZGNjRml0KHJldHVybjEpCgpTMi50ID0gZml0JHJoby50CgpmaXQxID0gZGNjRml0KHJldHVybjEsdHlwZT0iRW5nbGUiKQoKUzMudCA9IGZpdDEkcmhvLnQKCk1DSGRpYWcocmV0dXJuMSxTMi50KQoKTUNIZGlhZyhyZXR1cm4xLFMzLnQpCmBgYAoKIyMgQ29tcGFyaW5nIFNWLUFSKDEpIGFuZCBHQVJDSCgxLDEpCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTAsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQpwYXIobWZyb3c9YygyLDEpKQpyYW5nZSA9IHJhbmdlKHByZSRtYXJWb2xbLDFdLHNkMSkKdHMucGxvdChwcmUkbWFyVm9sWywxXSx4bGFiPSIiLHlsYWI9IiIsbWFpbj1uYW1lc1sxXSx5bGltPXJhbmdlKQpsaW5lcyhzaWdtYXMuc3ZbLDFdLGNvbD0yKQpsZWdlbmQoInRvcHJpZ2h0IixsZWdlbmQ9YygiR0FSQ0goMSwxKSIsIlNWLUFSKDEpIiksY29sPTE6MixsdHk9MSxidHk9Im4iKQoKcmFuZ2UgPSByYW5nZShwcmUkbWFyVm9sWywyXSxzZDIpCnRzLnBsb3QocHJlJG1hclZvbFssMl0seGxhYj0iIix5bGFiPSIiLG1haW49bmFtZXNbMl0seWxpbT1yYW5nZSkKbGluZXMoc2lnbWFzLnN2WywyXSxjb2w9MikKbGVnZW5kKCJ0b3ByaWdodCIsbGVnZW5kPWMoIkdBUkNIKDEsMSkiLCJTVi1BUigxKSIpLGNvbD0xOjIsbHR5PTEsYnR5PSJuIikKYGBgCgojIyBDb21wYXJpbmcgdGltZS12YXJ5aW5nIGNvcnJlbGF0aW9ucwoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTYsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQpwYXIobWZyb3c9YygxLDEpKQpwbG90KGZpdDEkcmhvLnRbLDJdLHR5cGU9ImwiLHlsYWI9IkNvcnJlbGF0aW9uIix5bGltPWMoMCwxKSx4bGFiPSJUaW1lIikKbGluZXMoY29ycixjb2w9MikKbGVnZW5kKCJ0b3BsZWZ0IixsZWdlbmQ9YygiRENDIiwiRlNWKDEpIiksY29sPTE6MixsdHk9MSxidHk9Im4iKQp0aXRsZShwYXN0ZShuYW1lc1sxXSwiIHggIixuYW1lc1syXSxzZXA9IiIpLGNleD0wLjc1KQphYmxpbmUoaD0wLjIsbHR5PTIpCmFibGluZShoPTAuNSxsdHk9MikKYWJsaW5lKGg9MC44LGx0eT0yKQpgYGBgCg==