In [1]:
import numpy as np
import pymc3 as pm
from pymc3.distributions.timeseries import GaussianRandomWalk
from scipy import optimize
%pylab inline
Asset prices have time-varying volatility (variance of day over day returns
). In some periods, returns are highly variable, while in others very stable. Stochastic volatility models model this with a latent volatility variable, modeled as a stochastic process. The following model is similar to the one described in the No-U-Turn Sampler paper, Hoffman (2011) p21.
Here, $y$ is the daily return series and $s$ is the latent log volatility process.
First we load some daily returns of the S&P 500.
In [2]:
n = 400
returns = np.genfromtxt(pm.get_data("SP500.csv"))[-n:]
returns[:5]
Out[2]:
In [3]:
plt.plot(returns)
Out[3]:
Specifying the model in pymc3 mirrors its statistical specification.
In [4]:
model = pm.Model()
with model:
sigma = pm.Exponential('sigma', 1./.02, testval=.1)
nu = pm.Exponential('nu', 1./10)
s = GaussianRandomWalk('s', sigma**-2, shape=n)
r = pm.StudentT('r', nu, lam=pm.math.exp(-2*s), observed=returns)
For this model, the full maximum a posteriori (MAP) point is degenerate and has infinite density. To get good convergence with NUTS we use ADVI (autodiff variational inference) for initialization.
In [9]:
with model:
trace = pm.sample(2000, tune=1000)[1000:]
In [10]:
figsize(12,6)
pm.traceplot(trace, model.vars[:-1]);
In [11]:
figsize(12,6)
title(str(s))
plot(trace[s][::10].T, 'b', alpha=.03);
xlabel('time')
ylabel('log volatility')
Out[11]:
Looking at the returns over time and overlaying the estimated standard deviation we can see how the model tracks the volatility over time.
In [12]:
plot(np.abs(returns))
plot(np.exp(trace[s][::10].T), 'r', alpha=.03);
sd = np.exp(trace[s].T)
xlabel('time')
ylabel('absolute returns')
Out[12]: