Source code for aleatory.processes.jump.variance_gamma

import numpy as np

from aleatory.processes.base_analytical import SPAnalytical, SPAnalyticalMarginals
from aleatory.utils.utils import (
    check_positive_integer,
    get_times,
)
from aleatory.stats.variance_gamma import vg


[docs]class VarianceGammaProcess(SPAnalyticalMarginals): r""" Variance Gamma Process ====================== .. image:: ../_static/variance_gamma_draw.png Notes ----- In the theory of stochastic processes, a part of the mathematical theory of probability, the variance gamma (VG) process, also known as Laplace motion, is a Lévy process determined by a random time change. The process has finite moments, distinguishing it from many Lévy processes. There is no diffusion component in the VG process and it is thus a pure jump process. The increments are independent and follow a variance-gamma distribution, which is a generalization of the Laplace distribution. There are several representations of the Variance-Gamma process that relate it to other processes. It can for example be written as a Brownian motion :math:`W` with drift :math:`\theta t` subjected to a random time change which follows Gamma process :math:`\Gamma(t;1 ,\nu)`. That is, .. math:: X(t; \sigma, \nu, \theta) = \theta \Gamma(t;1, \nu) + \sigma W(\Gamma(t;1, \nu)); \quad t \in [0,T]. Constructor, Methods, and Attributes ------------------------------------ """
[docs] def __init__(self, theta=0.0, nu=1.0, sigma=1.0, T=1.0, rng=None): """ :parameter double theta: the :math:`\\theta` parameter in the above expression :parameter double nu: the :math:`\\nu` parameter in the above expression :parameter double sigma: the :math:`\\sigma` parameter in the above expression :parameter float T: the right hand endpoint of the time interval :math:`[0,T]` for the process :parameter numpy.random.Generator rng: a custom random number generator """ super().__init__(T=T, rng=rng, initial=0.0) self.theta = theta self.nu = nu self.sigma = sigma self.name = f"Variance Gamma Process X($\\theta$={self.theta}, $\\nu$={self.nu}, $\\sigma$={self.sigma})" self.n = None self.times = None
def __str__(self): return f"Variance Gamma Process with parameters theta = {self.theta}, nu = {self.nu}, sigma = {self.sigma}" def __repr__(self): return f"VarianceGammaProcess(theta = {self.theta}, nu={self.nu}, sigma={self.sigma})" def _sample_variance_gamma_process(self, n): check_positive_integer(n) dt = self.T / n gammas = self.rng.gamma(shape=dt / self.nu, scale=self.nu, size=n - 1) gaussian_increments = self.rng.normal(loc=0.0, scale=1.0, size=n - 1) increments = ( self.theta * gammas + self.sigma * np.sqrt(gammas) * gaussian_increments ) sample = np.cumsum(increments) sample = np.concatenate(([0], sample)) return sample def sample(self, n): self.n = n self.times = get_times(self.T, self.n) return self._sample_variance_gamma_process(n) def _process_expectation(self, times=None): if times is None: times = self.times expectations = self.theta * times return expectations def _process_variance(self, times=None): if times is None: times = self.times variances = ((self.theta**2) * self.nu + self.sigma**2) * times return variances def marginal_expectation(self, times=None): expectations = self._process_expectation(times=times) return expectations def marginal_variance(self, times=None): variances = self._process_variance(times=times) return variances def get_marginal(self, t): a = 2.0 * t / self.nu b = 0.5 * self.theta * self.nu c = self.sigma * np.sqrt(0.5 * self.nu) marginal = vg(r=a, theta=b, sigma=c) return marginal def plot(self, n, N, T=None, mode="steps", title=None, **fig_kw): return self._plot_process(n=n, N=N, T=T, mode=mode, title=title, **fig_kw) def draw( self, n, N, T=None, mode="steps", marginal=True, envelope=False, empirical_envelope=True, title=None, **fig_kw, ): return self._draw_qqstyle( n, N, T=T, marginal=marginal, mode=mode, envelope=envelope, title=title, empirical_envelope=empirical_envelope, estimate_quantiles=True, **fig_kw, )
if __name__ == "__main__": import matplotlib.pyplot as plt qs = "https://raw.githubusercontent.com/quantgirluk/matplotlib-stylesheets/main/quant-pastel-light.mplstyle" plt.style.use(qs) # for T in [5.0, 10.0, 20.0]: # p = VarianceGammaProcess(T=T, theta=0.0, sigma=1.0) # # for n_grid in [500]: # p.draw(n=n_grid, N=200, figsize=(12, 7), style=qs, envelope=True) # p.draw(n=n_grid, N=200, figsize=(12, 7), style=qs, envelope=True) # # end_points = [path[-1] for path in p.paths] # plt.hist(end_points, density=True) # plt.show() # vals = p.marginal_density() p = VarianceGammaProcess() # p.plot(n=100, N=5, figsize=(10, 6), style=qs) p.plot( n=50, N=5, figsize=(10, 6), style=qs, mode="steps+points", title="Variance Gamma Process Paths", ) p.draw( n=50, N=100, figsize=(12, 7), style=qs, colormap="viridis", marginal=False, mode="steps+points", ) p.draw(n=50, N=100, T=2.0, figsize=(12, 7), style=qs, colormap="cool") p.plot(n=50, N=5, figsize=(10, 6), style=qs) p = VarianceGammaProcess(T=100) p.draw(n=100, N=100, figsize=(12, 7), style=qs, colormap="viridis") p.draw(n=100, N=200, T=10, figsize=(12, 7), style=qs, colormap="twilight") p.plot(n=100, N=5, T=2.0, figsize=(10, 6), style=qs) # p = VarianceGammaProcess(theta=0.0, nu=0.5, sigma=1.0, T=1.0) # p.draw(n=100, N=200, figsize=(12, 7), style=qs, colormap="winter", envelope=False) # p = VarianceGammaProcess(theta=-1.0, nu=4.0, sigma=2.0, T=100.0) # p.draw(n=100, N=200, figsize=(12, 7), style=qs, colormap="summer", envelope=False)