10
$\begingroup$

I am currently attempting to calculate the halflife of a mean reverting series using python programming language and the theory of the Ornstein–Uhlenbeck process.

I have a series which when plotted looks like:

Mean reverting series

Which obviously looks rather mean reverting. I am carrying out the following using python code to find the halflife (FYI the series shown above is held in the variable (z_array):

import numpy as np
import statsmodels.api as sm

#set up lagged series of z_array and return series of z_array
z_lag = np.roll(z_array,1)
z_lag[0] = 0
z_ret = z - z_lag
z_ret[0] = 0

#run OLS regression to find regression coefficient to use as "theta"
model = sm.OLS(z_ret,z_lag)
res = model.fit()

#calculate halflife
halflife = -log(2) / res.params[0]
print  'Halflife = ',halflife

The code runs fine, however for this series I am getting a halflife of 680.5 days - I can see from the chart that this looks very wrong. Full reversions are happening within a fraction of that time frame.

Could someone please advise me as to where I am going wrong with this?

Any help much appreciated!

$\endgroup$
2
  • 1
    $\begingroup$ It is hard to say what value "looks right" looking at the chart, I would plot the scatter diagram and see if the regression line through it "looks right". $\endgroup$
    – nbbo2
    Commented Mar 28, 2016 at 16:33
  • $\begingroup$ I found out what was wrong - I had to use the add_constant method to add an intercept term to the regression, then use res.params[1]. Thanks for your reply anyway - much appreciated indeed! $\endgroup$
    – s666
    Commented Mar 28, 2016 at 19:56

1 Answer 1

16
$\begingroup$

I found out what I was doing wrong - the OLS function was regressing with no intercept value - so I had to use the "add_constant" method to add an intercept term to the X series (z_lag) as follows:

z_lag = np.roll(z_array,1)
z_lag[0] = 0
z_ret = z_array - z_lag
z_ret[0] = 0

#adds intercept terms to X variable for regression
z_lag2 = sm.add_constant(z_lag)

model = sm.OLS(z_ret,z_lag2)
res = model.fit()

halflife = -log(2) / res.params[1]

I'm now getting a more resonable halflife of 15 days!

$\endgroup$
2
  • 2
    $\begingroup$ Hi there, according to this link, the estimation of half life from an AR(1) process should instead be log(0.5)/log(numpy.abs(res.params[1])). This derivation is typical from the ARMA methods. from OU process, have the result of $\log{2}$ / $\alpha$ where $\alpha > 0$ is the speed of mean reversion. mathtopics.wordpress.com/2013/01/10/… $\endgroup$
    – WillZ
    Commented Nov 21, 2016 at 2:21
  • 1
    $\begingroup$ second link for OU process half life: mathtopics.wordpress.com/2013/01/07/ornstein-uhlenbeck-process $\endgroup$
    – WillZ
    Commented Nov 21, 2016 at 2:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.