stochastic-rs
Getting started

Quickstart

A 5-minute end-to-end tour — simulate an OU path, price a Heston call, and run a Hurst estimator. Same code shown in Rust and Python side by side.

Quickstart

Three vignettes, each shown in Rust and Python. Pick whichever language you are working in — the API surface is intentionally close.

1. Simulate an OU path

The Ornstein-Uhlenbeck process

dXt=θ(μ−Xt) dt+σ dWt,X0=x0dX_t = \theta(\mu - X_t)\,dt + \sigma\,dW_t,\quad X_0 = x_0

with θ=2\theta = 2, μ=0\mu = 0, σ=1\sigma = 1, X0=0X_0 = 0, on t∈[0,1]t \in [0, 1] with 1000 steps:

Rust

tests/doctest_quickstart_ou.rs
// docs: getting-started/quickstart#1-simulate-an-ou-path
//! Backs vignette 1 (simulate an OU path) on the quickstart page.

use stochastic_rs::prelude::*;
use stochastic_rs::simd_rng::Unseeded;
use stochastic_rs::stochastic::diffusion::ou::Ou;

#[test]
fn simulate_an_ou_path() {
  let p = Ou::<f64, _>::new(2.0, 0.0, 1.0, 1_000, Some(0.0), Some(1.0), Unseeded);
  let path = p.sample();
  assert_eq!(path.len(), 1_000);
  assert!(path.mean().unwrap().is_finite());
}

Python

import stochastic_rs as srs

p = srs.PyOu(theta=2.0, mu=0.0, sigma=1.0, n=1000, x0=0.0, t=1.0)
path = p.sample()
print("len =", path.shape[0], "mean =", path.mean())

For the API contract see the Processes catalog.

2. Price a Heston European call

The Heston model is the workhorse stochastic-volatility model. The Fourier pricer uses Cui's analytic Jacobian for fast and stable characteristic-function evaluation.

Rust

tests/doctest_quickstart_heston.rs
// docs: getting-started/quickstart#2-price-a-heston-european-call
//! Backs vignette 2 (price a Heston European call) on the quickstart
//! page.

use stochastic_rs::prelude::*;
use stochastic_rs::quant::OptionType;
use stochastic_rs::quant::pricing::heston::HestonPricer;

#[test]
fn price_a_heston_european_call() {
  let model = HestonPricer::new(
    /* v0 */ 0.04, /* rho */ -0.5, /* kappa */ 2.0, /* theta */ 0.04,
    /* sigma */ 0.3, /* lambda */ None,
  );
  let (s, k, r, q, tau) = (100.0, 100.0, 0.03, 0.0, 1.0);

  let price = model.price_call(s, k, r, q, tau);
  let greeks = model.greeks(s, k, r, q, tau, OptionType::Call);
  assert!(price > 0.0);
  assert!(greeks.vega > 0.0);
}

Python

import stochastic_rs as srs

pricer = srs.HestonPricer(
    s=100, v0=0.04, k=100, r=0.03, kappa=2.0, theta=0.04, sigma=0.3,
    rho=-0.5, tau=1.0, q=0.0,
)
call, put = pricer.call_put()
print(f"call={call:.4f}, put={put:.4f}")

3. Estimate Hurst from a fractional-Brownian path

The hurst module's HurstEstimator trait unifies six estimators. This vignette uses the rescaled-range estimator (Hurst 1951 + Anis-Lloyd 1976 bias correction) directly on a sampled path — see the statistics catalog page for why the Fukasawa/Whittle estimator (also in this module) is the wrong tool for that job: it estimates latent-volatility roughness from a realized-variance series, not the Hurst exponent of a raw path.

Rust

tests/doctest_quickstart_hurst.rs
// docs: getting-started/quickstart#3-estimate-hurst-from-a-fractional-brownian-path
//! Backs vignette 3 (estimate Hurst) on the quickstart page. Uses the
//! rescaled-range estimator — see `doctest_stats_hurst.rs` for why the
//! Fukasawa/Whittle one is the wrong tool for a raw sampled path.

use stochastic_rs::simd_rng::Deterministic;
use stochastic_rs::stats::hurst::HurstEstimator;
use stochastic_rs::stats::hurst::rs::RescaledRange;
use stochastic_rs::stochastic::noise::fgn::Fgn;
use stochastic_rs::traits::ProcessExt;

#[test]
fn estimate_hurst_from_a_fractional_brownian_path() {
  let fgn = Fgn::<f64, _>::new(0.3, 4096, Some(1.0), Deterministic::new(7));
  let path = fgn.sample();

  let estimator = RescaledRange {
    take_differences: false,
    ..RescaledRange::default()
  };
  let est = estimator.estimate(path.view()).unwrap();
  assert!((est.hurst - 0.3).abs() < 0.1, "H = {:.3}", est.hurst);
}

Python

import stochastic_rs as srs
import numpy as np

# Mirrors the Rust vignette above: R/S on the cumulated path.
fgn = srs.PyFgn(hurst=0.3, n=4096, t=1.0, seed=7)
fbm = np.cumsum(fgn.sample())
res = srs.RescaledRange().estimate(fbm)
print(f"H = {res.hurst:.3f} (true 0.3)")

Where next

On this page