Skip to content

Commit

Permalink
feat: rework api for cleaner code
Browse files Browse the repository at this point in the history
  • Loading branch information
dancixx committed Jul 25, 2024
1 parent ef9e0d0 commit ebe8480
Show file tree
Hide file tree
Showing 31 changed files with 1,050 additions and 910 deletions.
106 changes: 25 additions & 81 deletions src/diffusions/cir.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use crate::{
noises::{fgn::FgnFft, gn},
utils::Generator,
};
use crate::noises::gn;
use ndarray::Array1;

/// Generates a path of the Cox-Ingersoll-Ross (CIR) process.
Expand Down Expand Up @@ -31,18 +28,30 @@ use ndarray::Array1;
/// ```
/// let cir_path = cir(0.5, 0.02, 0.1, 1000, Some(0.01), Some(1.0), Some(false));
/// ```
pub fn cir(
theta: f64,
mu: f64,
sigma: f64,
n: usize,
x0: Option<f64>,
t: Option<f64>,
use_sym: Option<bool>,
) -> Array1<f64> {
if 2.0 * theta * mu < sigma.powi(2) {
panic!("2 * theta * mu < sigma^2")
}
#[derive(Default)]
pub struct Cir {
pub theta: f64,
pub mu: f64,
pub sigma: f64,
pub n: usize,
pub x0: Option<f64>,
pub t: Option<f64>,
pub use_sym: Option<bool>,
}

pub fn cir(params: &Cir) -> Array1<f64> {
let Cir {
theta,
mu,
sigma,
n,
x0,
t,
use_sym,
} = *params;

assert!(2.0 * theta * mu < sigma.powi(2), "2 * theta * mu < sigma^2");

let gn = gn::gn(n - 1, Some(t.unwrap_or(1.0)));
let dt = t.unwrap_or(1.0) / n as f64;
Expand All @@ -60,68 +69,3 @@ pub fn cir(

cir
}

/// Generates a path of the fractional Cox-Ingersoll-Ross (fCIR) process.
///
/// The fCIR process incorporates fractional Brownian motion, which introduces long-range dependence.
///
/// # Parameters
///
/// - `hurst`: Hurst parameter for fractional Brownian motion, must be in (0, 1).
/// - `theta`: Speed of mean reversion.
/// - `mu`: Long-term mean level.
/// - `sigma`: Volatility parameter.
/// - `n`: Number of time steps.
/// - `x0`: Initial value of the process (optional, defaults to 0.0).
/// - `t`: Total time (optional, defaults to 1.0).
/// - `use_sym`: Whether to use symmetric noise (optional, defaults to false).
///
/// # Returns
///
/// A `Array1<f64>` representing the generated fCIR process path.
///
/// # Panics
///
/// Panics if `hurst` is not in (0, 1).
/// Panics if `2 * theta * mu < sigma^2`.
///
/// # Example
///
/// ```
/// let fcir_path = fcir(0.75, 0.5, 0.02, 0.1, 1000, Some(0.01), Some(1.0), Some(false));
/// ```
#[allow(clippy::too_many_arguments)]
pub fn fcir(
hurst: f64,
theta: f64,
mu: f64,
sigma: f64,
n: usize,
x0: Option<f64>,
t: Option<f64>,
use_sym: Option<bool>,
) -> Array1<f64> {
if !(0.0..1.0).contains(&hurst) {
panic!("Hurst parameter must be in (0, 1)")
}

if 2.0 * theta * mu < sigma.powi(2) {
panic!("2 * theta * mu < sigma^2")
}

let fgn = FgnFft::new(hurst, n - 1, t, None).sample();
let dt = t.unwrap_or(1.0) / n as f64;

let mut fcir = Array1::<f64>::zeros(n);
fcir[0] = x0.unwrap_or(0.0);

for i in 1..n {
let random = match use_sym.unwrap_or(false) {
true => sigma * (fcir[i - 1]).abs().sqrt() * fgn[i - 1],
false => sigma * (fcir[i - 1]).max(0.0) * fgn[i - 1],
};
fcir[i] = fcir[i - 1] + theta * (mu - fcir[i - 1]) * dt + random
}

fcir
}
80 changes: 80 additions & 0 deletions src/diffusions/fcir.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use ndarray::Array1;

use crate::{noises::fgn::FgnFft, utils::Generator};

/// Generates a path of the fractional Cox-Ingersoll-Ross (fCIR) process.
///
/// The fCIR process incorporates fractional Brownian motion, which introduces long-range dependence.
///
/// # Parameters
///
/// - `hurst`: Hurst parameter for fractional Brownian motion, must be in (0, 1).
/// - `theta`: Speed of mean reversion.
/// - `mu`: Long-term mean level.
/// - `sigma`: Volatility parameter.
/// - `n`: Number of time steps.
/// - `x0`: Initial value of the process (optional, defaults to 0.0).
/// - `t`: Total time (optional, defaults to 1.0).
/// - `use_sym`: Whether to use symmetric noise (optional, defaults to false).
///
/// # Returns
///
/// A `Array1<f64>` representing the generated fCIR process path.
///
/// # Panics
///
/// Panics if `hurst` is not in (0, 1).
/// Panics if `2 * theta * mu < sigma^2`.
///
/// # Example
///
/// ```
/// let fcir_path = fcir(0.75, 0.5, 0.02, 0.1, 1000, Some(0.01), Some(1.0), Some(false));
/// ```
#[derive(Default)]
pub struct Fcir {
pub hurst: f64,
pub theta: f64,
pub mu: f64,
pub sigma: f64,
pub n: usize,
pub x0: Option<f64>,
pub t: Option<f64>,
pub use_sym: Option<bool>,
}

pub fn fcir(params: &Fcir) -> Array1<f64> {
let Fcir {
hurst,
theta,
mu,
sigma,
n,
x0,
t,
use_sym,
} = *params;

assert!(
hurst > 0.0 && hurst < 1.0,
"Hurst parameter must be in (0, 1)"
);
assert!(2.0 * theta * mu < sigma.powi(2), "2 * theta * mu < sigma^2");

let fgn = FgnFft::new(hurst, n - 1, t, None).sample();
let dt = t.unwrap_or(1.0) / n as f64;

let mut fcir = Array1::<f64>::zeros(n);
fcir[0] = x0.unwrap_or(0.0);

for i in 1..n {
let random = match use_sym.unwrap_or(false) {
true => sigma * (fcir[i - 1]).abs().sqrt() * fgn[i - 1],
false => sigma * (fcir[i - 1]).max(0.0) * fgn[i - 1],
};
fcir[i] = fcir[i - 1] + theta * (mu - fcir[i - 1]) * dt + random
}

fcir
}
68 changes: 68 additions & 0 deletions src/diffusions/fgbm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use ndarray::Array1;

use crate::{noises::fgn::FgnFft, utils::Generator};

/// Generates a path of the fractional Geometric Brownian Motion (fGBM) process.
///
/// The fGBM process incorporates fractional Brownian motion, which introduces long-range dependence.
///
/// # Parameters
///
/// - `hurst`: Hurst parameter for fractional Brownian motion, must be in (0, 1).
/// - `mu`: Drift parameter.
/// - `sigma`: Volatility parameter.
/// - `n`: Number of time steps.
/// - `x0`: Initial value of the process (optional, defaults to 100.0).
/// - `t`: Total time (optional, defaults to 1.0).
///
/// # Returns
///
/// A `Array1<f64>` representing the generated fGBM process path.
///
/// # Panics
///
/// Panics if `hurst` is not in (0, 1).
///
/// # Example
///
/// ```
/// let fgbm_path = fgbm(0.75, 0.05, 0.2, 1000, Some(100.0), Some(1.0));
/// ```
#[derive(Default)]
pub struct Fgbm {
pub hurst: f64,
pub mu: f64,
pub sigma: f64,
pub n: usize,
pub x0: Option<f64>,
pub t: Option<f64>,
}

pub fn fgbm(params: &Fgbm) -> Array1<f64> {
let Fgbm {
hurst,
mu,
sigma,
n,
x0,
t,
} = *params;

assert!(
hurst > 0.0 && hurst < 1.0,
"Hurst parameter must be in (0, 1)"
);

let fgn = FgnFft::new(hurst, n - 1, t, None).sample();
let dt = t.unwrap_or(1.0) / n as f64;

let mut fgbm = Array1::<f64>::zeros(n);
fgbm[0] = x0.unwrap_or(100.0);

for i in 1..n {
fgbm[i] = fgbm[i - 1] + mu * fgbm[i - 1] * dt + sigma * fgbm[i - 1] * fgn[i - 1]
}

fgbm
}
85 changes: 85 additions & 0 deletions src/diffusions/fjacobi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use ndarray::Array1;

use crate::{noises::fgn::FgnFft, utils::Generator};

/// Generates a path of the fractional Jacobi (fJacobi) process.
///
/// The fJacobi process incorporates fractional Brownian motion, which introduces long-range dependence.
///
/// # Parameters
///
/// - `hurst`: Hurst parameter for fractional Brownian motion, must be in (0, 1).
/// - `alpha`: Speed of mean reversion.
/// - `beta`: Long-term mean level.
/// - `sigma`: Volatility parameter.
/// - `n`: Number of time steps.
/// - `x0`: Initial value of the process (optional, defaults to 0.0).
/// - `t`: Total time (optional, defaults to 1.0).
///
/// # Returns
///
/// A `Array1<f64>` representing the generated fJacobi process path.
///
/// # Panics
///
/// Panics if `hurst` is not in (0, 1).
/// Panics if `alpha`, `beta`, or `sigma` are not positive.
/// Panics if `alpha` is greater than `beta`.
///
/// # Example
///
/// ```
/// let fjacobi_path = fjacobi(0.75, 0.5, 1.0, 0.2, 1000, Some(0.5), Some(1.0));
/// ```
#[derive(Default)]
pub struct Fjacobi {
pub hurst: f64,
pub alpha: f64,
pub beta: f64,
pub sigma: f64,
pub n: usize,
pub x0: Option<f64>,
pub t: Option<f64>,
}

pub fn fjacobi(params: &Fjacobi) -> Array1<f64> {
let Fjacobi {
hurst,
alpha,
beta,
sigma,
n,
x0,
t,
} = *params;

assert!(
hurst > 0.0 && hurst < 1.0,
"Hurst parameter must be in (0, 1)"
);
assert!(alpha > 0.0, "alpha must be positive");
assert!(beta > 0.0, "beta must be positive");
assert!(sigma > 0.0, "sigma must be positive");
assert!(alpha < beta, "alpha must be less than beta");

let fgn = FgnFft::new(hurst, n - 1, t, None).sample();
let dt = t.unwrap_or(1.0) / n as f64;

let mut fjacobi = Array1::<f64>::zeros(n);
fjacobi[0] = x0.unwrap_or(0.0);

for i in 1..n {
fjacobi[i] = match fjacobi[i - 1] {
_ if fjacobi[i - 1] <= 0.0 && i > 0 => 0.0,
_ if fjacobi[i - 1] >= 1.0 && i > 0 => 1.0,
_ => {
fjacobi[i - 1]
+ (alpha - beta * fjacobi[i - 1]) * dt
+ sigma * (fjacobi[i - 1] * (1.0 - fjacobi[i - 1])).sqrt() * fgn[i - 1]
}
}
}

fjacobi
}
Loading

0 comments on commit ebe8480

Please sign in to comment.