Quick Start

This guide walks through a first PyQuantLib program: pricing a European call option using the Black-Scholes model.

Note

This guide assumes PyQuantLib is installed. See Installation for setup instructions.

Basic Usage

Import and Setup

import pyquantlib as ql

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

The evaluation date is a global setting that determines “today” for all pricing calculations. Always set this before creating term structures or pricing instruments.

Market Data with Quotes

PyQuantLib uses Quote objects to represent market observables:

# Create quotes for market data
spot = ql.SimpleQuote(100.0)    # Underlying price
rate = ql.SimpleQuote(0.05)     # Risk-free rate (5%)
vol = ql.SimpleQuote(0.20)      # Volatility (20%)

Quotes are observable: when a quote’s value changes, any dependent calculations automatically update.

Term Structures

Term structures describe how rates or volatilities vary over time:

dc = ql.Actual365Fixed()  # Day counter for year fractions

# Flat risk-free rate curve (pass quote directly)
risk_free = ql.FlatForward(today, rate, dc)

# Flat dividend yield curve
dividend = ql.FlatForward(today, 0.0, dc)

# Flat volatility surface (pass quote directly)
volatility = ql.BlackConstantVol(today, ql.TARGET(), vol, dc)

PyQuantLib supports hidden handles: pass objects directly without wrapping in QuoteHandle. Handles are created internally.

The Black-Scholes Process

Combine market data into a stochastic process:

process = ql.GeneralizedBlackScholesProcess(spot, dividend, risk_free, volatility)

Same here: pass term structures directly. PyQuantLib wraps them in handles internally.

Note

For advanced use cases requiring relinkable handles, explicit handle constructors are also available:

risk_free = ql.FlatForward(today, ql.QuoteHandle(rate), dc)
volatility = ql.BlackConstantVol(today, ql.TARGET(), ql.QuoteHandle(vol), dc)

process = ql.GeneralizedBlackScholesProcess(
    ql.QuoteHandle(spot),
    ql.YieldTermStructureHandle(dividend),
    ql.YieldTermStructureHandle(risk_free),
    ql.BlackVolTermStructureHandle(volatility),
)

Creating an Option

Define the option’s payoff and exercise:

# Call option with strike = 100
payoff = ql.PlainVanillaPayoff(ql.Call, 100.0)

# European exercise, 1 year to expiry
exercise = ql.EuropeanExercise(today + ql.Period("1Y"))

# Create the option instrument
option = ql.VanillaOption(payoff, exercise)

Pricing with an Engine

Assign a pricing engine and compute results:

# Use analytic Black-Scholes formula
engine = ql.AnalyticEuropeanEngine(process)
option.setPricingEngine(engine)

# Get results
print(f"NPV:   {option.NPV():.4f}")
print(f"Delta: {option.delta():.4f}")
print(f"Gamma: {option.gamma():.4f}")
print(f"Vega:  {option.vega():.4f}")
print(f"Theta: {option.theta():.4f}")

Output:

NPV:   10.4506
Delta: 0.6368
Gamma: 0.0188
Vega:  37.5240
Theta: -6.4140

Responding to Market Changes

Because Quote objects were used, the option automatically reprices when market data changes:

# Spot moves from 100 to 105
spot.setValue(105.0)
print(f"New NPV: {option.NPV():.4f}")  # Automatically updated

# Vol increases to 25%
vol.setValue(0.25)
print(f"New NPV: {option.NPV():.4f}")  # Updated again

Module Organization

PyQuantLib exposes QuantLib classes in a flat namespace:

import pyquantlib as ql

# Time
ql.Date, ql.Period, ql.Calendar, ql.Schedule, ql.DayCounter

# Market data
ql.SimpleQuote, ql.QuoteHandle

# Term structures
ql.FlatForward, ql.ZeroCurve, ql.BlackConstantVol, ql.BlackVarianceSurface

# Processes
ql.GeneralizedBlackScholesProcess, ql.HestonProcess

# Instruments
ql.VanillaOption, ql.BasketOption

# Pricing engines
ql.AnalyticEuropeanEngine, ql.MCEuropeanEngine, ql.AnalyticHestonEngine

Enum Convenience

Enum values are exported to the root namespace for convenience:

# Both work identically
date1 = ql.Date(15, ql.Month.June, 2025)
date2 = ql.Date(15, ql.June, 2025)  # Shorter

# Same for weekdays, time units, etc.
ql.Monday             # ql.Weekday.Monday
ql.Months             # ql.TimeUnit.Months
ql.ModifiedFollowing  # ql.BusinessDayConvention.ModifiedFollowing

Abstract Base Classes

For subclassing QuantLib abstractions, import from pyquantlib.base:

from pyquantlib.base import Observer, Observable, LazyObject

Alternative Pricing Engines

Monte Carlo

# Monte Carlo with 100,000 paths
mc_engine = ql.MCEuropeanEngine(
    process,
    timeSteps=100,
    requiredSamples=100000,
    seed=42,
)
option.setPricingEngine(mc_engine)
print(f"MC NPV: {option.NPV():.4f}")

Heston Stochastic Volatility

# Heston model parameters
v0 = 0.04      # Initial variance
kappa = 1.0    # Mean reversion speed
theta = 0.04   # Long-term variance
sigma = 0.5    # Vol of vol
rho = -0.7     # Correlation

heston_process = ql.HestonProcess(
    risk_free, dividend, spot,
    v0, kappa, theta, sigma, rho,
)

heston_model = ql.HestonModel(heston_process)
heston_engine = ql.AnalyticHestonEngine(heston_model)

option.setPricingEngine(heston_engine)
print(f"Heston NPV: {option.NPV():.4f}")