optionstratlib-simulation 0.23.0

Random walks, stochastic processes, simulators, exit policies and path statistics of OptionStratLib, on Decimal and Positive boundaries. Re-exported by the optionstratlib facade under its `simulation` feature.
Documentation
/******************************************************************************
   Author: Joaquín Béjar García
   Email: jb@taunais.com
   Date: 12/7/26
******************************************************************************/
//! Deterministic walkers for generator tests.
//!
//! `RampWalker` replaces the RNG-driven default walk methods with a fixed
//! arithmetic ramp so multi-step generator tests can assert exact prices,
//! indices and dates without seeds or wall-clock dependence.

use crate::error::SimulationError;
use crate::simulation::{WalkParams, WalkTypeAble};
use optionstratlib_core::model::Positive;
use std::convert::TryInto;
use std::fmt::Display;
use std::ops::AddAssign;

/// Test walker producing the deterministic ramp
/// `start, start + delta, start + 2·delta, …` (length `params.size`) for
/// every synthetic walk type. `Historical` keeps the default trait behavior
/// (slice of the provided prices) so its data-validation semantics stay
/// testable.
#[derive(Clone)]
pub(crate) struct RampWalker {
    /// Price increment per step.
    pub delta: Positive,
}

impl RampWalker {
    fn ramp<X, Y>(&self, params: &WalkParams<X, Y>) -> Result<Vec<Positive>, SimulationError>
    where
        X: Copy + TryInto<Positive> + AddAssign + Display,
        Y: TryInto<Positive> + Display + Clone,
    {
        let start = params.ystep_as_positive()?;
        Ok((0..params.size)
            .map(|i| start + self.delta * i as f64)
            .collect())
    }
}

impl<X, Y> WalkTypeAble<X, Y> for RampWalker
where
    X: Copy + TryInto<Positive> + AddAssign + Display,
    Y: TryInto<Positive> + Display + Clone,
{
    fn brownian(&self, params: &WalkParams<X, Y>) -> Result<Vec<Positive>, SimulationError> {
        self.ramp(params)
    }

    fn geometric_brownian(
        &self,
        params: &WalkParams<X, Y>,
    ) -> Result<Vec<Positive>, SimulationError> {
        self.ramp(params)
    }

    fn log_returns(&self, params: &WalkParams<X, Y>) -> Result<Vec<Positive>, SimulationError> {
        self.ramp(params)
    }

    fn mean_reverting(&self, params: &WalkParams<X, Y>) -> Result<Vec<Positive>, SimulationError> {
        self.ramp(params)
    }

    fn jump_diffusion(&self, params: &WalkParams<X, Y>) -> Result<Vec<Positive>, SimulationError> {
        self.ramp(params)
    }

    fn garch(&self, params: &WalkParams<X, Y>) -> Result<Vec<Positive>, SimulationError> {
        self.ramp(params)
    }

    fn heston(&self, params: &WalkParams<X, Y>) -> Result<Vec<Positive>, SimulationError> {
        self.ramp(params)
    }

    fn custom(&self, params: &WalkParams<X, Y>) -> Result<Vec<Positive>, SimulationError> {
        self.ramp(params)
    }

    fn telegraph(&self, params: &WalkParams<X, Y>) -> Result<Vec<Positive>, SimulationError> {
        self.ramp(params)
    }
}