Ornstein Uhlenbeck process
- class quantfinlib.sim.OrnsteinUhlenbeck(mean=0.0, mrr=1.0, vol=0.1, cor=None)
Bases:
SimBase,SimNllMixinA 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]