PyQuantLib Documentation

License Python

Modern Python bindings for QuantLib

PyQuantLib provides Python bindings for QuantLib, the open-source library for quantitative finance.

Motivation

There are existing Python bindings for QuantLib:

  • QuantLib-SWIG: official bindings generated using SWIG

  • PyQL: bindings implemented using Cython

Both are mature projects. However, they introduce an additional language beyond C++ and Python: SWIG’s interface definition language or Cython’s hybrid syntax. This increases cognitive load when navigating binding code or keeping wrappers in sync with upstream QuantLib.

PyQuantLib is built on pybind11, with all bindings written in standard C++. No intermediate DSL or code generation step.

Pythonic API

Pass Python types directly to functions:

result = ql.DotProduct([1, 2, 3], [4, 5, 6])
transposed = ql.transpose([[1, 2], [3, 4]])
date = ql.Date(15, ql.June, 2025)  # or datetime.date(2025, 6, 15)

Zero-Copy NumPy Integration

Buffer protocol for efficient, bidirectional data exchange:

arr = ql.Array([1, 2, 3, 4, 5])
np_view = np.array(arr, copy=False)  # shared memory, no copy

Developer Experience

  • No additional language beyond C++ and Python (no SWIG, no Cython)

  • Type-safe bindings resolved at compile time (signature mismatches fail at build, not runtime)

  • Debugging with standard C++ tools (no generated code obscuring the call stack)

  • Wrapper code mirrors QuantLib headers and class structure

  • IDE autocompletion via .pyi type stubs

API Design

PyQuantLib preserves QuantLib’s domain model – class names, method names, and inheritance hierarchy – so that QuantLib documentation, textbooks, and community knowledge transfer directly to Python. But not everything in QuantLib’s API is a QuantLib concept. Handle<T> wrappers, builder method chaining, and Null<Rate>() sentinels are C++ idioms solving problems Python does not have. PyQuantLib replaces each with its Python equivalent: plain objects instead of handles, keyword arguments instead of method chaining, None instead of null sentinels.

See API Design for the full story.

Performance

PyQuantLib uses pybind11, which provides a thin, low-overhead C++/Python boundary. Function calls are dispatched directly to QuantLib’s C++ implementation, with no runtime code generation or reflection.

In practice, the dominant cost in typical QuantLib usage (pricing, curve construction, calibration) remains the underlying C++ computation, not the binding layer. Where applicable, PyQuantLib supports zero-copy data exchange with NumPy arrays.

As with any Python binding, performance-critical loops should remain in C++. PyQuantLib is designed to expose QuantLib’s APIs efficiently, while preserving Python’s productivity for orchestration, configuration, and analysis.

Features

  • Pythonic API: Implicit conversion, hidden handles, native datetime.date

  • NumPy integration: Zero-copy data exchange via buffer protocol

  • Type hints: IDE-friendly with complete .pyi stubs

  • Python subclassing: Extend QuantLib classes without C++ recompilation

  • Modern tooling: scikit-build-core, CMake presets, CI/CD ready

Quick Example

import pyquantlib as ql

# Set evaluation date
today = ql.Date(15, 6, 2025)
ql.Settings.evaluationDate = today

# Market data
spot = ql.SimpleQuote(100.0)
rate = ql.SimpleQuote(0.05)
vol = ql.SimpleQuote(0.20)

# Term structures (pass quotes directly, handles created internally)
dc = ql.Actual365Fixed()
risk_free = ql.FlatForward(today, rate, dc)
dividend = ql.FlatForward(today, 0.0, dc)
volatility = ql.BlackConstantVol(today, ql.TARGET(), vol, dc)

# Black-Scholes process (pass objects directly)
process = ql.GeneralizedBlackScholesProcess(spot, dividend, risk_free, volatility)

# European call option
payoff = ql.PlainVanillaPayoff(ql.Call, 100.0)
exercise = ql.EuropeanExercise(today + ql.Period("1Y"))
option = ql.VanillaOption(payoff, exercise)

# Price with analytic Black-Scholes
option.setPricingEngine(ql.AnalyticEuropeanEngine(process))

print(f"NPV:   {option.NPV():.4f}")    # 10.4506
print(f"Delta: {option.delta():.4f}")  # 0.6368
print(f"Gamma: {option.gamma():.4f}")  # 0.0188
print(f"Vega:  {option.vega():.4f}")   # 37.5240
print(f"Theta: {option.theta():.4f}")  # -6.4140

Documentation

License

BSD 3-Clause License. See LICENSE for details.

Acknowledgments