Skip to main content

A Python library for simulating stochastic processes in finance.

Project description

FinStoch

A Python library for simulating stochastic processes in finance.

Installation

pip install FinStoch

Development

pip install -e ".[dev]"

# Run tests
python -m unittest discover -s tests -p "*_test.py"

# Format / lint / type check
ruff format
flake8 --max-line-length 127
mypy . --exclude venv --ignore-missing-imports

Processes

Geometric Brownian Motion

  • SDE

$$ dS_t = \mu S_t dt + \sigma S_t dW_t $$

  • A stochastic process where the logarithm of the variable follows a Brownian motion with drift, representing continuous growth with random fluctuations.

  • Euler-Maruyama Discretization

$$ S_{t+\Delta t} = S_t.e^{\left(\mu-\frac{\sigma^2}{2}\right)\Delta t+\sigma\sqrt{\Delta t}\epsilon_t} $$

Where $\epsilon_t \sim \mathcal{N}(0, 1)$.

import numpy as np
from FinStoch.processes import GeometricBrownianMotion

S0 = 100                    # Initial value 
mu = 0.05                   # Annualized Drift coefficient (expected return rate)
sigma = 0.2                 # Annualized Volatility (standard deviation of returns)
num_paths = 10              # Number of paths to simulate
start_date = '2023-09-01'   # Start date for the simulation
end_date = '2024-09-01'     # End date for the simulation
granularity = 'D'           # Granularity in daily intervals
    
# Create the GBM model
gbm = GeometricBrownianMotion(S0, mu, sigma, num_paths, start_date, end_date, granularity)

# Simulate the GBM process
simulated_paths = gbm.simulate()

# Plot the simulated paths
gbm.plot(paths=simulated_paths, 
         title='Stock Price under Geometric Brownian Motion Assumption', 
         ylabel='Stock Price',
         fig_size=(15,5)
        )

Plot

Merton's Jump Diffusion Model

  • SDE

$$ dS_t = \left(\mu - \lambda_j\left( e^{\mu_j+\frac{\sigma_j^2}{2}} - 1\right) \right) S_t dt + \sigma S_t dW_t + S_t \left( \prod_{i=1}^{dN_t} Y_i - 1\right) $$

  • An extension of the geometric Brownian motion that incorporates sudden, discrete jumps $ J_t $ in addition to continuous diffusion, capturing both regular volatility and occasional large shocks.

  • Euler-Maruyama Discretization

$$ S_{t+\Delta t} = S_t . e^{\left( \mu - \frac{1}{2} \sigma^2 -\lambda_j\left( e^{\mu_j+\frac{\sigma_j^2}{2}} - 1\right)\right) \Delta t + \sigma \sqrt{\Delta t} \epsilon_t + J_t } $$

Where $\epsilon_t \sim \mathcal{N}(0, 1)$ and $J_t$ is the jump component at time $t$.

import numpy as np
from FinStoch.processes import MertonJumpDiffusion

# Parameters
S0 = 100                    # Initial process value
mu = 0.05                   # Drift coefficient
sigma = 0.2                 # Volatility
lambda_j = 1                # Jump intensity
mu_j = 0.0                  # Mean of jump size
sigma_j = 0.15              # Standard deviation of jump size
num_paths = 10              # Number of simulated paths
start_date = '2023-09-01'   # Start date for the simulation
end_date = '2024-09-01'     # End date for the simulation
granularity = 'D'           # Granularity in daily intervals


# Create Merton model instance and plot
merton = MertonJumpDiffusion(S0, mu, sigma, lambda_j, mu_j, sigma_j, num_paths, start_date, end_date, granularity)

# Simulate the Merton process
simulated_paths = merton.simulate()

# Plot the simulated paths
merton.plot(paths=simulated_paths, 
         title='Stock Price under the Merton Model Assumption', 
         ylabel='Stock Price',
         fig_size=(15,5)
        )

Plot

Ornstein-Uhlenbeck model

  • SDE

$$ dS_t = \theta (\mu - S_t) dt + \sigma dW_t $$

  • A mean-reverting stochastic process where the variable fluctuates around a long-term mean with a tendency to revert back, driven by continuous noise.

  • Euler-Maruyama Discretization

$$ S_{t+\Delta t} = S_t + \theta (\mu - S_t) \Delta t + \sigma \sqrt{\Delta t} \epsilon_t $$

Where $\epsilon_t \sim \mathcal{N}(0, 1)$.

import numpy as np
from FinStoch.processes import OrnsteinUhlenbeck 

# Parameters
S0 = 100                    # Initial value
mu = 100                    # Annualized drift coefficient
sigma = 0.2                 # Anualized volatility
theta = 0.5                 # Annualized mean reversion rate
num_paths = 10              # Number of paths to simulate
start_date = '2023-09-01'   # Start date for the simulation
end_date = '2024-09-01'     # End date for the simulation
granularity = 'D'           # Granularity in daily intervals

# Create Ornstein-Uhlenbeck model instance and plot
ou = OrnsteinUhlenbeck(S0, mu, sigma, theta, num_paths, start_date, end_date, granularity)

# Simulate the OU process
simulated_paths = ou.simulate()

# Plot the simulated paths
ou.plot(paths=simulated_paths, 
         title='Stock Price under the Ornstein Uhlenbeck model Assumption', 
         ylabel='Stock Price',
         fig_size=(15,5)
        )

Plot

Cox-Ingersoll-Ross Model

  • SDE

$$ dS_t = \kappa (\theta - S_t) dt + \sigma \sqrt{S_t} dW_t $$

  • A mean-reverting process with volatility that depends on the current level of the variable, ensuring the values are always non-negative.

  • Euler-Maruyama Discretization

$$ S_{t+\Delta t} = S_t + \kappa (\theta - S_t) \Delta t + \sigma \sqrt{S_t} \sqrt{\Delta t} \epsilon_t $$

Where $\epsilon_t \sim \mathcal{N}(0, 1)$.

import numpy as np
from FinStoch.processes import CoxIngersollRoss 

# Parameters 
S0 = 0.03                   # Initial value
mu = 0.03                   # Long-term mean
sigma = 0.1                 # Volatility
theta = 0.03                # Speed of reversion
num_paths = 10              # Number of simulation paths
start_date = '2023-09-01'   # Start date for the simulation
end_date = '2024-09-01'     # End date for the simulation
granularity = 'D'           # Granularity in daily intervals

# Create an instance of the CoxIngersollRoss class
cir = CoxIngersollRoss(S0, mu, sigma, theta, num_paths, start_date, end_date, granularity)

# Simulate the CIR process
simulated_paths = cir.simulate()

# Plot the simulated paths
cir.plot(paths=simulated_paths, 
         title='Rate under the CIR model Assumption', 
         ylabel='Rate',
         fig_size=(15,5)
        )

Plot

Constant Elasticity of Variance Model

  • SDE

$$ dS_t = \mu S_t dt + \sigma {S_t}^\gamma dW_t $$

  • A stochastic process that extends the Geometric Brownian Motion process.

  • Euler-Maruyama Discretization

$$ S_{t+\Delta t} = S_t + \mu S_t \Delta t + \sigma {S_t}^\gamma \sqrt{\Delta t} \epsilon_t $$

Where $\epsilon_t \sim \mathcal{N}(0, 1)$.

import numpy as np 
from FinStoch.processes import ConstantElasticityOfVariance

S0 = 100                    # Initial value
mu = 0.05                   # Annualized Drift coefficient (expected return rate)
sigma = 0.2                 # Annualized Volatility (standard deviation of returns)
gamma = 1.2                 # Elasticity coefficient
num_paths = 10              # Number of paths to simulate
start_date = '2023-09-01'   # Start date for the simulation
end_date = '2024-09-01'     # End date for the simulation
granularity = 'D'           # Granularity in daily intervals
    
# Create the CEV model
cev = ConstantElasticityOfVariance(S0, mu, sigma, gamma, num_paths, start_date, end_date, granularity)

# Simulate the CEV process
simulated_paths = cev.simulate()

# Plot the simulated paths
cev.plot(paths=simulated_paths, 
         title='Stock Price under the Constant Elasricity of Variance Model Assumption', 
         ylabel='Stock Price',
         fig_size=(15,5)
        )

Plot

Heston Stochastic Volatility Model

  • SDEs

$$ dS_t = \mu S_t dt + \sqrt{v_t} S_t dW_{S,t} $$

$$ dv_t = \kappa (\theta - v_t) dt + \sigma_v \sqrt{v_t} dW_{v,t} $$

$$ dW_{S,t}\times dW_{v,t}=\rho dt $$

  • A stochastic volatility model where the volatility of a variable follows its own mean-reverting process, allowing for time-varying volatility that evolves over time.

  • Euler-Maruyama Discretization

$$ S_{t+\Delta t} = S_t.e^{\left(\mu-\frac{v_t}{2}\right)\Delta t+\sqrt{v_t}\sqrt{\Delta t}\epsilon_{S,t}} $$

$$ v_{t+\Delta t} = v_t + \kappa (\theta - v_t) \Delta t + \sigma_v \sqrt{v_t} \sqrt{\Delta t} \epsilon_{v,t} $$

$$ Corr(\epsilon_{S,t},\epsilon_{v,t})=\rho $$

Where $\epsilon_S$ and $\epsilon_v$ are correlated standard normal variables.

import numpy as np
from FinStoch.processes import HestonModel

# Parameters
S0 = 100                    # Initial value
v0 = 0.02                   # Initial volatility
mu = 0.05                   # Long-term mean of the value
theta = 0.04                # Long-term mean of the volatility
sigma = 0.3                 # Volatility of the volatility
kappa = 1.5                 # Speed of reversion
rho = -0.7                  # Correlation between shocks
num_paths = 10              # Number of simulation paths
start_date = '2023-09-01'   # Start date for the simulation
end_date = '2024-09-01'     # End date for the simulation
granularity = 'D'           # Granularity in daily intervals

# Initialize Heston model
heston = HestonModel(S0, v0, mu, sigma, theta, kappa, rho, num_paths, start_date, end_date, granularity)

# Simulate the Heston model
simulated_paths = heston.simulate()

# Plot the simulated paths
heston.plot(paths=simulated_paths,
            title='Asset Price under the Heston model Assumption', 
            ylabel='Asset Price',
            fig_size=(15,5)
        )

heston.plot(paths=simulated_paths,
            title='Asset Volatility under the Heston model Assumption', 
            ylabel='Asset Volatility',
            variance=True,
            fig_size=(15,5)
            )

Plot Plot

Seed Control

All processes accept an optional seed parameter for reproducible simulations:

from FinStoch.processes import GeometricBrownianMotion

gbm = GeometricBrownianMotion(100, 0.05, 0.2, 10, '2023-09-01', '2024-09-01', 'D')

# Reproducible simulation
paths_a = gbm.simulate(seed=42)
paths_b = gbm.simulate(seed=42)
# paths_a and paths_b are identical

Data Conversion

Convert simulation output to a pandas DataFrame with to_dataframe():

paths = gbm.simulate(seed=42)
df = gbm.to_dataframe(paths)
# DataFrame with DatetimeIndex columns and path indices as rows

# For Heston (tuple output), select price or variance
heston_paths = heston.simulate(seed=42)
df_prices = heston.to_dataframe(heston_paths, variance=False)
df_variance = heston.to_dataframe(heston_paths, variance=True)

Analytics

All processes inherit analytics methods from the base class, operating on simulation output:

paths = gbm.simulate(seed=42)

# Summary statistics (mean, std, skew, kurtosis, min, max) at each time step
stats = gbm.summary_statistics(paths)

# Mean path across all simulations
mean_path = gbm.expected_path(paths)

# 95% confidence bands
lower, upper = gbm.confidence_bands(paths, level=0.95)

# Value at Risk at terminal time step (5th percentile)
var_95 = gbm.var(paths, alpha=0.05)

# Conditional VaR / Expected Shortfall
cvar_95 = gbm.cvar(paths, alpha=0.05)

# Maximum drawdown per path (peak-to-trough decline as fraction)
drawdowns = gbm.max_drawdown(paths)

# Histogram of terminal values with fitted normal overlay
gbm.terminal_distribution(paths, bins=50)

License

This project is licensed under the MIT license found in the LICENSE file.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

finstoch-0.6.0.tar.gz (13.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

finstoch-0.6.0-py3-none-any.whl (20.7 kB view details)

Uploaded Python 3

File details

Details for the file finstoch-0.6.0.tar.gz.

File metadata

  • Download URL: finstoch-0.6.0.tar.gz
  • Upload date:
  • Size: 13.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for finstoch-0.6.0.tar.gz
Algorithm Hash digest
SHA256 7499e60714e8872dfef9f26ca611f4d1ddc5ff9d961c3e49967a8fd19cd03791
MD5 ec9cc8034a6a345874969a257849becf
BLAKE2b-256 94cf0b33d02d92f85844c18ebb02db8762125d79124c35c81c3d01055241111d

See more details on using hashes here.

Provenance

The following attestation bundles were made for finstoch-0.6.0.tar.gz:

Publisher: cd.yml on Yosri-Ben-Halima/FinStoch

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file finstoch-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: finstoch-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 20.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for finstoch-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 82522fcd22cea673ae8ec8335e7008c20c8421595bd73f96960305a04c29936f
MD5 5412e68dc890e7cba3d5de7ef25d6594
BLAKE2b-256 35fc141dbfb831bb286f13660057d19d2730dcbd634f064e1f81b32bcf47eb36

See more details on using hashes here.

Provenance

The following attestation bundles were made for finstoch-0.6.0-py3-none-any.whl:

Publisher: cd.yml on Yosri-Ben-Halima/FinStoch

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page