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
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ docs: ## build documentation
@uv run ./dev/build-examples
@uv run mkdocs build

.PHONY: docs-bib
docs-bib: ## Regenerate docs bibliography
@uv run ./docs/bib2md.py

.PHONY: docs-examples
docs-examples: ## Regenerate docs examples
@uv run ./dev/build-examples
Expand Down
2 changes: 2 additions & 0 deletions docs/api/options/pricer.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ different stochastic volatility models.

::: quantflow.options.pricer.OptionPricerBase

::: quantflow.options.pricer.OptionPricingMethod

::: quantflow.options.pricer.OptionPricer

::: quantflow.options.pricer.MaturityPricer
Expand Down
3 changes: 3 additions & 0 deletions docs/api/sp/bns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Barndorff-Nielson & Shephard process

::: quantflow.sp.bns.BNS
2 changes: 2 additions & 0 deletions docs/api/sp/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,5 @@ This page gives an overview of all stochastic processes available in the library
::: quantflow.sp.base.StochasticProcess1D

::: quantflow.sp.base.IntensityProcess

::: quantflow.sp.base.StochasticProcess1DMarginal
2 changes: 2 additions & 0 deletions docs/api/sp/ou.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ These are the classes that implement gaussian and non-gaussian

## Non-Gaussian OU process

::: quantflow.sp.ou.NGOU

::: quantflow.sp.ou.GammaOU
14 changes: 13 additions & 1 deletion docs/api/utils/index.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# Utilities

This section contains utility functions and classes that are used throughout the library. They are not meant to be used directly by the user, but they can be useful for advanced users who want to extend the library or understand its inner workings.
This section contains utility functions and classes used throughout the library.
They are not meant to be used directly by the user, but can be useful for advanced
users who want to extend the library or understand its inner workings.

## Classes

| 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.) |
195 changes: 195 additions & 0 deletions docs/bib2md.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
#!/usr/bin/env python3
"""Convert docs/references.bib to docs/bibliography.md.

Usage:
uv run python docs/bib2md.py [--bib PATH] [--out PATH]

The BibTeX file is the source of truth; run this script whenever it changes.
"""
from __future__ import annotations

import argparse
import re
import sys
from pathlib import Path

# ---------------------------------------------------------------------------
# Parser
# ---------------------------------------------------------------------------

_ENTRY_RE = re.compile(
r"@(\w+)\s*\{\s*([\w][\w:/-]*)\s*,\s*(.*?)\n\}",
re.DOTALL,
)
_FIELD_RE = re.compile(
r"""(\w+)\s*=\s*(?:\{((?:[^{}]|\{[^{}]*\})*)\}|"([^"]*)")""",
re.DOTALL,
)


def _strip_braces(text: str) -> str:
"""Remove single-level LaTeX capitalisation braces, e.g. {Lévy} -> Lévy."""
return re.sub(r"\{([^{}]*)\}", r"\1", text)


def _clean(value: str) -> str:
text = _strip_braces(" ".join(value.split()))
# Convert LaTeX en-dash (--) to a plain hyphen
return text.replace("--", "-")


def parse_bib(text: str) -> list[dict[str, str]]:
entries = []
for m in _ENTRY_RE.finditer(text):
entry: dict[str, str] = {
"type": m.group(1).lower(),
"key": m.group(2),
}
for fm in _FIELD_RE.finditer(m.group(3)):
raw = fm.group(2) if fm.group(2) is not None else fm.group(3)
entry[fm.group(1).lower()] = _clean(raw)
entries.append(entry)
return entries


# ---------------------------------------------------------------------------
# Author formatting
# ---------------------------------------------------------------------------

def _format_single_author(author: str) -> str:
"""Convert 'Lastname, Firstname' to 'Firstname Lastname'; leave others as-is."""
author = author.strip()
# Only reformat if a comma is clearly separating last from first name
# (avoid splitting on commas inside name suffixes or freeform strings)
parts = author.split(",", 1)
if len(parts) == 2:
last, first = parts[0].strip(), parts[1].strip()
# Sanity: last name should be a single word (no spaces)
if first and " " not in last:
return f"{first} {last}"
return author


def format_authors(author_field: str) -> str:
# Normalise separators: "and" and "&" both split authors
normalised = re.sub(r"\s+and\s+", " & ", author_field, flags=re.IGNORECASE)
authors = [a.strip() for a in normalised.split("&") if a.strip()]
return ", ".join(_format_single_author(a) for a in authors)


# ---------------------------------------------------------------------------
# Entry formatter
# ---------------------------------------------------------------------------

def _title_link(title: str, url: str) -> str:
if not url:
return title
return f'[{title}]({url}){{target="_blank" rel="noopener"}}'


def _journal_detail(entry: dict[str, str]) -> str:
"""Build 'Journal, Vol(Num):Pages' string."""
journal = entry.get("journal", "")
volume = entry.get("volume", "")
number = entry.get("number", "")
pages = entry.get("pages", "")
if not journal:
return ""
detail = journal
if volume:
vol_str = volume
if number:
vol_str += f"({number})"
if pages:
vol_str += f":{pages}"
detail += f", {vol_str}"
elif pages:
detail += f", {pages}"
return detail


def format_entry(entry: dict[str, str]) -> str:
key = entry["key"]
title = entry.get("title", "Unknown Title")
year = entry.get("year", "")
url = entry.get("url", "")
author = entry.get("author", "")

# Prefer doi as url when no url field present
if not url and "doi" in entry:
doi = entry["doi"].lstrip("doi:")
url = f"https://doi.org/{doi}"

author_str = format_authors(author) if author else ""
title_md = _title_link(title, url)
year_str = f"({year})" if year else ""

# Prefix: "Author(s). (Year)"
prefix_parts = []
if author_str:
prefix_parts.append(author_str.rstrip(".") + ".")
if year_str:
prefix_parts.append(year_str)
prefix = " ".join(prefix_parts)

# Suffix depends on entry type
entry_type = entry.get("type", "article")
if entry_type == "article":
suffix = _journal_detail(entry)
elif entry_type == "book":
suffix = entry.get("publisher", "")
elif entry_type in ("mastersthesis", "phdthesis"):
suffix = entry.get("school", "")
else:
suffix = entry.get("publisher", entry.get("school", ""))

body = f"{prefix} {title_md}" if prefix else title_md
if suffix:
body = f"{body}, {suffix}"

return f"#### {key}\n\n{body}\n"


# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------

def convert(bib_path: Path, out_path: Path) -> None:
text = bib_path.read_text(encoding="utf-8")
entries = parse_bib(text)
if not entries:
print(f"No entries found in {bib_path}", file=sys.stderr)
sys.exit(1)

entries.sort(key=lambda e: e["key"].lower())

lines = ["# Bibliography\n", "\n---\n"]
for entry in entries:
lines.append("\n")
lines.append(format_entry(entry))

out_path.write_text("".join(lines), encoding="utf-8")
print(f"Wrote {len(entries)} entries to {out_path}")


def main() -> None:
docs = Path(__file__).parent
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--bib",
type=Path,
default=docs / "references.bib",
help="Input BibTeX file (default: docs/references.bib)",
)
parser.add_argument(
"--out",
type=Path,
default=docs / "bibliography.md",
help="Output Markdown file (default: docs/bibliography.md)",
)
args = parser.parse_args()
convert(args.bib, args.out)


if __name__ == "__main__":
main()
62 changes: 56 additions & 6 deletions docs/bibliography.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,73 @@
# Bibliography

The raw BibTeX source for all entries is available in [references.bib](/references.bib).

---

#### bertoin

J. Bertoin. (1996) Lévy Processes, Cambridge University Press

#### bns

O.E. Barndorff-Nielsen, N. Shephard. (2001) [Non-Gaussian OU based models and some of their uses in financial economics](https://drive.google.com/file/d/11TnGl2ER_-QzEu_h7ZtGGass2rF8_u1Y/view){target="_blank" rel="noopener"}, Journal of the Royal Statistical Society, 63(2)

#### carr_madan

Peter Carr, Dilip Madan, [Option Valuation Using the Fast Fourier Transform](https://doi.org/10.21314/JCF.1999.043), Journal of Computational Finance, 2(4):61-73, 1999
P. Carr, D. Madan. (1999) [Option valuation using the fast Fourier transform](http://faculty.baruch.cuny.edu/lwu/890/CarrMadan99.pdf){target="_blank" rel="noopener"}, Journal of Computational Finance, 3:463-520

#### carr_wu

Peter Carr, Liuren Wu, [Time-Changed Lévy Processes and Option Pricing](https://doi.org/10.1016/S0304-405X(03)00171-5), Journal of Financial Economics, 71(1):113-141, 2004
P. Carr, L. Wu. (2002) [Time-changed Lévy processes and option pricing](https://engineering.nyu.edu/sites/default/files/2019-03/Carr-time-changed-levy-processes-option-pricing.pdf){target="_blank" rel="noopener"}, Journal of Financial Economics, 7:113-141

#### cgmy

Carr P., Geman H., Madan D.B., Yor M. (2003) [Stochastic Volatility for Lévy processes](https://engineering.nyu.edu/sites/default/files/2019-03/Carr-stochastic-volatility-levy-processes.pdf){target="_blank" rel="noopener"}, Mathematical Finance, 13(3)

#### chourdakis

Kyriakos Chourdakis, [Option Pricing Using the Fractional FFT](https://doi.org/10.21314/JCF.2005.137),Journal of Computational Finance, 8(2):1-18, 2005
K. Chourdakis. (2004) [Option Pricing Using the Fractional FFT](https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=6bdf4696312d37427eda2740137650c09deacda7){target="_blank" rel="noopener"}, Journal of Computational Finance, 8:1-18

#### cos

F. Fang, K. Oosterlee. (2008) [A Novel Pricing Method for European Options Based on Fourier-Cosine Series Expansions](https://mpra.ub.uni-muenchen.de/8914/4/MPRA_paper_8914.pdf){target="_blank" rel="noopener"}

#### dsp

Unknown. (2017) [Doubly Stochastic Poisson Processes with Affine Intensities](https://editorialexpress.com/cgi-bin/conference/download.cgi?db_name=sbe35&paper_id=179){target="_blank" rel="noopener"}, internet

#### ekf

Wang X., He X., Zhao Y., Zuo Z. (2017) [Parameter Estimations of Heston Model Based on Consistent Extended Kalman Filter](https://www.sciencedirect.com/science/article/pii/S2405896317324758){target="_blank" rel="noopener"}, internet

#### gamma-ou

P. Sabino, C. Petroni. (2021) [Gamma Related Ornstein-Uhlenbeck Processes and their Simulation](https://doi.org/10.1080/00949655.2020.1842408){target="_blank" rel="noopener"}, Journal of Statistical Computation and Simulation, 91(6)

#### heston-calibration

Milan Mrázek, Jan Pospíšil. (2017) [Calibration and simulation of Heston model](https://doi.org/10.1515/math-2017-0058){target="_blank" rel="noopener"}, Open Mathematics, 15(1):679-704

#### heston-simulation

Leif B.G. Andersen. (2008) [Efficient Simulation of the Heston Stochastic Volatility Model](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=946405){target="_blank" rel="noopener"}, Journal of Computational Finance, 11(3)

#### lee_option

R. W. Lee. (2004) [Option Pricing by Transform Methods: Extensions, Unification, and Error Control](https://www.math.uchicago.edu/~rl/dft.pdf){target="_blank" rel="noopener"}

#### lewis

A. L. Lewis. (2001) [A Simple Option Formula for General Jump-Diffusion and other Exponential Lévy Processes](https://drive.google.com/file/d/1JiYfyOU7lUKHrMqTRPbBCdasctwYDc4Z/view){target="_blank" rel="noopener"}

#### molnar

Peter Molnar, [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), Master's thesis, University of Economics in Prague, 2020
Peter Molnar. (2020) [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){target="_blank" rel="noopener"}, University of Economics in Prague

#### saez

G. K. G. Saez. (2014) [Fourier Transform Methods for Option Pricing: An Application to extended Heston-type Models](https://www.uv.es/bfc/TFM2014/008-014.pdf){target="_blank" rel="noopener"}, Universidad del Pais Vasco

#### Gauthier
#### ukf

Gauthier Godin & Legros, [Deep Implied Volatility Factor Models for Stock Options](https://drive.google.com/file/d/1Rjypn1IqnhpiZz08s0hxl5ISQDC8KeWk/view?usp=sharing), 2025
Merwe. (2014) [The Unscented Kalman Filter for Nonlinear Estimation](https://groups.seas.harvard.edu/courses/cs281/papers/unscented.pdf){target="_blank" rel="noopener"}, internet
Loading
Loading