Usage
quantplus is designed around a straightforward numerical-finance workflow:
price an option using a CRR binomial lattice, compare the result against the
Black-Scholes closed form, and inspect tree values when needed for debugging or
visualization.
The package is intentionally small and exposes a few top-level functions:
quantplus.crr_price()for CRR option pricingquantplus.black_scholes_price()for the benchmark formulaquantplus.crr_tree()for examining terminal stock prices and payoffsquantplus.plot_crr_tree()for an interactive thresholded tree view
Importing the package
import quantplus as qp
This is the standard import pattern used in the examples below.
How the package is organized
The source tree is organized as follows:
quantplus/
├── __init__.py
├── _crr_pricer.pyx
├── plotting.py
├── csrc/
│ ├── crr_core.cpp
│ └── crr_core.h
└── tests/
└── test_quantplus.py
A few important points:
quantplus/__init__.pyre-exports the public Python functions.quantplus/_crr_pricer.pyxis the Cython bridge between Python and native C++ code.quantplus/plotting.pyprovides the optional interactive Matplotlib view.quantplus/csrc/crr_core.cppcontains the numerical implementation for the CRR and Black-Scholes pricing logic.quantplus/tests/test_quantplus.pycontains regression and validation tests.
This split is useful because Python is best for ergonomics and API design, while C++ is excellent for performance-sensitive root-finding, loops, and lattice operations.
CRR option pricing
The core function is quantplus.crr_price(). It values a European or
American option by building a binomial tree and recursively evaluating the value
at each node.
price = qp.crr_price(
S0=100.0,
K=100.0,
r=0.05,
sigma=0.20,
T=1.0,
N=200,
q=0.01,
is_call=True,
american=False,
)
print(price)
Parameter meaning
S0: current underlying priceK: strike pricer: continuously compounded risk-free ratesigma: volatilityT: time to maturity in yearsN: number of time steps in the CRR treeq: dividend yield or cost-of-carry adjustmentis_call:Truefor a call,Falsefor a putamerican:Truefor American exercise,Falsefor European exercise
The implementation validates common edge cases such as non-positive time to maturity, non-positive step counts, and negative volatility.
Threshold-pruned pricing
The CRR pricer can restrict the tree to an inclusive stock-price band. Bounds
apply to expiry nodes by default. With every_step=True, intermediate nodes
outside the band are also pruned. Earlier nodes are considered alive only when
they can reach an allowed terminal node (and, in every-step mode, are themselves
inside the band).
bounded_call = qp.crr_price(
S0=100.0,
K=100.0,
r=0.05,
sigma=0.20,
T=1.0,
N=200,
q=0.01,
is_call=True,
american=True,
S_lower=80.0,
S_upper=120.0,
every_step=False,
)
every_step_call = qp.crr_price(
S0=100.0, K=100.0, r=0.05, sigma=0.20, T=1.0, N=200,
q=0.01, is_call=True, american=True,
S_lower=80.0, S_upper=120.0, every_step=True,
)
When both child nodes survive, the usual risk-neutral probabilities are used.
When only one child survives, it receives the remaining probability. Bounds that
are reversed or leave no terminal node reachable from the root raise
ValueError.
European vs American options
The difference between European and American exercise is controlled by the
american flag.
european_call = qp.crr_price(
S0=100.0,
K=100.0,
r=0.05,
sigma=0.20,
T=1.0,
N=200,
q=0.01,
is_call=True,
american=False,
)
american_call = qp.crr_price(
S0=100.0,
K=100.0,
r=0.05,
sigma=0.20,
T=1.0,
N=200,
q=0.01,
is_call=True,
american=True,
)
print(european_call)
print(american_call)
American options are at least as valuable as their European counterparts because exercising early is a right, not an obligation.
Black-Scholes benchmark
For closed-form comparison, use quantplus.black_scholes_price().
This implements the standard Black-Scholes-Merton formula and is often used to
check whether the CRR price converges as the lattice becomes finer.
bs_price = qp.black_scholes_price(
S0=100.0,
K=100.0,
r=0.05,
sigma=0.20,
T=1.0,
q=0.01,
is_call=True,
)
print(bs_price)
Interesting fact: as N becomes large, the CRR binomial price approaches the
Black-Scholes value. This makes the CRR model intuitive and also gives a useful
sanity check during testing.
Inspecting the tree
The quantplus.crr_tree() helper returns the root price, the terminal stock
values, and the terminal option values for the lattice. This is useful for
debugging, plotting, or understanding how the payoff evolves across the tree.
root, stocks, values = qp.crr_tree(
S0=100.0,
K=100.0,
r=0.05,
sigma=0.20,
T=1.0,
N=5,
q=0.01,
is_call=True,
)
print(root)
print(stocks)
print(values)
The call returns three items:
root: the option value at the tree rootstocks: the terminal stock prices at maturityvalues: the terminal option payoffs at maturity
Interactive tree plot
Use quantplus.plot_crr_tree() to visualize the lattice and adjust the
thresholds interactively. The red and green bars set the upper and lower bounds;
the checkbox switches between expiry-only and every-step filtering.
fig, ax = qp.plot_crr_tree(
S0=100.0,
K=100.0,
r=0.05,
sigma=0.20,
T=1.0,
N=30,
q=0.01,
is_call=True,
american=True,
S_lower=80.0,
S_upper=120.0,
show=True,
)
The function returns the Matplotlib (figure, axes) pair. Set show=False
to construct the figure without starting the GUI event loop. Matplotlib is needed
only when this plotting function is called.
Example: put option pricing
put_price = qp.crr_price(
S0=90.0,
K=100.0,
r=0.03,
sigma=0.25,
T=2.0,
N=500,
q=0.00,
is_call=False,
american=False,
)
print(f"European put price: {put_price:.4f}")
C++ and Python working together
The package is a good example of a hybrid numerical library:
Python defines the public API and validation logic.
The Cython bridge exposes a low-level extension module.
The native C++ implementation performs the numerical calculations.
The compiled extension is loaded by Python at import time.
The C++ layer is compiled as part of the extension module using setup.py and
Cython. This allows the runtime to call the C++ pricing functions directly while
keeping the end-user experience simple and Pythonic.
The performance benefit is especially noticeable in repeated lattice calculations, where the hot loop is executed in compiled C++ rather than pure Python.