This repository implements and benchmarks Least Squares Monte Carlo (LSMC) pricing for American-style options on CPU and NVIDIA GPUs.
The first target is a clean reproduction of Fatica and Phillips, "Pricing American Options with Least Squares Monte Carlo on GPUs" (WHPCF 2013), using American put options under geometric Brownian motion. The code is organized as a public Python package with a traditional NumPy CPU backend and a CuPy CUDA GPU backend.
The ACM paper PDF is not redistributed here. Reference values used by the reproduction scripts are encoded as small CSV tables in data/reference/.
This work is based on:
Pricing American Options with Least Squares Monte Carlo on GPUs
- Authors: Massimiliano Fatica and Everett Phillips, NVIDIA
- Venue: WHPCF 2013
- DOI:
10.1145/2535557.2535564 - Focus: Longstaff-Schwartz LSMC for American option pricing on CUDA GPUs
- Reported result: an American put with
200,000paths and50time steps priced in under10 mson a Tesla K20X
The paper emphasizes that most of the interesting acceleration comes from keeping simulation data on the GPU and mapping the backward regression phase to GPU-friendly reductions and small normal-equation solves.
This repo provides a public Python reproduction scaffold for the Fatica and Phillips LSMC setup.
Key additions:
- Standard
src/package layout for public GitHub use - Plain
pipinstallation with a single requirements file - CPU baseline LSMC using NumPy
- GPU LSMC using CuPy CUDA arrays and normal equations
- Paper reference tables as CSV data
- CLI for pricing, reproduction, benchmarking, and environment diagnostics
- Unit tests and optional GPU parity tests
- Clear benchmark reporting for reproducible American put workloads
- American put LSMC: Longstaff-Schwartz backward induction for early exercise
- CPU backend: NumPy path generation and QR/lstsq or normal-equation regression
- GPU backend: CuPy path generation, GPU-resident backward induction, and normal-equation regression
- Basis functions: Monomial and weighted Laguerre bases
- Variance reduction: Antithetic variates and moment matching
- Reproduction scripts: Regenerate paper-style comparison tables
- Benchmark outputs: CSV, environment metadata, and optional runtime plots
- CUDA diagnostics: Detects GPU, driver, CuPy, CUDA runtime, and package versions
Deferred v2 ideas include Sobol/quasi-Monte Carlo, European control variates, native CUDA C++ kernels, and multi-right exercise benchmarks.
GPU speedups are workload-dependent. The current implementation prioritizes a clear, reproducible Python version of the paper-style American put setup.
| Component | Value |
|---|---|
| GPU | NVIDIA RTX 2000 Ada Generation Laptop GPU |
| GPU memory | 8 GB |
| Driver CUDA | 13.2 |
| Python | 3.12 |
| GPU package | CuPy 14.1.1 |
Parameters: American put, K=40, r=0.06, 100,000 paths, 50 time steps per year, four monomial basis terms.
| S0 | Sigma | T | Finite difference | Longstaff-Schwartz paper | Paper GPU |
|---|---|---|---|---|---|
| 36 | 0.20 | 1 | 4.478 | 4.472 | 4.473 |
| 36 | 0.20 | 2 | 4.840 | 4.821 | 4.854 |
| 36 | 0.40 | 1 | 7.101 | 7.091 | 7.098 |
| 36 | 0.40 | 2 | 8.508 | 8.488 | 8.501 |
| 38 | 0.20 | 1 | 3.250 | 3.244 | 3.248 |
| 38 | 0.20 | 2 | 3.745 | 3.735 | 3.746 |
| 38 | 0.40 | 1 | 6.148 | 6.139 | 6.138 |
| 38 | 0.40 | 2 | 7.670 | 7.669 | 7.663 |
| 40 | 0.20 | 1 | 2.314 | 2.313 | 2.309 |
| 40 | 0.20 | 2 | 2.885 | 2.879 | 2.877 |
| 40 | 0.40 | 1 | 5.312 | 5.308 | 5.305 |
| 40 | 0.40 | 2 | 6.920 | 6.921 | 6.909 |
| 42 | 0.20 | 1 | 1.617 | 1.617 | 1.616 |
| 42 | 0.20 | 2 | 2.212 | 2.206 | 2.204 |
| 42 | 0.40 | 1 | 4.582 | 4.588 | 4.578 |
| 42 | 0.40 | 2 | 6.248 | 6.243 | 6.233 |
| 44 | 0.20 | 1 | 1.110 | 1.118 | 1.112 |
| 44 | 0.20 | 2 | 1.690 | 1.675 | 1.684 |
| 44 | 0.40 | 1 | 3.948 | 3.957 | 3.944 |
| 44 | 0.40 | 2 | 5.647 | 5.622 | 5.627 |
Parameters: S0=36, K=40, r=0.06, sigma=0.20, T=1, 524,288 paths, 50 time steps, float64.
| Backend | Solver | Price | RNG (s) | Path gen (s) | Regression (s) | Total (s) | Speedup |
|---|---|---|---|---|---|---|---|
| CPU NumPy | QR / lstsq | 4.4720 | 0.175 | 0.306 | 1.654 | 2.151 | 1.0x |
| GPU CuPy | Normal equations | 4.4712 | 0.142 | 0.099 | 0.849 | 1.090 | 2.0x |
This is a high-level Python/CuPy implementation, so it validates the GPU workflow but does not claim the full Tesla K20X-style optimized CUDA C performance from the paper.
To run locally on an NVIDIA machine, clone the repository and install the Python dependencies:
git clone https://github.com/ryan-racer/LSMC_CUDA.git
cd lsmc-cuda
pip install -r requirements.txtRequires an NVIDIA driver with CUDA support. A system CUDA Toolkit or nvcc is not required for the default CuPy wheel path.
Check the environment:
python lsmc.py doctorPrice one American put on CPU:
python lsmc.py price --backend cpu --spot 36 --strike 40 --sigma 0.2 --rate 0.06 --maturity 1Price one American put on GPU:
python lsmc.py price --backend gpu --spot 36 --strike 40 --sigma 0.2 --rate 0.06 --maturity 1Run the CPU reproduction:
python lsmc.py reproduce-paper --backend cpu --output-dir outputs/reproductionRun the GPU reproduction:
python lsmc.py reproduce-paper --backend gpu --output-dir outputs/reproduction-gpuThe default reproduction grid follows the paper's American put setup:
- Strike
K=40 - Risk-free rate
r=0.06 - Spot prices
36,38,40,42,44 - Volatilities
0.20,0.40 - Maturities
1,2 100,000paths50time steps per year- Four monomial basis terms
For quick smoke tests, reduce path count and steps:
python lsmc.py reproduce-paper --backend cpu --paths 200 --steps-per-year 5 --output-dir outputs/smoke-reproductionRun an end-to-end benchmark:
python lsmc.py benchmark --backends cpu,gpu --paths 10000,50000,100000 --output-dir outputs/benchmarksRun a shared-normal benchmark, where CPU and GPU use the same random shocks:
python lsmc.py benchmark --backends cpu,gpu --paths 10000,50000,100000 --shared-normals --output-dir outputs/benchmarks-sharedBenchmark outputs include:
runtime_benchmark.csvenvironment.jsonruntime_benchmark.pngunless--no-plotis passed
src/lsmc_cuda/
analytics.py Black-Scholes diagnostic formula
basis.py Monomial and weighted Laguerre bases
benchmarking.py CPU/GPU benchmark workflow
cli.py lsmc command line interface
config.py Dataclasses for params, config, results
cpu.py NumPy LSMC backend
gpu.py CuPy CUDA LSMC backend
paths.py GBM path and random shock generation
reproduce.py Paper reproduction workflows
benchmarks/ Script wrappers for benchmark runs
data/reference/ Paper reference tables as CSV
docs/ Reproduction notes
examples/ Minimal library usage examples
tests/ Unit and CPU/GPU smoke tests
CPU:
- Python
3.12 - NumPy
- SciPy
- pandas
- matplotlib
- Typer
- Rich
GPU:
- NVIDIA GPU and recent driver
- CuPy CUDA wheel installed from
requirements.txt - No system
nvccis required for the default CuPy wheel path
Fatica, M., and Phillips, E. (2013). "Pricing American Options with Least Squares Monte Carlo on GPUs." Proceedings of the 6th Workshop on High Performance Computational Finance. DOI: 10.1145/2535557.2535564.
Longstaff, F. A., and Schwartz, E. S. (2001). "Valuing American Options by Simulation: A Simple Least-Squares Approach." Review of Financial Studies.
MIT License. See LICENSE.