Poisson Processes#
In this section, we look at the family of pure jump processes which are Lévy provcesses. The most common process is the Poisson process.
Poisson Process#
The Poisson Process \(N_t\) with intensity parameter \(\lambda > 0\) is a Lévy process with values in \(N\) such that each \(N_t\) has a Poisson distribution with parameter \(\lambda t\), that is
The characteristic exponent is given by
from quantflow.sp.poisson import PoissonProcess
pr = PoissonProcess(intensity=1)
pr
PoissonProcess(intensity=1.0)
m = pr.marginal(0.1)
import numpy as np
cdf = m.cdf(np.arange(5))
cdf
array([0.90483742, 0.99532116, 0.99984535, 0.99999615, 0.99999992])
n = 128*8
m.cdf_from_characteristic(5, frequency_n=n).y
array([0.90403788, 0.99499564, 0.99839477, 0.99901958, 0.99901958])
cdf1 = m.cdf_from_characteristic(5, frequency_n=n).y
cdf2 = m.cdf_from_characteristic(5, frequency_n=n, simpson_rule=False).y
10000*np.max(np.abs(cdf-cdf1)), 10000*np.max(np.abs(cdf-cdf2))
(np.float64(14.505795170645097), np.float64(17.76098399924986))
Marginal#
import numpy as np
from quantflow.utils import plot
m = pr.marginal(1)
plot.plot_marginal_pdf(m, frequency_n=128*8)
from quantflow.utils.plot import plot_characteristic
plot_characteristic(m)
Sampling Poisson#
p = pr.sample(10, time_horizon=10, time_steps=1000)
p.plot().update_traces(line_width=1)
Compound Poisson Process#
The compound poisson process is a jump process, where the arrival of jumps \(N_t\) follows the same dynamic as the Poisson process but the size of jumps is no longer constant and equal to 1, instead, they are i.i.d. random variables independent from \(N_t\).
The characteristic exponent of a compound Poisson process is given by
where \(\Phi_{j,u}\) is the characteristic function of the jump distribution.
As long as we have a closed-form solution for the characteristic function of the jump distribution, then we have a closed-form solution for the characteristic exponent of the compound Poisson process.
The mean and variance of the compund Poisson is given by
Exponential Compound Poisson Process#
The library includes the Exponential Poisson Process, a compound Poisson process where the jump sizes are sampled from an exponential distribution.
from quantflow.sp.poisson import CompoundPoissonProcess
from quantflow.utils.distributions import Exponential
pr = CompoundPoissonProcess(intensity=1, jumps=Exponential(decay=1))
pr
CompoundPoissonProcess(intensity=1.0, jumps=Exponential(decay=1.0))
from quantflow.utils.plot import plot_characteristic
m = pr.marginal(1)
plot_characteristic(m)
m.mean(), m.mean_from_characteristic()
(1.0, np.float64(0.9999978333375087))
m.variance(), m.variance_from_characteristic()
(2.0, np.float64(1.999998249717447))
pr.sample(10, time_horizon=10, time_steps=1000).plot().update_traces(line_width=1)
MC simulations#
Here we test the simulated mean and standard deviation against the analytical values.
import pandas as pd
from quantflow.utils import plot
paths = pr.sample(100, time_horizon=10, time_steps=1000)
mean = dict(mean=pr.marginal(paths.time).mean(), simulated=paths.mean())
df = pd.DataFrame(mean, index=paths.time)
plot.plot_lines(df)
std = dict(std=pr.marginal(paths.time).std(), simulated=paths.std())
df = pd.DataFrame(std, index=paths.time)
plot.plot_lines(df)
Normal Compound Poisson#
A compound Poisson process with a normal jump distribution
from quantflow.utils.distributions import Normal
from quantflow.sp.poisson import CompoundPoissonProcess
pr = CompoundPoissonProcess(intensity=10, jumps=Normal(mu=0.01, sigma=0.1))
pr
CompoundPoissonProcess(intensity=10.0, jumps=Normal(mu=0.01, sigma=0.1))
m = pr.marginal(1)
m.mean(), m.std()
(0.1, np.float64(0.3178049716414141))
m.mean_from_characteristic(), m.std_from_characteristic()
(np.float64(0.09999999428166687), np.float64(0.3178049681523679))
Doubly Stochastic Poisson Process#
The aim is to identify a stochastic process for simulating arrivals which fulfills the following properties
Capture overdispersion
Analytically tractable
Capture the inherent randomness of the Poisson intensity
Intuitive
The DSP process presented in [Unk17] has an intensity process which belongs to a class of affine diffusion and it can treated analytically.
Additional links
Closed-form formulas for the distribution of the jumps of doubly-stochastic Poisson processes
On the characteristic functional of a doubly stochastic Poisson process
DSP process#
The DSP is defined as a time-changed Poisson process
where \(\tau_t\) is the cumulative intensity, or the hazard process, for the intensity process \(\lambda_t\). The Characteristic function of \(D_t\) can therefore be written as
The doubly stochastic Poisson process (DSP process) with intensity process \(\lambda_t\) is a point process \(y_t = p_{\Lambda_t}\) satisfying the following expression for the conditional distribution of the n-th jump
The intensity function of a DSPP is given by:
from quantflow.sp.dsp import DSP, PoissonProcess, CIR
pr = DSP(intensity=CIR(sigma=2, kappa=1), poisson=PoissonProcess(intensity=2))
pr2 = DSP(intensity=CIR(rate=2, sigma=4, kappa=2, theta=2), poisson=PoissonProcess(intensity=1))
pr, pr2
(DSP(intensity=CIR(rate=1.0, kappa=1.0, sigma=2.0, theta=1.0, sample_algo=<SamplingAlgorithm.implicit: 'implicit'>), poisson=PoissonProcess(intensity=2.0)),
DSP(intensity=CIR(rate=2.0, kappa=2.0, sigma=4.0, theta=2.0, sample_algo=<SamplingAlgorithm.implicit: 'implicit'>), poisson=PoissonProcess(intensity=1.0)))
import numpy as np
from quantflow.utils import plot
import plotly.graph_objects as go
n=16
m = pr.marginal(1)
pdf = m.pdf_from_characteristic(n)
fig = plot.plot_marginal_pdf(m, n, analytical=False, label=f"rate={pr.intensity.rate}")
plot.plot_marginal_pdf(pr2.marginal(1), n, analytical=False, fig=fig, marker_color="yellow", label=f"rate={pr2.intensity.rate}")
fig.add_trace(go.Scatter(x=pdf.x, y=pr.poisson.marginal(1).pdf(pdf.x), name="Poisson", mode="markers", marker_color="blue"))
pr.marginal(1).mean(), pr.marginal(1).variance()
(np.float64(1.9999909680081247), np.float64(4.689459199192303))
pr2.marginal(1).mean(), pr2.marginal(1).variance()
(np.float64(1.999989818527503), np.float64(5.046045401891716))
from quantflow.utils.plot import plot_characteristic
m = pr.marginal(2)
plot_characteristic(m)
pr.sample(10, time_horizon=10, time_steps=1000).plot().update_traces(line_width=1)
m.characteristic(2)
np.complex128(0.000708775281497072+0.013619153217117782j)
m.characteristic(-2).conj()
np.complex128(0.000708775281497072+0.013619153217117782j)