Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions app/poisson_sampling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import marimo

__generated_with = "0.19.7"
app = marimo.App(width="medium")


@app.cell
def _():
import marimo as mo
from app.utils import nav_menu
nav_menu()
return (mo,)


@app.cell
def _(mo):
mo.md(r"""
# Poisson Sampling

Evaluate the MC simulation for The Poisson process against the analytical PDF.
""")
return


@app.cell
def _():
from quantflow.sp.poisson import PoissonProcess
import pandas as pd

def simulate_poisson(intensity: float, samples: int) -> pd.DataFrame:
pr = PoissonProcess(intensity=intensity)
paths = pr.sample(samples, 1, 1000)
pdf = paths.pdf(delta=1)
pdf["simulation"] = pdf["pdf"]
pdf["analytical"] = pr.marginal(1).pdf(pdf.index)
return pdf
return (simulate_poisson,)


@app.cell
def _(mo):
samples = mo.ui.slider(start=100, stop=10000, step=100, value=1000, debounce=True, label="Samples")
intensity = mo.ui.slider(start=2, stop=5, step=0.1, debounce=True, label="Poisson intensity $\lambda$")

controls = mo.hstack([samples, intensity], justify="start")
controls
return intensity, samples


@app.cell
def _(intensity, samples, simulate_poisson):
df = simulate_poisson(intensity=intensity.value, samples=samples.value)
return (df,)


@app.cell
def _(df):
import plotly.graph_objects as go
simulation = go.Bar(x=df.index, y=df["simulation"], name="simulation")
analytical = go.Bar(x=df.index, y=df["analytical"], name="analytical")
fig = go.Figure(data=[simulation, analytical])
fig
return


@app.cell
def _():
return


if __name__ == "__main__":
app.run()
18 changes: 3 additions & 15 deletions docs/api/sp/heston.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
================
Heston process
================
# Heston process

.. currentmodule:: quantflow.sp.heston
::: quantflow.sp.heston.Heston

.. autoclass:: Heston
:members:
:member-order: groupwise
:autosummary:
:autosummary-nosignatures:


.. autoclass:: HestonJ
:members:
:member-order: groupwise
:autosummary:
:autosummary-nosignatures:
::: quantflow.sp.heston.HestonJ
12 changes: 2 additions & 10 deletions docs/api/sp/jump_diffusion.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
================
Jump diffusions
================
# Jump diffusions

Jump-diffusions models are a class of stochastic processes that combine a diffusion process with a jump process. The jump process is a Poisson process that generates jumps in the value of the underlying asset. The jump-diffusion model is a generalization of the Black-Scholes model that allows for the possibility of large,
discontinuous jumps in the value of the underlying asset.

The most famous jump-diffusion model is the Merton model, which was introduced by Robert Merton in 1976. The Merton model assumes that the underlying asset follows a geometric Brownian motion with jumps that are normally distributed.

.. currentmodule:: quantflow.sp.jump_diffusion

.. autoclass:: JumpDiffusion
:members:
:member-order: groupwise
:autosummary:
:autosummary-nosignatures:
::: quantflow.sp.jump_diffusion.JumpDiffusion
2 changes: 2 additions & 0 deletions docs/api/sp/poisson.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Poisson process

::: quantflow.sp.poisson.PoissonBase

::: quantflow.sp.poisson.PoissonProcess
13 changes: 2 additions & 11 deletions docs/api/sp/weiner.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
===============
Weiner process
===============

.. module:: quantflow.sp.weiner

.. autoclass:: WeinerProcess
:members:
:member-order: groupwise
:autosummary:
:autosummary-nosignatures:
# Weiner process

::: quantflow.sp.weiner.WeinerProcess
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ nav:
- Home: index.md
- Examples:
- Gaussian Sampling: examples/gaussian-sampling
- Poisson Sampling: examples/poisson-sampling
- Hurst: examples/hurst
- Supersmoother: examples/supersmoother
- API Reference:
Expand Down
38 changes: 22 additions & 16 deletions quantflow/sp/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import numpy as np
from pydantic import BaseModel, ConfigDict, Field
from scipy.optimize import Bounds
from typing_extensions import Annotated, Doc

from quantflow.ta.paths import Paths
from quantflow.utils.marginal import Marginal1D, default_bounds
Expand All @@ -26,29 +27,33 @@ def sample_from_draws(self, draws: Paths, *args: Paths) -> Paths:
"""Sample :class:`.Paths` from the process given a set of draws"""

@abstractmethod
def sample(self, n: int, time_horizon: float = 1, time_steps: int = 100) -> Paths:
"""Generate random :class:`.Paths` from the process.

:param n: number of paths
:param time_horizon: time horizon
:param time_steps: number of time steps to arrive at horizon
"""
def sample(
self,
n: Annotated[int, Doc("number of paths")],
time_horizon: Annotated[float, Doc("time horizon")] = 1,
time_steps: Annotated[
int, Doc("number of time steps to arrive at horizon")
] = 100,
) -> Paths:
"""Generate random :class:`.Paths` from the process."""

@abstractmethod
def characteristic_exponent(self, t: FloatArrayLike, u: Vector) -> Vector:
"""Characteristic exponent at time `t` for a given input parameter"""

def characteristic(self, t: FloatArrayLike, u: Vector) -> Vector:
def characteristic(
self,
t: Annotated[FloatArrayLike, Doc("Time horizon")],
u: Annotated[Vector, Doc("Characteristic function input parameter")],
) -> Vector:
r"""Characteristic function at time `t` for a given input parameter

The characteristic function represents the Fourier transform of the
probability density function

.. math::
\begin{equation}
\phi = {\mathbb E} \left[e^{i u x_t}\right]

:param t: time horizon
:param u: characteristic function input parameter
\end{equation}
"""
return np.exp(-self.characteristic_exponent(t, u))

Expand Down Expand Up @@ -174,14 +179,15 @@ class IntensityProcess(StochasticProcess1D):
r"""Mean reversion speed :math:`\kappa`"""

@abstractmethod
def integrated_log_laplace(self, t: FloatArrayLike, u: Vector) -> Vector:
def integrated_log_laplace(
self,
t: Annotated[FloatArrayLike, Doc("time horizon")],
u: Annotated[Vector, Doc("frequency")],
) -> Vector:
r"""The log-Laplace transform of the cumulative process:

.. math::
e^{\phi_{t, u}} = {\mathbb E} \left[e^{i u \int_0^t x_s ds}\right]

:param t: time horizon
:param u: frequency
"""

def domain_range(self) -> Bounds:
Expand Down
6 changes: 3 additions & 3 deletions quantflow/sp/dsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ class DSP(PoissonBase):
Doubly Stochastic Poisson process.

It's a process where the inter-arrival time is exponentially distributed
with rate :math:`\lambda_t`
with rate $\lambda_t$

:param intensity: the stochastic intensity of the Poisson
"""

intensity: IntensityProcess = Field( # type ignore
intensity: IntensityProcess = Field(
default_factory=CIR, description="intensity process"
)
poisson: PoissonProcess = Field(default_factory=PoissonProcess, exclude=True)
Expand All @@ -39,7 +39,7 @@ def characteristic_exponent(self, t: FloatArrayLike, u: Vector) -> Vector:
phi = self.poisson.characteristic_exponent(t, u)
return -self.intensity.integrated_log_laplace(t, phi)

def arrivals(self, t: float = 1) -> list[float]:
def arrivals(self, t: float = 1) -> FloatArray:
paths = self.intensity.sample(1, t, math.ceil(100 * t)).integrate()
intensity = paths.data[-1, 0]
return poisson_arrivals(intensity, t)
Expand Down
Loading