Ornstein Uhlenbeck process

class quantfinlib.sim.OrnsteinUhlenbeck(mean=0.0, mrr=1.0, vol=0.1, cor=None)

Bases: SimBase, SimNllMixin

A class for simulating the mean-reverting Ornstein-Uhlenbeck process.

The Ornstein-Uhlenbeck process is a continuous-time stochastic mean-reverting process. In finance, it is commonly used to model time series that tend to mean-revert to som e long term mean like interest rates, volatility and some commodities.

Below an example of 10 Ornstein-Uhlenbeck paths:

Examples

Generate 10 Ornstein-Uhlenbeck motion paths. All paths start at 1, have a long term mean of 4, a mean reversion rate of 2, and a volatility of 1. We simulate 252 timesteps.

from quantfinlib.sim import OrnsteinUhlenbeck

model = OrnsteinUhlenbeck(mean=4, mrr=2, vol=1)
paths = model.path_sample(
    x0=1,
    label_start='2020-01-01',
    label_freq='B',
    num_steps=252,
    num_paths=10
)

print(paths)
                 S_0       S_1       S_2  ...       S_7       S_8       S_9
2020-01-01  1.000000  1.000000  1.000000  ...  1.000000  1.000000  1.000000
2020-01-02  0.919154  0.965448  1.023299  ...  0.980354  1.108555  0.903668
2020-01-03  1.007359  0.867752  0.952275  ...  0.996325  1.105968  0.924980
2020-01-06  0.908543  0.856959  1.070149  ...  0.944215  1.134630  0.955399
2020-01-07  0.944982  0.909189  1.150446  ...  1.056977  1.223049  0.893311
...              ...       ...       ...  ...       ...       ...       ...
2020-12-14  3.908057  2.600729  3.119261  ...  3.689857  3.228736  2.942655
2020-12-15  3.910446  2.648233  3.128725  ...  3.673271  3.320162  3.013343
2020-12-16  3.834102  2.614061  3.168067  ...  3.753988  3.408200  3.000749
2020-12-17  3.901277  2.562282  3.238122  ...  3.841879  3.403761  3.037872
2020-12-18  3.822642  2.540020  3.320001  ...  3.873465  3.379697  2.996597

[253 rows x 10 columns]

(Source code, html)

Properties and Limitations

  • The mean (\(\mu\)), mean reversion rate (\(\lambda\)) and volatility (\(\sigma\)) are considered constant over time.

  • Simulated values can be both positive and negative.

  • The Ornstein-Uhlenbeck assumes a continuous path.

Use Cases in Finance

The Ornstein-Uhlenbeck process is popular in finance:

  • Modeling short term interest rate. In this setting the model is also known as the Vasicek model.

Details

The stochastic differential equation (SDE) for Brownian motion is:

\[dX_t = \Theta(\mu - X_t) dt + \sigma dW_t\]

where:

  • \(dX_t\) is the change in the process X at time t,

  • \(\Theta\) the annualized mean-reversion rate,

  • \(\mu\) the long-term mean,

  • \(\sigma\) is the volatility coefficient (annualized volatility rate),

  • \(dW_t\) is a Wiener process (standard Brownian motion).

  • todo: explain that sigma is a cov when MV

Simulation

For path simulations we use the exact solution of the discretize SDE:

\[X[t + dt] = \mu + (X[t] - \mu) e^{-\Theta dt} + % \sqrt{\frac{\sigma^2}{2\Theta}\left(1 - e^{-2\Theta dt} \right) } \mathcal{N}(0,1)\]

where:

  • \(dt\) the time-step size.

Calibration

For fitting we use a linear regession based on the simulation equation

\[X[t + dt] = a X[t] + b + c N(0,1)\]

where:

\[\begin{split}\begin{align} a &= e^{-\lambda dt} \\ b &= \mu(1 - e^{-\lambda dt}) \\ c &= \sqrt{\frac{\sigma^2}{2\lambda}\left(1 - e^{-2\lambda dt} \right) } \end{align}\end{split}\]

\(a, b\) are estimated with least squares regression, and \(c\) is estimated from the regression residuals. The residuals are also used to estimate the correlations if the data is multi-variate. From these estimates the Ornstein-Uhlenbeck parameters are derived as follows:

\[\begin{split}\begin{align} \lambda &= -\frac{\ln(a)}{dt} \\ \mu &= \frac{b}{1-a} \\ \sigma &= \sqrt{ \frac{2 \lambda c^2}{1 - a^2} } \end{align}\end{split}\]

Member functions

__init__(mean=0.0, mrr=1.0, vol=0.1, cor=None)

Initializes the BrownianMotion instance with specified drift and volatility.

Parameters:
  • mean (float, optional) – The long term mean (default is 0.0).

  • mrr (float, optional) – The annualized mean reversion rat (default is 0.1).

  • vol (float, optional) – The annualized volatility (default is 0.1).

  • cor (optional) – Correlation matrix for multivariate model (default is None, uncorrelated).

aic(x: ndarray | DataFrame | Series, dt: float | None = None) float

Calculate the Akaike Information Criterion (AIC) for a given path.

Parameters:
  • x (Union[np.ndarray, pd.DataFrame, pd.Series]) – The input data for AIC calculation.

  • dt (Optional[float]) – The time step between observations.

Returns:

aic – The computed Akaike Information Criterion (AIC) value.

Return type:

float

bic(x: ndarray | DataFrame | Series, dt: float | None = None) float

Calculate the Bayesian Information Criterion (BIC) for a given path.

Parameters:
  • x (Union[np.ndarray, pd.DataFrame, pd.Series]) – The input data for BIC calculation.

  • dt (Optional[float]) – The time step between observations.

Returns:

bic – The computed Bayesian Information Criterion (BIC) value.

Return type:

float

fit(x: ndarray | DataFrame | Series, dt: float | None = None, **kwargs)

Calibrates the model to the given path(s).

Parameters:
  • x (Union[np.ndarray, pd.DataFrame, pd.Series]) – The input data for calibration.

  • dt (Optional[float]) – The time step between observations.

  • **kwargs – Additional arguments for the fit process.

Returns:

self – The fitted model instance.

Return type:

Self

nll(x: ndarray | DataFrame | Series, dt: float | None = None) float

Calculate the negative log-likelihood (lower is better) for a given path.

Parameters:
  • x (Union[np.ndarray, pd.DataFrame, pd.Series]) – The input data for negative log-likelihood calculation.

  • dt (Optional[float]) – The time step between observations.

Returns:

nll – The computed negative log-likelihood.

Return type:

float

path_sample(x0: float | ndarray | DataFrame | Series | str | None = None, dt: float | None = None, num_steps: int | None = 252, num_paths: int | None = 1, label_start=None, label_freq: str | None = None, columns: List[str] | None = None, random_state: int | None = None, include_x0: bool = True) ndarray | DataFrame | Series

Simulates random paths.

Parameters:
  • x0 (Optional[Union[float, np.ndarray, pd.DataFrame, pd.Series, str]], optional) – The initial value(s) of the paths (default is None). The strings “first” and “last” will set x0 to the first or last value of the datasets used in a fit() call.

  • dt (Optional[float], optional) – The time step between observations (default is None). If dt is not specfied a values will be picked based on the bollowing fall-backs: * if label_freq is specfied dt will based on that * if the model is fitted with fit() the value of dt used during fitting is used * else dt will default to 1 / 252.

  • num_steps (Optional[int], optional) – The number of time steps to simulate (default is 252).

  • num_paths (Optional[int], optional) – The number of paths to simulate (default is 1).

  • label_start (optional, date-time like.) – The date-time start label for the simulated paths (default is None). When set, this function will return Pandas DataFrame with a DateTime index.

  • label_freq (Optional[str], optional) – The frequency for labeling the time steps (default is None).

  • columns (Optional[List[str]], optional) – A list of column names.

  • random_state (Optional[int], optional) – The seed for the random number generator (default is None).

  • include_x0 (bool, optional) – Whether to include the initial value in the simulated paths (default is True).

Returns:

The simulated random paths.

Return type:

Union[np.ndarray, pd.DataFrame, pd.Series]