|
2 | 2 | from pymc import *
|
3 | 3 |
|
4 | 4 | from scipy.sparse import csc_matrix
|
| 5 | +from scipy import optimize |
5 | 6 |
|
6 |
| -#data |
| 7 | +""" |
| 8 | +1. Data |
| 9 | +------- |
| 10 | +""" |
7 | 11 | returns = np.genfromtxt("data/SP500.csv")
|
8 | 12 |
|
9 | 13 | n = 400
|
10 | 14 | returns = returns[-n:]
|
11 | 15 |
|
12 |
| -#model |
13 |
| - |
| 16 | +""" |
| 17 | +2. Build Model |
| 18 | +-------------- |
| 19 | +Stochastic volatility model described in Hoffman (2011) on p21. |
| 20 | +""" |
14 | 21 | model = Model()
|
15 | 22 | Var = model.Var
|
16 | 23 | Data = model.Data
|
17 | 24 |
|
18 |
| - |
19 |
| - |
20 |
| -sd, lsd = model.TransformedVar( |
21 |
| - 'sd', Exponential(1./.02), |
| 25 | +#its easier to sample the scale of the volatility process innovations on a log scale |
| 26 | +sd, log_sd = model.TransformedVar('sd', Exponential(1./.02), |
22 | 27 | transforms.log, testval = -2.5)
|
23 | 28 |
|
24 | 29 | nu = Var('nu', Exponential(1./10))
|
|
27 | 32 |
|
28 | 33 | lreturns = Data(returns, T(nu, lam = exp(-2*lvol)))
|
29 | 34 |
|
30 |
| - |
31 |
| - |
32 |
| -#fitting |
33 |
| - |
| 35 | +""" |
| 36 | +3. Fit Model |
| 37 | +------------ |
| 38 | +""" |
34 | 39 | H = model.d2logpc()
|
35 | 40 |
|
36 |
| -def hessian(q, nusd): |
37 |
| - h = H(q) |
| 41 | +""" |
| 42 | +To get a decent scale for the hamiltonaian sampler, we find the hessian at a point. However, the 2nd derivatives for the degrees of freedom are negative and thus not very informative, so we make an educated guess. The interactions between lsd/nu and lvol are also not very useful, so we set them to zero. |
| 43 | +
|
| 44 | +The hessian matrix is also very sparse, so we make it a sparse matrix for faster sampling. |
| 45 | +""" |
| 46 | +def hessian(point, nusd): |
| 47 | + h = H(point) |
38 | 48 | h[1,1] = nusd**-2
|
39 | 49 | h[:2,2:] = h[2:,:2] = 0
|
40 | 50 |
|
41 | 51 | return csc_matrix(h)
|
42 | 52 |
|
| 53 | +""" |
| 54 | +the full MAP is a degenerate case wrt to sd and nu, so we find the MAP wrt the volatility process, keeping log_sd and nu constant at their default values. we use l_bfgs_b because it is more efficient for high dimensional functions (lvol has n elements) |
| 55 | +""" |
43 | 56 |
|
44 |
| -from scipy import optimize |
45 | 57 | s = find_MAP(model, vars = [lvol], fmin = optimize.fmin_l_bfgs_b)
|
46 |
| -s = find_MAP(model, s, vars = [lsd, nu]) |
47 | 58 |
|
| 59 | +#we do a short initial run to get near the right area |
48 | 60 | step = hmc_step(model, model.vars, hessian(s, 6))
|
49 | 61 | trace, _,t = sample(200, step, s)
|
50 | 62 |
|
| 63 | +#then start again using a new hessian at the new start |
51 | 64 | s2 = trace.point(-1)
|
52 |
| - |
53 | 65 | step = hmc_step(model, model.vars, hessian(s2, 6), trajectory_length = 4.)
|
54 | 66 | trace, _,t = sample(4000, step, trace = trace)
|
55 | 67 |
|
| 68 | +""" |
| 69 | +4. References |
| 70 | +------------- |
| 71 | + 1. Hoffman & Gelman. (2011). The No-U-Turn Sampler: Adaptively Setting Path Lengths in Hamiltonian Monte Carlo. http://arxiv.org/abs/1111.4246 |
| 72 | +""" |
0 commit comments