quantflow 0.6.0__tar.gz → 0.6.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {quantflow-0.6.0 → quantflow-0.6.2}/.github/copilot-instructions.md +5 -1
- {quantflow-0.6.0 → quantflow-0.6.2}/.gitignore +1 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/.vscode/launch.json +1 -1
- {quantflow-0.6.0 → quantflow-0.6.2}/Makefile +5 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/PKG-INFO +3 -3
- quantflow-0.6.2/app/volatility_surface.py +106 -0
- quantflow-0.6.2/dev/build-examples +28 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/dev/quantflow.dockerfile +2 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/data/deribit.md +1 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/data/index.md +1 -1
- quantflow-0.6.2/docs/api/options/black.md +25 -0
- quantflow-0.6.2/docs/api/options/index.md +52 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/options/pricer.md +2 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/options/vol_surface.md +22 -0
- quantflow-0.6.2/docs/api/sp/dsp.md +3 -0
- quantflow-0.6.2/docs/api/utils/index.md +3 -0
- quantflow-0.6.2/docs/api/utils/numbers.md +4 -0
- quantflow-0.6.2/docs/api/utils/types.md +6 -0
- quantflow-0.6.2/docs/bibliography.md +43 -0
- quantflow-0.6.2/docs/examples/heston_volatility_pricer.py +25 -0
- quantflow-0.6.2/docs/examples/weiner_volatility_pricer.py +19 -0
- {quantflow-0.6.0/notebooks → quantflow-0.6.2/docs}/theory/characteristic.md +8 -25
- quantflow-0.6.2/docs/theory/index.md +51 -0
- {quantflow-0.6.0/notebooks → quantflow-0.6.2/docs}/theory/inversion.md +20 -45
- {quantflow-0.6.0/notebooks → quantflow-0.6.2/docs}/theory/levy.md +18 -38
- {quantflow-0.6.0/notebooks → quantflow-0.6.2/docs}/theory/option_pricing.md +19 -42
- quantflow-0.6.2/docs/tutorials/option_pricing.md +36 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/mkdocs.yml +22 -6
- {quantflow-0.6.0 → quantflow-0.6.2}/pyproject.toml +3 -3
- quantflow-0.6.2/quantflow/__init__.py +5 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/data/deribit.py +48 -10
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/options/bs.py +95 -38
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/options/calibration.py +9 -8
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/options/inputs.py +11 -0
- quantflow-0.6.2/quantflow/options/pricer.py +335 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/options/surface.py +538 -175
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/sp/base.py +3 -2
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/sp/dsp.py +0 -2
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/sp/heston.py +49 -28
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/sp/poisson.py +21 -14
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/utils/bins.py +29 -15
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/utils/distributions.py +27 -25
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/utils/marginal.py +47 -22
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/utils/types.py +10 -3
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/test_options.py +2 -2
- quantflow-0.6.2/quantflow_tests/test_options_pricer.py +53 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/uv.lock +1021 -860
- quantflow-0.6.0/docs/api/options/black.md +0 -23
- quantflow-0.6.0/docs/api/options/index.md +0 -5
- quantflow-0.6.0/docs/api/utils/index.md +0 -1
- quantflow-0.6.0/docs/bibliography.md +0 -13
- quantflow-0.6.0/notebooks/theory/overview.md +0 -17
- quantflow-0.6.0/quantflow/__init__.py +0 -3
- quantflow-0.6.0/quantflow/options/pricer.py +0 -196
- quantflow-0.6.0/quantflow_tests/test_options_pricer.py +0 -22
- {quantflow-0.6.0 → quantflow-0.6.2}/.coveragerc +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/.dockerignore +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/.github/workflows/build.yml +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/.github/workflows/deploy.yml +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/.github/workflows/docker-multiarch.yml +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/.vscode/settings.json +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/.vscode/tasks.json +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/CITATION.cff +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/CLAUDE.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/LICENSE +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/app/__main__.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/app/cointegration.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/app/double_exponential_sampling.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/app/gaussian_sampling.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/app/hurst.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/app/poisson_sampling.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/app/supersmoother.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/app/utils/__init__.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/dev/blocks/quantflow.yaml +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/dev/charts.yaml +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/dev/helm/.helmignore +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/dev/helm/Chart.yaml +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/dev/helm/templates/_helpers.tpl +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/dev/helm/templates/_service.tpl +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/dev/helm/templates/app.yaml +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/dev/helm/templates/configmap.yaml +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/dev/helm/templates/secret.yaml +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/dev/helm/values.yaml +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/dev/install +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/dev/lint +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/dev/marimo +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/dev/test +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/data/fed.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/data/fmp.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/data/fred.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/index.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/options/calibration.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/sp/cir.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/sp/compound_poisson.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/sp/heston.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/sp/index.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/sp/jump_diffusion.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/sp/ou.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/sp/poisson.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/sp/weiner.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/ta/ewma.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/ta/index.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/ta/kalman.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/ta/ohlc.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/ta/paths.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/ta/supersmoother.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/utils/bins.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/utils/distributions.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/api/utils/marginal1d.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/assets/heston.gif +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/assets/linkedin-banner.png +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/assets/quantflow-light.svg +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/assets/quantflow-logo.png +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/assets/quantflow-repo.png +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/assets/quantflow-repo.svg +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/assets/quantflow.svg +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/contributing.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/index.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/docs/javascripts/mathjax.js +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/CNAME +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/_config.yml +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/_toc.yml +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/applications/calibration.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/applications/calibration.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/applications/hurst.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/applications/overview.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/applications/sampling.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/applications/volatility_surface.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/conf.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/data/fed.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/data/fiscal_data.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/data/fmp.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/data/timeseries.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/examples/heston_vol_surface.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/index.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/models/bns.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/models/cir.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/models/gousv.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/models/heston.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/models/heston_jumps.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/models/jump_diffusion.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/models/ou.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/models/overview.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/models/poisson.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/models/weiner.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/reference/biblio.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/reference/contributing.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/reference/glossary.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/notebooks/reference/references.bib +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ai/__init__.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ai/server.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ai/tools/__init__.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ai/tools/base.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ai/tools/charts.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ai/tools/crypto.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ai/tools/fred.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ai/tools/stocks.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ai/tools/vault.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/data/__init__.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/data/fed.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/data/fiscal_data.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/data/fmp.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/data/fred.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/data/vault.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/options/__init__.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/py.typed +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/sp/__init__.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/sp/bns.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/sp/cir.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/sp/copula.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/sp/jump_diffusion.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/sp/ou.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/sp/weiner.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ta/__init__.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ta/base.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ta/ewma.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ta/kalman.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ta/ohlc.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ta/paths.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/ta/supersmoother.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/utils/__init__.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/utils/dates.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/utils/functions.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/utils/interest_rates.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/utils/numbers.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/utils/plot.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow/utils/transforms.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/conftest.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/test_ai.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/test_cir.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/test_copula.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/test_data.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/test_distributions.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/test_frft.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/test_heston.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/test_jump_diffusion.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/test_ohlc.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/test_ou.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/test_poisson.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/test_utils.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/test_vault.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/test_weiner.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/utils.py +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/quantflow_tests/volsurface.json +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/readme.md +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/rops.toml +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/taplo.toml +0 -0
- {quantflow-0.6.0 → quantflow-0.6.2}/test_comparison.py +0 -0
|
@@ -12,6 +12,8 @@ applyTo: '/**'
|
|
|
12
12
|
|
|
13
13
|
* Always run `make lint` after code changes — runs taplo, isort, black, ruff, and mypy
|
|
14
14
|
* Never edit `readme.md` directly — it is generated from `docs/index.md` via `make docs`
|
|
15
|
+
* To run all tests use `make test` — runs all tests in the `tests/` directory using pytest
|
|
16
|
+
* To run a specific test file, use `uv run pytest tests/path/to/test_file.py`
|
|
15
17
|
|
|
16
18
|
## Docker
|
|
17
19
|
|
|
@@ -24,4 +26,6 @@ applyTo: '/**'
|
|
|
24
26
|
|
|
25
27
|
* The documentation for quantflow is available at `https://quantflow.quantmid.com`
|
|
26
28
|
* Documentation is built using [mkdocs](https://www.mkdocs.org/) and stored in the `docs/` directory. The documentation source files are written in markdown format.
|
|
27
|
-
|
|
29
|
+
* Do not use em dashes (—) in documentation files or docstrings. Use colons, parentheses, or restructure the sentence instead.
|
|
30
|
+
* Math in documentation and docstrings uses `$...$` for inline and `$$...$$` or `\begin{equation}...\end{equation}` for block equations. Do not use `.. math::` or `:math:` (RST syntax).
|
|
31
|
+
* To rebuild doc examples run `uv run ./dev/build-examples` — runs all scripts in `docs/examples/` and writes their output to `docs/examples_output/`
|
|
@@ -27,6 +27,7 @@ marimo: ## Run marimo for editing notebooks
|
|
|
27
27
|
.PHONY: docs
|
|
28
28
|
docs: ## build documentation
|
|
29
29
|
@cp docs/index.md readme.md
|
|
30
|
+
@uv run ./dev/build-examples
|
|
30
31
|
@uv run mkdocs build
|
|
31
32
|
|
|
32
33
|
.PHONY: docs-serve
|
|
@@ -46,3 +47,7 @@ tests: ## Unit tests
|
|
|
46
47
|
.PHONY: outdated
|
|
47
48
|
outdated: ## Show outdated packages
|
|
48
49
|
uv tree --outdated
|
|
50
|
+
|
|
51
|
+
.PHONY: upgrade
|
|
52
|
+
upgrade: ## Upgrade dependencies
|
|
53
|
+
uv lock --upgrade
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quantflow
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
4
4
|
Summary: quantitative analysis
|
|
5
5
|
Project-URL: Homepage, https://github.com/quantmind/quantflow
|
|
6
6
|
Project-URL: Repository, https://github.com/quantmind/quantflow
|
|
@@ -9,7 +9,7 @@ Author-email: Luca Sbardella <luca@quantmind.com>
|
|
|
9
9
|
License-Expression: BSD-3-Clause
|
|
10
10
|
License-File: LICENSE
|
|
11
11
|
Requires-Python: <3.15,>=3.11
|
|
12
|
-
Requires-Dist: ccy>=
|
|
12
|
+
Requires-Dist: ccy>=2.0.0
|
|
13
13
|
Requires-Dist: polars[pandas,pyarrow]>=1.11.0
|
|
14
14
|
Requires-Dist: pydantic>=2.0.2
|
|
15
15
|
Requires-Dist: python-dotenv>=1.0.1
|
|
@@ -17,7 +17,7 @@ Requires-Dist: scipy>=1.14.1
|
|
|
17
17
|
Requires-Dist: statsmodels<0.15.0,>=0.14.6
|
|
18
18
|
Provides-Extra: ai
|
|
19
19
|
Requires-Dist: asciichartpy>=1.5.25; extra == 'ai'
|
|
20
|
-
Requires-Dist: ccy[holidays]>=
|
|
20
|
+
Requires-Dist: ccy[holidays]>=2.0.0; extra == 'ai'
|
|
21
21
|
Requires-Dist: google-genai>=1.61.0; extra == 'ai'
|
|
22
22
|
Requires-Dist: mcp>=1.26.0; extra == 'ai'
|
|
23
23
|
Requires-Dist: openai>=2.16.0; extra == 'ai'
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import marimo
|
|
2
|
+
|
|
3
|
+
__generated_with = "0.20.4"
|
|
4
|
+
app = marimo.App(width="medium")
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@app.cell
|
|
8
|
+
def _():
|
|
9
|
+
import marimo as mo
|
|
10
|
+
from app.utils import nav_menu
|
|
11
|
+
nav_menu()
|
|
12
|
+
return (mo,)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@app.cell(hide_code=True)
|
|
16
|
+
def _(mo):
|
|
17
|
+
mo.md(r"""
|
|
18
|
+
# Volatility Surface
|
|
19
|
+
|
|
20
|
+
In this notebook we illustrate the use of the Volatility Surface tool in the library. We use [deribit](https://docs.deribit.com/) options on ETHUSD as example.
|
|
21
|
+
|
|
22
|
+
The library provide a [VolSurfaceLoader](api/options/vol_surface/#quantflow.options.surface.VolSurfaceLoader) for Deribit:
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
import pandas as pd
|
|
26
|
+
from quantflow.data.deribit import Deribit
|
|
27
|
+
|
|
28
|
+
async with Deribit() as cli:
|
|
29
|
+
loader = await cli.volatility_surface_loader("eth", exclude_open_interest=0)
|
|
30
|
+
|
|
31
|
+
# build the volatility surface
|
|
32
|
+
surface = loader.surface()
|
|
33
|
+
# calculate black implied volatilities
|
|
34
|
+
surface.bs()
|
|
35
|
+
# disable outliers
|
|
36
|
+
surface.disable_outliers()
|
|
37
|
+
# display inputs - only options with converged implied volatility
|
|
38
|
+
surface_inputs = surface.inputs(converged=True)
|
|
39
|
+
pd.DataFrame([i.model_dump() for i in surface_inputs.inputs])
|
|
40
|
+
```
|
|
41
|
+
""")
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@app.cell
|
|
46
|
+
def _(mo):
|
|
47
|
+
inverse = mo.ui.checkbox(value=True, label="Inverse options")
|
|
48
|
+
inverse
|
|
49
|
+
return (inverse,)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@app.cell
|
|
53
|
+
async def _(inverse):
|
|
54
|
+
import pandas as pd
|
|
55
|
+
from quantflow.data.deribit import Deribit
|
|
56
|
+
|
|
57
|
+
async with Deribit() as cli:
|
|
58
|
+
loader = await cli.volatility_surface_loader("eth", exclude_open_interest=0, inverse=inverse.value)
|
|
59
|
+
|
|
60
|
+
# build the volatility surface
|
|
61
|
+
surface = loader.surface()
|
|
62
|
+
# calculate black implied volatilities
|
|
63
|
+
surface.bs()
|
|
64
|
+
# disable outliers
|
|
65
|
+
surface.disable_outliers()
|
|
66
|
+
# display inputs - only options with converged implied volatility
|
|
67
|
+
surface_inputs = surface.inputs(converged=True)
|
|
68
|
+
pd.DataFrame([i.model_dump() for i in surface_inputs.inputs])
|
|
69
|
+
return (surface,)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@app.cell(hide_code=True)
|
|
73
|
+
def _(mo):
|
|
74
|
+
mo.md(r"""
|
|
75
|
+
##Volatility Surface
|
|
76
|
+
""")
|
|
77
|
+
return
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@app.cell
|
|
81
|
+
def _(surface):
|
|
82
|
+
surface.plot3d()
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@app.cell(hide_code=True)
|
|
87
|
+
def _(mo):
|
|
88
|
+
mo.md(r"""
|
|
89
|
+
## Term Structure
|
|
90
|
+
""")
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@app.cell
|
|
95
|
+
def _(surface):
|
|
96
|
+
surface.term_structure()
|
|
97
|
+
return
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@app.cell
|
|
101
|
+
def _():
|
|
102
|
+
return
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
if __name__ == "__main__":
|
|
106
|
+
app.run()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Run all example scripts in docs/examples/ and capture their stdout to .out files."""
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
out_dir = Path("docs/examples_output")
|
|
8
|
+
out_dir.mkdir(exist_ok=True)
|
|
9
|
+
|
|
10
|
+
examples = sorted(Path("docs/examples").glob("*.py"))
|
|
11
|
+
failed = []
|
|
12
|
+
|
|
13
|
+
for script in examples:
|
|
14
|
+
out_file = out_dir / script.with_suffix(".out").name
|
|
15
|
+
print(f"running {script} -> {out_file}")
|
|
16
|
+
result = subprocess.run(
|
|
17
|
+
[sys.executable, str(script)],
|
|
18
|
+
capture_output=True,
|
|
19
|
+
text=True,
|
|
20
|
+
)
|
|
21
|
+
if result.returncode != 0:
|
|
22
|
+
print(f"FAILED: {script}\n{result.stderr}", file=sys.stderr)
|
|
23
|
+
failed.append(script)
|
|
24
|
+
else:
|
|
25
|
+
out_file.write_text(result.stdout)
|
|
26
|
+
|
|
27
|
+
if failed:
|
|
28
|
+
sys.exit(1)
|
|
@@ -14,6 +14,8 @@ RUN uv sync --frozen --no-install-project --extra ai --extra book --extra docs -
|
|
|
14
14
|
COPY mkdocs.yml ./
|
|
15
15
|
COPY docs/ ./docs/
|
|
16
16
|
COPY quantflow/ ./quantflow/
|
|
17
|
+
COPY dev/build-examples ./dev/build-examples
|
|
18
|
+
RUN uv run ./dev/build-examples
|
|
17
19
|
RUN uv run mkdocs build
|
|
18
20
|
|
|
19
21
|
# Stage 2: Runtime stage
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Data fetching
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
The
|
|
4
|
+
The `quantflow.data` module provides classes and functions for fetching data from various sources.
|
|
5
5
|
To use the module the package must be installed with the optional `data` extra.
|
|
6
6
|
```
|
|
7
7
|
pip install quantflow[data]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Black Pricing
|
|
2
|
+
|
|
3
|
+
Here we define the log strike `k` as
|
|
4
|
+
$$
|
|
5
|
+
k = \log{\frac{K}{F}}
|
|
6
|
+
$$
|
|
7
|
+
|
|
8
|
+
where $K$ is the strike price and $F$ is the forward price of the underlying asset.
|
|
9
|
+
We also refers to this log-strike as `moneyness`, since it is zero for at-the-money (ATM) options,
|
|
10
|
+
negative for in-the-money (ITM) call options, and positive for out-of-the-money (OTM) call options.
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
::: quantflow.options.bs.black_price
|
|
14
|
+
|
|
15
|
+
::: quantflow.options.bs.black_call
|
|
16
|
+
|
|
17
|
+
::: quantflow.options.bs.black_vega
|
|
18
|
+
|
|
19
|
+
::: quantflow.options.bs.BlackSensitivities
|
|
20
|
+
|
|
21
|
+
::: quantflow.options.bs.implied_black_volatility
|
|
22
|
+
|
|
23
|
+
::: quantflow.options.bs.ImpliedVols
|
|
24
|
+
|
|
25
|
+
::: quantflow.options.bs.ImpliedVol
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Options
|
|
2
|
+
|
|
3
|
+
The `options` module provides classes and functions for pricing and calibrating options.
|
|
4
|
+
|
|
5
|
+
## Volatility Surface
|
|
6
|
+
|
|
7
|
+
The central class is [VolSurface][quantflow.options.surface.VolSurface], which represents
|
|
8
|
+
the implied volatility surface for an asset across all strikes and maturities. It holds:
|
|
9
|
+
|
|
10
|
+
- a [SpotPrice][quantflow.options.surface.SpotPrice] for the underlying asset
|
|
11
|
+
- a sorted tuple of [VolCrossSection][quantflow.options.surface.VolCrossSection] objects, one per maturity
|
|
12
|
+
|
|
13
|
+
Each [VolCrossSection][quantflow.options.surface.VolCrossSection] contains the forward price
|
|
14
|
+
at that maturity and a tuple of [Strike][quantflow.options.surface.Strike] objects.
|
|
15
|
+
Each [Strike][quantflow.options.surface.Strike] holds a call and/or put as an
|
|
16
|
+
[OptionPrices][quantflow.options.surface.OptionPrices], which in turn pairs a bid and ask
|
|
17
|
+
[OptionPrice][quantflow.options.surface.OptionPrice].
|
|
18
|
+
|
|
19
|
+
A surface is typically constructed via [VolSurfaceLoader][quantflow.options.surface.VolSurfaceLoader],
|
|
20
|
+
which accepts price inputs incrementally and builds the surface through its `surface()` method.
|
|
21
|
+
The lower-level [GenericVolSurfaceLoader][quantflow.options.surface.GenericVolSurfaceLoader]
|
|
22
|
+
provides the same functionality with a user-defined security type.
|
|
23
|
+
|
|
24
|
+
## Price Classes
|
|
25
|
+
|
|
26
|
+
| Class | Description |
|
|
27
|
+
|---|---|
|
|
28
|
+
| [Price][quantflow.options.surface.Price] | Base bid/ask price for any security |
|
|
29
|
+
| [SpotPrice][quantflow.options.surface.SpotPrice] | Spot bid/ask price of an underlying asset |
|
|
30
|
+
| [FwdPrice][quantflow.options.surface.FwdPrice] | Forward bid/ask price at a specific maturity |
|
|
31
|
+
| [OptionPrice][quantflow.options.surface.OptionPrice] | Single-sided option price with implied volatility and convergence flag |
|
|
32
|
+
| [OptionPrices][quantflow.options.surface.OptionPrices] | Paired bid and ask [OptionPrice][quantflow.options.surface.OptionPrice] for a given strike and option type |
|
|
33
|
+
|
|
34
|
+
## Input Classes
|
|
35
|
+
|
|
36
|
+
The input classes are plain data containers used to serialize and deserialize volatility surface data,
|
|
37
|
+
for example when storing or transmitting a snapshot of the surface.
|
|
38
|
+
|
|
39
|
+
| Class | Description |
|
|
40
|
+
|---|---|
|
|
41
|
+
| [VolSurfaceInputs][quantflow.options.inputs.VolSurfaceInputs] | Top-level container: asset name, reference date, and a list of inputs |
|
|
42
|
+
| [VolSurfaceInput][quantflow.options.inputs.VolSurfaceInput] | Base input with bid, ask, open interest and volume |
|
|
43
|
+
| [SpotInput][quantflow.options.inputs.SpotInput] | Input for a spot price |
|
|
44
|
+
| [ForwardInput][quantflow.options.inputs.ForwardInput] | Input for a forward price with maturity |
|
|
45
|
+
| [OptionInput][quantflow.options.inputs.OptionInput] | Input for an option with strike, maturity, type, and optional implied vols |
|
|
46
|
+
|
|
47
|
+
A [VolSurface][quantflow.options.surface.VolSurface] can be round-tripped via:
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
inputs = surface.inputs() # VolSurface -> VolSurfaceInputs
|
|
51
|
+
surface = surface_from_inputs(inputs) # VolSurfaceInputs -> VolSurface
|
|
52
|
+
```
|
|
@@ -9,10 +9,32 @@
|
|
|
9
9
|
|
|
10
10
|
::: quantflow.options.surface.VolSurfaceLoader
|
|
11
11
|
|
|
12
|
+
::: quantflow.options.surface.VolCrossSectionLoader
|
|
13
|
+
|
|
14
|
+
## Bid/Ask Prices
|
|
15
|
+
|
|
16
|
+
::: quantflow.options.surface.Price
|
|
17
|
+
|
|
18
|
+
::: quantflow.options.surface.SpotPrice
|
|
19
|
+
|
|
20
|
+
::: quantflow.options.surface.FwdPrice
|
|
21
|
+
|
|
22
|
+
::: quantflow.options.surface.Strike
|
|
23
|
+
|
|
24
|
+
::: quantflow.options.surface.OptionArrays
|
|
25
|
+
|
|
26
|
+
::: quantflow.options.surface.OptionMetadata
|
|
27
|
+
|
|
12
28
|
::: quantflow.options.surface.OptionPrice
|
|
13
29
|
|
|
30
|
+
::: quantflow.options.surface.OptionPrices
|
|
31
|
+
|
|
14
32
|
::: quantflow.options.surface.OptionSelection
|
|
15
33
|
|
|
34
|
+
::: quantflow.options.inputs.OptionType
|
|
35
|
+
|
|
36
|
+
## Vol Surface Inputs
|
|
37
|
+
|
|
16
38
|
::: quantflow.options.inputs.VolSurfaceInputs
|
|
17
39
|
|
|
18
40
|
::: quantflow.options.inputs.VolSurfaceInput
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Bibliography
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
### carr_madan
|
|
6
|
+
|
|
7
|
+
Peter Carr, Dilip Madan
|
|
8
|
+
|
|
9
|
+
[Option Valuation Using the Fast Fourier Transform](https://doi.org/10.1002/(SICI)1097-0261(199904)2:1<61::AID-FUT4>3.0.CO;2-4)
|
|
10
|
+
|
|
11
|
+
Journal of Computational Finance, 2(4):61-73, 1999
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
### carr_wu
|
|
16
|
+
|
|
17
|
+
Peter Carr, Liuren Wu
|
|
18
|
+
|
|
19
|
+
[Time-Changed Lévy Processes and Option Pricing](https://doi.org/10.1016/S0304-405X(03)00171-5)
|
|
20
|
+
|
|
21
|
+
Journal of Financial Economics, 71(1):113-141, 2004
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
### chourdakis
|
|
26
|
+
|
|
27
|
+
Kyriakos Chourdakis
|
|
28
|
+
|
|
29
|
+
[Option Pricing Using the Fractional FFT](https://doi.org/10.21314/JCF.2005.102)
|
|
30
|
+
|
|
31
|
+
Journal of Computational Finance, 8(2):1-18, 2005
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
### molnar
|
|
36
|
+
|
|
37
|
+
Peter Molnar
|
|
38
|
+
|
|
39
|
+
[Volatility modeling and forecasting: utilization of realized volatility, implied volatility and the highest and lowest price of the day](https://drive.google.com/file/d/1zCU1OZyrKQLpxaypPv9U5UPbReBDXcMf/view)
|
|
40
|
+
|
|
41
|
+
Master's thesis, University of Economics in Prague, 2020
|
|
42
|
+
|
|
43
|
+
---
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from quantflow.options.inputs import OptionType
|
|
2
|
+
from quantflow.options.pricer import OptionPricer
|
|
3
|
+
from quantflow.sp.heston import HestonJ
|
|
4
|
+
from quantflow.utils.distributions import DoubleExponential
|
|
5
|
+
|
|
6
|
+
pricer = OptionPricer(
|
|
7
|
+
model=HestonJ.create(
|
|
8
|
+
DoubleExponential,
|
|
9
|
+
vol=0.5,
|
|
10
|
+
kappa=2,
|
|
11
|
+
rho=-0.2,
|
|
12
|
+
sigma=0.8,
|
|
13
|
+
jump_fraction=0.5,
|
|
14
|
+
jump_asymmetry=0.2,
|
|
15
|
+
)
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# Price an ATM call option at time to maturity 1.0
|
|
19
|
+
price = pricer.price(
|
|
20
|
+
option_type=OptionType.call,
|
|
21
|
+
strike=100.0,
|
|
22
|
+
forward=100.0,
|
|
23
|
+
ttm=1.0,
|
|
24
|
+
)
|
|
25
|
+
print(price.model_dump_json(indent=2))
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from quantflow.options.inputs import OptionType
|
|
2
|
+
from quantflow.options.pricer import OptionPricer
|
|
3
|
+
from quantflow.sp.weiner import WeinerProcess
|
|
4
|
+
from quantflow.utils.distributions import DoubleExponential
|
|
5
|
+
|
|
6
|
+
# Weiner process with constant volatility
|
|
7
|
+
# This produces the same sensitivities as the Black-Scholes model
|
|
8
|
+
pricer = OptionPricer(
|
|
9
|
+
model=WeinerProcess(sigma=0.3)
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
# Price an ATM call option at time to maturity 1.0
|
|
13
|
+
price = pricer.price(
|
|
14
|
+
option_type=OptionType.call,
|
|
15
|
+
strike=100.0,
|
|
16
|
+
forward=100.0,
|
|
17
|
+
ttm=1.0,
|
|
18
|
+
)
|
|
19
|
+
print(price.model_dump_json(indent=2))
|
|
@@ -1,24 +1,12 @@
|
|
|
1
|
-
---
|
|
2
|
-
jupytext:
|
|
3
|
-
text_representation:
|
|
4
|
-
extension: .md
|
|
5
|
-
format_name: myst
|
|
6
|
-
format_version: 0.13
|
|
7
|
-
jupytext_version: 1.16.6
|
|
8
|
-
kernelspec:
|
|
9
|
-
display_name: Python 3 (ipykernel)
|
|
10
|
-
language: python
|
|
11
|
-
name: python3
|
|
12
|
-
---
|
|
13
|
-
|
|
14
1
|
# Characteristic Function
|
|
15
2
|
|
|
16
|
-
The library makes heavy use of [characteristic function](https://en.wikipedia.org/wiki/Characteristic_function_(probability_theory))
|
|
3
|
+
The library makes heavy use of the [characteristic function](https://en.wikipedia.org/wiki/Characteristic_function_(probability_theory))
|
|
17
4
|
concept and therefore, it is useful to familiarize with it.
|
|
18
5
|
|
|
19
6
|
## Definition
|
|
20
7
|
|
|
21
|
-
The characteristic function of a random variable $x$ is the Fourier (inverse) transform of ${\mathbb P}_x$, where ${\mathbb P}_x$ is the
|
|
8
|
+
The characteristic function of a random variable $x$ is the Fourier (inverse) transform of ${\mathbb P}_x$, where ${\mathbb P}_x$ is the distribution measure of $x$
|
|
9
|
+
|
|
22
10
|
\begin{equation}
|
|
23
11
|
\Phi_{x,u} = {\mathbb E}\left[e^{i u x}\right] = \int e^{i u s} {\mathbb P}_x\left(ds\right)
|
|
24
12
|
\end{equation}
|
|
@@ -33,23 +21,23 @@ The characteristic function of a random variable $x$ is the Fourier (inverse) tr
|
|
|
33
21
|
* moments of $x$ are given by
|
|
34
22
|
|
|
35
23
|
\begin{equation}
|
|
36
|
-
{\mathbb E}\left[x^n\right] = i^{-n} \left.\frac{\Phi_{x, u}}{d u}\right|_{u=0}
|
|
24
|
+
{\mathbb E}\left[x^n\right] = i^{-n} \left.\frac{d\Phi_{x, u}}{d u}\right|_{u=0}
|
|
37
25
|
\end{equation}
|
|
38
26
|
|
|
39
|
-
##
|
|
27
|
+
## Convolution
|
|
40
28
|
|
|
41
|
-
The characteristic function is a great tool for working with linear
|
|
29
|
+
The characteristic function is a great tool for working with linear combinations of random variables.
|
|
42
30
|
|
|
43
31
|
* if $x$ and $y$ are independent random variables then the characteristic function of the linear combination $a x + b y$ ($a$ and $b$ are constants) is
|
|
44
32
|
|
|
45
33
|
\begin{equation}
|
|
46
|
-
\Phi_{ax+
|
|
34
|
+
\Phi_{ax+by,u} = \Phi_{x,a u}\Phi_{y,b u}
|
|
47
35
|
\end{equation}
|
|
48
36
|
|
|
49
37
|
* which means, if $x$ and $y$ are independent, the characteristic function of $x+y$ is the product
|
|
50
38
|
|
|
51
39
|
\begin{equation}
|
|
52
|
-
\Phi_{x+
|
|
40
|
+
\Phi_{x+y,u} = \Phi_{x,u}\Phi_{y,u}
|
|
53
41
|
\end{equation}
|
|
54
42
|
|
|
55
43
|
* The characteristic function of $ax+b$ is
|
|
@@ -79,11 +67,6 @@ The inversion formula for these distributions is given by
|
|
|
79
67
|
{\mathbb P}_x\left(x=k\right) = \frac{1}{2\pi}\int_{-\pi}^\pi e^{-iuk}\Phi_{k, u} du
|
|
80
68
|
\end{equation}
|
|
81
69
|
|
|
82
|
-
```{code-cell}
|
|
83
|
-
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
(characteristic-exponent)=
|
|
87
70
|
## Characteristic Exponent
|
|
88
71
|
|
|
89
72
|
The characteristic exponent $\phi_{x,u}$ is defined as
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Theory
|
|
2
|
+
|
|
3
|
+
QuantFlow is built around a unified mathematical framework based on **characteristic functions** and **Lévy processes**. This section introduces the core ideas that underpin the library's stochastic process models, Fourier inversion methods, and option pricing routines.
|
|
4
|
+
|
|
5
|
+
## Characteristic Functions
|
|
6
|
+
|
|
7
|
+
The [characteristic function](./characteristic.md) of a random variable $x$ is its Fourier transform under the probability measure:
|
|
8
|
+
|
|
9
|
+
$$
|
|
10
|
+
\Phi_{x,u} = \mathbb{E}\left[e^{iux}\right]
|
|
11
|
+
$$
|
|
12
|
+
|
|
13
|
+
It is the central computational object throughout the library. Unlike the probability density function, the characteristic function is always well-defined, bounded, and closed under convolution of independent random variables. This makes it the natural tool for working with Lévy processes, where densities are often unavailable in closed form.
|
|
14
|
+
|
|
15
|
+
## Lévy Processes
|
|
16
|
+
|
|
17
|
+
A [Lévy process](./levy.md) $x_t$ has independent and stationary increments, and its characteristic function factors cleanly over time:
|
|
18
|
+
|
|
19
|
+
$$
|
|
20
|
+
\Phi_{x_t, u} = e^{-t\,\phi_{x_1, u}}
|
|
21
|
+
$$
|
|
22
|
+
|
|
23
|
+
where $\phi_{x_1,u}$ is the **characteristic exponent** at unit time, given by the Lévy-Khintchine formula.
|
|
24
|
+
|
|
25
|
+
The library extends this to **time-changed Lévy processes** $y_t = x_{\tau_t}$, where $\tau_t$ is a stochastic clock driven by an intensity process $\lambda_t$. When $\tau_t$ and $x_t$ are independent, the characteristic function of $y_t$ reduces to the Laplace transform of the integrated intensity:
|
|
26
|
+
|
|
27
|
+
$$
|
|
28
|
+
\Phi_{y_t, u} = \mathcal{L}_{\tau_t}\!\left(\phi_{x_1, u}\right)
|
|
29
|
+
$$
|
|
30
|
+
|
|
31
|
+
This structure includes the Heston stochastic volatility model and its jump extensions as special cases, where the intensity process follows a CIR (Cox-Ingersoll-Ross) dynamics.
|
|
32
|
+
|
|
33
|
+
## Fourier Inversion
|
|
34
|
+
|
|
35
|
+
Given the characteristic function, the [probability density function](./inversion.md) is recovered via inverse Fourier transform. The library implements two numerical schemes:
|
|
36
|
+
|
|
37
|
+
- **Trapezoidal / Simpson integration** (default) using the Fractional FFT (FRFT), which allows the frequency and space domains to be discretized independently.
|
|
38
|
+
- **Standard FFT**, available as an alternative, with the constraint that $\delta_u \cdot \delta_x = 2\pi / N$.
|
|
39
|
+
|
|
40
|
+
The FRFT is preferred in practice as it achieves higher accuracy with fewer points.
|
|
41
|
+
|
|
42
|
+
## Option Pricing
|
|
43
|
+
|
|
44
|
+
[European call options](./option_pricing.md) are priced by applying the Fourier inversion machinery to the damped call payoff. For an underlying $S_t = S_0 e^{s_t}$ with log-price process $s_t = x_t - c_t$ (where $c_t$ is the convexity correction ensuring the forward is a martingale), the call price in log-moneyness $k = \ln(K/S_0)$ is:
|
|
45
|
+
|
|
46
|
+
$$
|
|
47
|
+
c_k = \frac{e^{-\alpha k}}{\pi} \int_0^\infty e^{-ivk}\, \Psi(v - i\alpha)\, dv, \qquad
|
|
48
|
+
\Psi_u = \frac{\Phi_{s_t}(u-i)}{iu(iu+1)}
|
|
49
|
+
$$
|
|
50
|
+
|
|
51
|
+
The same numerical transforms used for PDF inversion are reused here, making option pricing computationally efficient across all supported models.
|