Estimating Mean-Reversion Half-Life with an Intercept
Summary
The document describes estimating the half-life of a mean-reverting series using an Ornstein–Uhlenbeck-style regression. The proposed approach forms lagged values and changes, regresses the changes on the lagged series, and converts the fitted coefficient into a half-life estimate. The original regression omits a constant, which the author finds produces an estimate inconsistent with the apparent speed of reversion in the plotted data. Adding an intercept to the regression resolves that reported discrepancy.
The author reports that the estimate changes from 680.5 days to 15 days after including the intercept. This is a practical warning about regression specification when estimating reversion speed. The exchange does not validate the series’ mean-reverting behavior, assess statistical uncertainty, or address sampling frequency and model fit; the reported estimate should therefore be understood as the outcome for this example rather than a general guarantee.
Key ideas
- A common half-life estimate regresses series changes on lagged series values and transforms the fitted slope.
- The example’s initial regression omits an intercept, which leads to an implausible reported half-life.
- Including an intercept changes the reported estimate substantially in this case.
- A plausible estimate from one regression does not establish that the series follows an Ornstein–Uhlenbeck process.
Tags
Full text
# Calculating half life of mean reverting series with python # Calculating half life of mean reverting series with python 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: 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! ## Answer by s666 (score 16, accepted) https://quant.stackexchange.com/a/25119 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!
Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.