1 Introduction

Volatility is a major driven factor for the price of underlying assets. “Stochastic volatility models are those in which the variance of a stochastic process is itself randomly distributed.”[1] There are many popular stochastic volatility models: Heston model, CEV model, SABR model etc. In this project, we are going to use pomp to study the performance of Heston model on Dow Jones Industrial Average Index, which is a stock market index.



2 Data Introduction

setwd("~/Desktop/531-final")
dow=read.csv(file = "dow.csv",header = T)
dow_log=diff(log(dow$Adj_Close))
dow_hp=dow_log-mean(dow_log)
par(mfrow=c(1,2))
plot(dow$Adj_Close,type='l',main="Adjusted Dow-Jones")
plot(dow_hp,type = 'l',main="Demeaned log return")



3 Heston model



4 Building a POMP model

require(pomp)

dow_statenames <- c("V","Y_state")
dow_rp_names <- c("sigma_omega","phi","theta")
dow_ivp_names <- c("V_0")
dow_paramnames <- c(dow_rp_names,dow_ivp_names)
dow_covarnames <- "covaryt"

rproc1 <- "
  double omega;
  omega = rnorm(0,sigma_omega);
  V = theta*(1 - phi) + phi*sqrt(V) + sqrt(V)*omega;
"
rproc2.sim <- "
  Y_state = rnorm( 0,sqrt(V) );
 "
rproc2.filt <- "
  Y_state = covaryt;
 "
dow_rproc.sim <- paste(rproc1,rproc2.sim)
dow_rproc.filt <- paste(rproc1,rproc2.filt)
dow_initializer <- "
  V = V_0;
  Y_state = rnorm( 0,sqrt(V) );
"
dow_rmeasure <- "
   y=Y_state;
"
dow_dmeasure <- "
   lik=dnorm(y,0,sqrt(V),give_log);
"
dow_toEstimationScale <- "
  Tsigma_omega = log(sigma_omega);
  Ttheta = log(theta);
  Tphi = logit(phi);
"
dow_fromEstimationScale <- "
  Tsigma_omega = exp(sigma_omega);
  Ttheta = exp(theta);
  Tphi = expit(phi);
"
##----------test for parameters--------------##
dow.filt <- pomp(data=data.frame(y=dow_hp,
                     time=1:length(dow_hp)),
              statenames=dow_statenames,
              paramnames=dow_paramnames,
              covarnames=dow_covarnames,
              times="time",
              t0=0,
              covar=data.frame(covaryt=c(0,dow_hp),
                     time=0:length(dow_hp)),
              tcovar="time",
              rmeasure=Csnippet(dow_rmeasure),
              dmeasure=Csnippet(dow_dmeasure),
              rprocess=discrete.time.sim(step.fun=Csnippet(dow_rproc.filt),delta.t=1),
              initializer=Csnippet(dow_initializer),
              toEstimationScale=Csnippet(dow_toEstimationScale), 
              fromEstimationScale=Csnippet(dow_fromEstimationScale)
)

expit<-function(real){1/(1+exp(-real))}
logit<-function(p.arg){log(p.arg/(1-p.arg))}

params_test <- c(
     sigma_omega = 0.001,  
     phi = 0.001,
     theta = 0.0004,
     V_0= 0.002
  )

sim1.sim <- pomp(dow.filt, 
               statenames=dow_statenames,
               paramnames=dow_paramnames,
               covarnames=dow_covarnames,
               rprocess=discrete.time.sim(step.fun=Csnippet(dow_rproc.sim),delta.t=1)
)

sim1.sim <- simulate(sim1.sim,seed=1,params=params_test)
plot(Y_state~time,data=sim1.sim,type='l',col="red",ylim=c(-0.06,0.1))
lines(dow_hp,type='l')
legend("topleft",legend=c("Original","Simulated"),col=c("black","red"),
       cex=0.8,lty=1,bty="n")

par(mfrow=c(1,2))
plot(V~time,data=sim1.sim,type='l',main="Simulated Volatility")
plot(Y_state~time,data=sim1.sim,type='l',main="Simulated Y_state")

#plot(sim1.sim)


5 Filtering on simulated data

##--------filtering on simulated data----------
run_level <- 1 
dow_Np <-          c(100,1e3,5e3)
dow_Nmif <-        c(10, 100,200)
dow_Nreps_eval <-  c(4,  10,  20)
dow_Nreps_local <- c(10, 20, 20)
dow_Nreps_global <-c(10, 20, 40)
require(doParallel)
registerDoParallel(2)
sim1.filt <- pomp(sim1.sim, 
  covar=data.frame(
    covaryt=c(obs(sim1.sim),NA),
    time=c(timezero(sim1.sim),time(sim1.sim))),
  tcovar="time",
  statenames=dow_statenames,
  paramnames=dow_paramnames,
  covarnames=dow_covarnames,
  rprocess=discrete.time.sim(step.fun=Csnippet(dow_rproc.filt),delta.t=1)
)

stew(file=sprintf("pf1.rda",run_level),{
  t.pf1 <- system.time(
    pf1 <- foreach(i=1:dow_Nreps_eval[run_level],.packages='pomp',
                   .options.multicore=list(set.seed=TRUE)) %dopar% try(
                     pfilter(sim1.filt,Np=dow_Np[run_level])
                   )
  )
},seed=493536993,kind="L'Ecuyer")
(L.pf1 <- logmeanexp(sapply(pf1,logLik),se=TRUE))
##                        se 
## 823.82018907   0.01162847


6 Fitting the stochastic volatility model to Dow-Jones data

##---------Fitting the stochastic leverage model to Dow-Jones data------------
run_level <- 3 
dow_Np <-          c(100,1e3,5e3)
dow_Nmif <-        c(10, 100,200)
dow_Nreps_eval <-  c(4,  10,  20)
dow_Nreps_local <- c(10, 20, 20)
dow_Nreps_global <-c(10, 20, 40)

dow_rw.sd_rp <- 0.001
dow_rw.sd_ivp <- 0.001
dow_cooling.fraction.50 <- 0.5

params_test <- c(
     sigma_omega = 0.001,  
     phi = 0.001,
     theta = 1,
     V_0= 0.02
  )

stew(file=sprintf("mif1-%d.rda",run_level),{
   t.if1 <- system.time({
   if1 <- foreach(i=1:dow_Nreps_global[run_level],
                  .packages='pomp', .combine=c,
                  .options.multicore=list(set.seed=TRUE)) %dopar% try(
                    mif2(dow.filt,
                         start=params_test,
                         Np=dow_Np[run_level],
                         Nmif=dow_Nmif[run_level],
                         cooling.type="geometric",
                         cooling.fraction.50=dow_cooling.fraction.50,
                         transform=TRUE,
                         rw.sd = rw.sd(
                            sigma_omega  = dow_rw.sd_rp,
                            theta      = dow_rw.sd_rp,
                            phi       = dow_rw.sd_rp,
                            V_0       = ivp(dow_rw.sd_ivp)
                         )
                    )
                  )
   L.if1 <- foreach(i=1:dow_Nreps_global[run_level],.packages='pomp',
                      .combine=rbind,.options.multicore=list(set.seed=TRUE)) %dopar% 
                      {
                        logmeanexp(
                          replicate(dow_Nreps_eval[run_level],
                                    logLik(pfilter(dow.filt,params=coef(if1[[i]]),Np=dow_Np[run_level]))
                          ),
                          se=TRUE)
                      }
    
  })
},seed=318817883,kind="L'Ecuyer")

r.if1 <- data.frame(logLik=L.if1[,1],logLik_se=L.if1[,2],t(sapply(if1,coef)))
if (run_level>1) 
  write.table(r.if1,file="dow_params.csv",append=TRUE,col.names=FALSE,row.names=FALSE)
summary(r.if1$logLik,digits=5)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  300.03  310.92  314.83  314.72  318.61  325.90
r.if1[which.max(r.if1$logLik),]
##             logLik   logLik_se  sigma_omega          phi   theta
## result.37 325.9047 0.000182989 0.0009329165 0.0009294475 0.02147
##                  V_0
## result.37 0.01934202
pairs(~logLik+sigma_omega+theta+phi,data=r.if1)

plot(if1)



7 Likelihood maximization using randomized starting values

##--------Likelihood maximization using randomized starting values--------

dow_box <- rbind(
  sigma_omega=c(0.001,0.005),
  theta    = c(0.9,1),
  phi = c(0.001,0.005),
  V_0 = c(0.02,0.03)
)

stew(file=sprintf("box_eval-%d.rda",run_level),{
  t.box <- system.time({
    if.box <- foreach(i=1:dow_Nreps_global[run_level],.packages='pomp',.combine=c,
                  .options.multicore=list(set.seed=TRUE)) %dopar%  
      mif2(
        if1[[1]],
        start=apply(dow_box,1,function(x)runif(1,x[1],x[2]))
      )
    
    L.box <- foreach(i=1:dow_Nreps_global[run_level],.packages='pomp',.combine=rbind,
                      .options.multicore=list(set.seed=TRUE)) %dopar% {
                        set.seed(87932+i)
                        logmeanexp(
                          replicate(dow_Nreps_eval[run_level],
                                    logLik(pfilter(dow.filt,params=coef(if.box[[i]]),Np=dow_Np[run_level]))
                          ), 
                          se=TRUE)
                      }
  })
},seed=290860873,kind="L'Ecuyer")

r.box <- data.frame(logLik=L.box[,1],logLik_se=L.box[,2],t(sapply(if.box,coef)))
if(run_level>1) write.table(r.box,file="dow_params.csv",append=TRUE,col.names=FALSE,row.names=FALSE)
summary(r.box$logLik,digits=5)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  303.46  318.07  324.55  322.55  328.52  339.65
r.box[which.max(r.box$logLik),]
##             logLik    logLik_se sigma_omega      theta         phi
## result.31 339.6471 0.0006702892  0.00353226 0.01948088 0.003015225
##                  V_0
## result.31 0.03219206
pairs(~logLik+sigma_omega+theta+phi+V_0,data=r.box)

plot(if.box)



8 Benchmark likelihoods for GARCH models

library(tseries)
L.garch.benchmark = logLik(garch(dow_hp))
## 
##  ***** ESTIMATION WITH ANALYTICAL GRADIENT ***** 
## 
## 
##      I     INITIAL X(I)        D(I)
## 
##      1     8.836655e-05     1.000e+00
##      2     5.000000e-02     1.000e+00
##      3     5.000000e-02     1.000e+00
## 
##     IT   NF      F         RELDF    PRELDF    RELDX   STPPAR   D*STEP   NPRELDF
##      0    1 -1.347e+03
##      1    8 -1.347e+03  1.83e-04  3.41e-04  4.9e-05  1.9e+10  4.9e-06  3.26e+06
##      2    9 -1.347e+03  5.77e-07  6.69e-07  4.9e-05  2.0e+00  4.9e-06  2.47e+00
##      3   17 -1.351e+03  3.19e-03  4.84e-03  4.4e-01  2.0e+00  8.0e-02  2.46e+00
##      4   20 -1.358e+03  4.82e-03  4.59e-03  7.4e-01  1.7e+00  3.2e-01  1.43e-01
##      5   22 -1.359e+03  1.10e-03  1.04e-03  7.8e-02  2.0e+00  6.4e-02  4.61e+00
##      6   34 -1.360e+03  1.02e-04  1.04e-03  7.7e-06  2.5e+00  6.7e-06  4.45e+00
##      7   35 -1.360e+03  2.77e-04  2.34e-04  3.2e-06  2.0e+00  3.4e-06  2.40e+00
##      8   36 -1.360e+03  6.16e-06  9.70e-06  3.7e-06  2.0e+00  3.4e-06  2.90e+00
##      9   45 -1.363e+03  2.42e-03  3.89e-03  2.0e-01  2.0e+00  2.2e-01  2.82e+00
##     10   57 -1.364e+03  4.74e-04  9.04e-04  1.8e-06  3.5e+00  2.3e-06  1.43e-03
##     11   58 -1.364e+03  5.43e-06  5.74e-06  1.7e-06  2.0e+00  2.3e-06  1.02e-04
##     12   64 -1.364e+03  6.28e-09  2.36e-07  2.6e-08  2.6e+00  3.4e-08  1.18e-04
##     13   75 -1.364e+03 -6.02e-14  6.76e-14  1.5e-14  9.2e+05  1.9e-14  1.17e-04
## 
##  ***** FALSE CONVERGENCE *****
## 
##  FUNCTION    -1.363890e+03   RELDX        1.486e-14
##  FUNC. EVALS      75         GRAD. EVALS      13
##  PRELDF       6.762e-14      NPRELDF      1.171e-04
## 
##      I      FINAL X(I)        D(I)          G(I)
## 
##      1    1.280051e-05     1.000e+00     4.740e+03
##      2    2.237690e-01     1.000e+00     6.291e+00
##      3    6.545035e-01     1.000e+00    -4.166e+00
L.garch.benchmark
## 'log Lik.' 1064.316 (df=3)


9 Conclusion



10 Reference

[1] “Stochastic volatility”, https://en.wikipedia.org/wiki/Stochastic_volatility#Heston_model

[2]&[3] “Heston model”, https://en.wikipedia.org/wiki/Heston_model

[4] David Backus, Silvio Foresi, Chris I. Telmer, 1998. Discrete Time Models of Bond Pricing. http://repository.cmu.edu/cgi/viewcontent.cgi?article=1504&context=tepper

[5] Edward Ionides, 2016. Case study: POMP modeling to investigate financial volatility. http://ionides.github.io/531w16/notes15/notes15.html#benchmark-likelihoods-for-alternative-models