Algostream_advanced_models.Ornstein_uhlenbeckOrnstein-Uhlenbeck continuous-time mean-reverting process modeling.
SDE: dr = theta * (mu - r) dt + sigma * dW. Calibration uses the exact discrete-time transition at fixed time step dt: r at (t + dt) given r at t is Gaussian with mean mu + (r - mu) * exp(-theta * dt) and variance sigma^2 * (1 - exp(-2 * theta * dt)) / (2 * theta). The continuous-time half-life is ln(2) / theta.
fit returns Error `Non_reverting if the AR(1) slope is outside (0, 1) — i.e., the series shows no mean-reversion at the supplied dt. Use Pairs.Mean_reversion.half_life for the discrete-time alternative on residuals.
type fit_error = [ | `Insufficient_data of int * int| `Non_reverting| `Ols of Algostream_pairs.Ols.error ]val fit :
series:float array ->
dt:float ->
(fit_result, fit_error) Stdlib.resultval expected_value : params -> r0:float -> t:float -> floatE[r_t | r_0] = μ + (r_0 − μ) · e^{−θ t}.
val expected_variance : params -> t:float -> floatVar[r_t | r_0] = σ² (1 − e^{−2θ t}) / (2θ).
val simulate :
params ->
n:int ->
dt:float ->
seed:int ->
r0:float ->
float arraySimulate n steps at uniform dt starting from r0, using the exact Gaussian transition. seed makes the trajectory reproducible.
Trajectories are not comparable across the RNG change. This draws from Algostream_rng; an earlier implementation used Math_utils.FastRandom, whose constructor seeds only one of four state words and leaves the rest at fixed constants — so nearby seeds produced visibly correlated paths, and a uniform draw of exactly 0.0 could turn a sample into nan. It now draws from Algostream_rng.Rng, which has neither defect. Same signature, same statistical contract, different numbers for a given seed. No test pinned the old values (they assert run-twice equality and ±30% parameter recovery), but any external result generated by that earlier implementation will not reproduce bit-for-bit.
val simulate_with :
params ->
rng:Algostream_rng.Rng.t ->
n:int ->
dt:float ->
r0:float ->
float arrayAs simulate, but driven by a caller-owned generator. Use this inside a Monte Carlo worker so every path in a batch draws from Rng.substream ~root_seed ~index and is therefore reproducible independently of how many Domains run the batch.