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
14 changes: 4 additions & 10 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,6 @@ on:
jobs:
build:
runs-on: ubuntu-latest
services:
redis:
image: redis:7
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
PYTHON_ENV: ci
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -41,6 +31,10 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Start Redis
uses: supercharge/redis-github-action@1.8.1
with:
redis-version: 7
- name: Install uv
run: pip install -U pip uv
- name: Install dependencies
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ permissions:
jobs:
release:
runs-on: ubuntu-latest
services:
redis:
image: redis:7
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
PYTHON_ENV: ci
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ app-serve: ## serve app
docs: ## build documentation
@cp docs/index.md readme.md
@uv run ./dev/build-examples
@uv run mkdocs build
@uv run mkdocs build --strict

.PHONY: docs-bib
docs-bib: ## Regenerate docs bibliography
Expand Down
30 changes: 25 additions & 5 deletions app/api/deps.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import io
import json
import logging
import os
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from dataclasses import dataclass, field
from typing import Annotated, Generic, TypeVar, cast

import pandas as pd
from fastapi import Depends, FastAPI, Request
from fluid.utils import log
from fluid.utils.redis import FluidRedis
from pydantic import BaseModel
from redis.asyncio import Redis

from quantflow.data.fmp import FMP

M = TypeVar("M", bound=BaseModel)
logger = log.get_logger(__name__)
logger = logging.getLogger(__name__)


def instrument_app(app: FastAPI) -> None:
Expand Down Expand Up @@ -44,7 +45,17 @@ class RedisCache(Generic[M]):
redis: Redis
Model: type[M]
key: str
ttl: int = 60
prefix: str = field(
default_factory=lambda: os.getenv(
"QUANTFLOW_REDIS_CACHE_PREFIX", "quantflow:cache"
)
)
ttl: int = field(
default_factory=lambda: int(os.getenv("QUANTFLOW_REDIS_CACHE_TTL", "60"))
)

def __post_init__(self) -> None:
self.key = f"{self.prefix}:{self.key}"

async def from_cache(self, loader: Callable[[], Awaitable[M]]) -> M:
"""Get a value from the cache"""
Expand All @@ -53,7 +64,7 @@ async def from_cache(self, loader: Callable[[], Awaitable[M]]) -> M:
return await self.set_cache(await loader())
try:
return self.Model.model_validate_json(value)
except json.JSONDecodeError:
except json.JSONDecodeError: # pragma: no cover
logger.exception(f"Failed to decode cache value for key {self.key}")
return await self.set_cache(await loader())

Expand All @@ -63,6 +74,15 @@ async def set_cache(self, value: M) -> M:
await self.redis.set(self.key, payload, ex=self.ttl)
return value

@classmethod
async def clear(cls, redis: Redis) -> int:
"""Delete all cache entries under the prefix"""
cache = cls(redis=redis, Model=cast(type[M], BaseModel), key="*")
keys = [key async for key in cache.redis.scan_iter(f"{cache.prefix}:*")]
if not keys:
return 0
return await cache.redis.delete(*keys)


@dataclass
class RedisDataframe:
Expand Down
2 changes: 1 addition & 1 deletion app/api/heston.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
from pydantic import BaseModel, Field

from app.api.docs import load_description
from quantflow.dists.distributions1d import DoubleExponential
from quantflow.options.pricer import OptionPricer
from quantflow.sp.heston import HestonJ
from quantflow.sp.jump_diffusion import JumpDiffusion
from quantflow.utils.distributions import DoubleExponential

heston_router = APIRouter()

Expand Down
2 changes: 1 addition & 1 deletion app/api/sampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
from scipy.stats import chisquare, ks_1samp

from app.api.docs import load_description
from quantflow.dists.distributions1d import DoubleExponential
from quantflow.sp.ou import Vasicek
from quantflow.sp.poisson import PoissonProcess
from quantflow.ta.paths import Paths
from quantflow.utils import bins
from quantflow.utils.distributions import DoubleExponential

sampling_router = APIRouter()

Expand Down
2 changes: 1 addition & 1 deletion app/scripts/heston_divfm_fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from quantflow.options.divfm.trainer import DayData, DIVFMTrainer
from quantflow.options.pricer import OptionPricer
from quantflow.sp.heston import HestonJ
from quantflow.utils.distributions import DoubleExponential
from quantflow.dists.distributions1d import DoubleExponential

# ---------------------------------------------------------------------------
# Grid settings
Expand Down
9 changes: 9 additions & 0 deletions docs/api/dists/distributions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Distributions

::: quantflow.dists.Distribution

::: quantflow.dists.MvDistribution

::: quantflow.dists.MeanAndCov

::: quantflow.dists.MvNormal
9 changes: 9 additions & 0 deletions docs/api/dists/distributions1d.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# 1D Distributions

::: quantflow.dists.Distribution1D

::: quantflow.dists.Normal

::: quantflow.dists.Exponential

::: quantflow.dists.DoubleExponential
15 changes: 6 additions & 9 deletions docs/api/dists/index.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
# Distributions

Probability distributions with a uniform `sample` / `log_pdf` API, used as
return types of the
[StateSpaceModel](../ta/kalman.md#quantflow.ta.kalman.StateSpaceModel)
distribution-level interface.
The `dists` module collects the probability distributions used across quantflow,
both standalone parametric laws and the marginal distributions implied by a
stochastic process at a fixed time horizon.

::: quantflow.dists.MeanAndCov

::: quantflow.dists.Distribution

::: quantflow.dists.MvNormal
Every distribution derives from
[Distribution][quantflow.dists.Distribution], which exposes a common
[sample][quantflow.dists.Distribution.sample] method for drawing random variates.
9 changes: 9 additions & 0 deletions docs/api/dists/marginal1d.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Marginal 1D

::: quantflow.dists.OptionPricingMethod

::: quantflow.dists.OptionPricingResult

::: quantflow.dists.OptionPricingCosResult

::: quantflow.dists.Marginal1D
14 changes: 11 additions & 3 deletions docs/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ Option pricing, volatility surface construction, and model calibration.
| [Calibration](options/calibration.md) | Calibrate Heston and Heston-jump-diffusion models to a surface |
| [Deep IV Factor Model](options/divfm.md) | Neural-network option pricing via the DIVFM architecture |

### [Distributions](dists/index.md)

Probability distributions: parametric laws and the marginals implied by a stochastic process via its characteristic function.

| Module | Description |
|---|---|
| [Distributions](dists/distributions.md) | Base classes ([Distribution][quantflow.dists.Distribution], [MvDistribution][quantflow.dists.MvDistribution]) and the multivariate normal |
| [1D Distributions](dists/distributions1d.md) | Parametric 1D laws (Normal, Exponential, DoubleExponential) |
| [Marginal 1D](dists/marginal1d.md) | Marginal distribution via characteristic function inversion, with Fourier-based option pricing |

### [Stochastic Processes](sp/index.md)

Continuous-time stochastic processes used as underlying models for option pricing and simulation.
Expand Down Expand Up @@ -68,16 +78,14 @@ Interest rate models and curve construction tools for discounting and term-struc
| [CIR Curve](rates/cir.md) | Cox-Ingersoll-Ross short-rate term-structure model |
| [Nelson Siegel Curve](rates/nelson_siegel.md) | Parametric yield curve with level, slope, and curvature factors |
| [Vasicek Curve](rates/vasicek.md) | Gaussian mean-reverting short-rate term-structure model |
| [Options Discounting](rates/options.md) | Curve calibration from discount factors and put-call parity data |
| [Calibration](rates/calibration.md) | Curve calibration from discount factors and put-call parity data |

### [Utilities](utils/index.md)

Low-level building blocks used throughout the library.

| Module | Description |
|---|---|
| [Distributions](utils/distributions.md) | Jump-size distributions (Normal, DoubleExponential) |
| [Marginal 1D](utils/marginal1d.md) | Marginal distribution via characteristic function inversion |
| [Bins](utils/bins.md) | Histogram binning helpers |
| [Numbers](utils/numbers.md) | Decimal and float numeric utilities |
| [Types](utils/types.md) | Shared type aliases |
9 changes: 0 additions & 9 deletions docs/api/utils/distributions.md

This file was deleted.

2 changes: 0 additions & 2 deletions docs/api/utils/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ users who want to extend the library or understand its inner workings.

| Page | Description |
|---|---|
| [Marginal 1D](marginal1d.md) | Abstract base class for 1D marginal distributions with Fourier-based option pricing (Carr-Madan and Lewis formulas) |
| [Distributions](distributions.md) | Parametric 1D distributions (e.g. Exponential) |
| [Bins](bins.md) | Histogram and event-density utilities |
| [Numbers](numbers.md) | Decimal number helpers |
| [Types](types.md) | Shared type aliases (FloatArray, etc.) |
9 changes: 0 additions & 9 deletions docs/api/utils/marginal1d.md

This file was deleted.

2 changes: 1 addition & 1 deletion docs/examples/heston_volatility_pricer.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from quantflow.dists.distributions1d import DoubleExponential
from quantflow.options.inputs import OptionType
from quantflow.options.pricer import OptionPricer
from quantflow.sp.heston import HestonJ
from quantflow.utils.distributions import DoubleExponential

pricer = OptionPricer(
model=HestonJ.create(
Expand Down
8 changes: 4 additions & 4 deletions docs/examples/pricing_method_comparison.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
from pydantic import BaseModel, Field

from docs.examples._utils import assets_path
from quantflow.options.bs import implied_black_volatility
from quantflow.sp.base import StochasticProcess1D
from quantflow.sp.heston import Heston
from quantflow.utils.marginal import (
from quantflow.dists.marginal1d import (
OptionPricingCosResult,
OptionPricingMethod,
OptionPricingResult,
)
from quantflow.options.bs import implied_black_volatility
from quantflow.sp.base import StochasticProcess1D
from quantflow.sp.heston import Heston


class ChartProps(BaseModel):
Expand Down
4 changes: 2 additions & 2 deletions docs/examples/vol_surface_hestonj_calibration.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import json

from docs.examples._utils import FIXTURES, assets_path, print_model
from quantflow.dists.distributions1d import DoubleExponential
from quantflow.dists.marginal1d import OptionPricingMethod
from quantflow.options.calibration import HestonJCalibration
from quantflow.options.calibration.base import ResidualKind
from quantflow.options.pricer import OptionPricer
from quantflow.options.surface import VolSurface, VolSurfaceInputs, surface_from_inputs
from quantflow.sp.heston import HestonJ
from quantflow.utils.distributions import DoubleExponential
from quantflow.utils.marginal import OptionPricingMethod

# Load a saved volatility surface snapshot and build the surface
with open(FIXTURES / "volsurface_btc.json") as fp:
Expand Down
2 changes: 1 addition & 1 deletion docs/theory/kalman.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ exposes a distribution-level API that mirrors the
These methods return [Distribution](../api/dists/index.md) objects and are
intended for particle-filter algorithms (sequential Monte Carlo). They are
abstract on the base class; [LinearGaussianModel](../api/ta/kalman.md#quantflow.ta.kalman.LinearGaussianModel)
implements them by returning [MvNormal](../api/dists/index.md#quantflow.dists.MvNormal)
implements them by returning [MvNormal](../api/dists/distributions.md#quantflow.dists.MvNormal)
instances.

| Method | Signature | Returns |
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/cir.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ The marginal PDF has two independent routes to the same result:
* **Analytical**: the [scaled non-central chi-squared][quantflow.sp.cir.CIR.analytical_pdf]
transition density in closed form.
* **Characteristic function**: numerical inversion of $\Phi = e^{-\phi}$ via
[pdf_from_characteristic][quantflow.utils.marginal.Marginal1D.pdf_from_characteristic].
[pdf_from_characteristic][quantflow.dists.Marginal1D.pdf_from_characteristic].

The charts below overlay both for a CIR process with
$\kappa=1$, $\theta=0.5$, $\sigma=0.8$, $x_0=3$, starting well above the long-run mean
Expand Down
6 changes: 3 additions & 3 deletions docs/tutorials/heston_calibration.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ the motivation for the Heston jump-diffusion model described in the next section
[HestonJCalibration][quantflow.options.calibration.heston.HestonJCalibration] extends the
Heston calibration with a compound Poisson jump component via the
[HestonJ][quantflow.sp.heston.HestonJ] model. Jumps are drawn from a
[DoubleExponential][quantflow.utils.distributions.DoubleExponential] distribution,
[DoubleExponential][quantflow.dists.DoubleExponential] distribution,
which captures asymmetric jump behaviour common in equity and crypto markets.

```python
Expand Down Expand Up @@ -126,7 +126,7 @@ whole surface, so short maturities — with fewer strikes — are outvoted and t
systematically sacrificed.

**The jump distribution is not rich enough.** The short-term smile in crypto is driven
by large, rare, asymmetric events. A [DoubleExponential][quantflow.utils.distributions.DoubleExponential]
by large, rare, asymmetric events. A [DoubleExponential][quantflow.dists.DoubleExponential]
with fixed parameters cannot simultaneously match the wing curvature at short and long
maturities.

Expand All @@ -149,4 +149,4 @@ The calibrated parameter vector for the jump-diffusion model is:
| `rho` | Spot-variance correlation |
| `jump intensity` | Jump arrival rate (jumps per year) |
| `jump variance` | Variance of a single jump |
| `jump asymmetry` | Asymmetry of the jump distribution ([DoubleExponential][quantflow.utils.distributions.DoubleExponential]) |
| `jump asymmetry` | Asymmetry of the jump distribution ([DoubleExponential][quantflow.dists.DoubleExponential]) |
2 changes: 1 addition & 1 deletion docs/tutorials/option_pricing.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ The first example shows how to price an option using the Black-Scholes model and

The underlying model is [HestonJ][quantflow.sp.heston.HestonJ], a Heston stochastic
volatility model extended with jumps drawn from a
[DoubleExponential][quantflow.utils.distributions.DoubleExponential] distribution.
[DoubleExponential][quantflow.dists.DoubleExponential] distribution.

```python
--8<-- "docs/examples/heston_volatility_pricer.py"
Expand Down
5 changes: 3 additions & 2 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ nav:
- Yahoo: api/data/yahoo.md
- Distributions:
- api/dists/index.md
- Distributions: api/dists/distributions.md
- 1D Distributions: api/dists/distributions1d.md
- Marginal 1D: api/dists/marginal1d.md
- Options:
- api/options/index.md
- Black-Scholes: api/options/black.md
Expand Down Expand Up @@ -111,8 +114,6 @@ nav:
- Utilities:
- api/utils/index.md
- Bins: api/utils/bins.md
- Distributions: api/utils/distributions.md
- Marginal 1D: api/utils/marginal1d.md
- Numbers: api/utils/numbers.md
- Price: api/utils/price.md
- Types: api/utils/types.md
Expand Down
Loading
Loading