QuantLib icon indicating copy to clipboard operation
QuantLib copied to clipboard

Add ql.ZabrSwaptionVolatilityCube()

Open LZ1153 opened this issue 1 month ago • 2 comments

We have ql.SabrSwaptionVolatilityCube() please can expert make one Zabr version? I can see we do have Zabr interpolation but it will be great to have ql.ZabrSwaptionVolatilityCube()

LZ1153 avatar Nov 02 '25 09:11 LZ1153

QuantLib currently provides ql.SabrSwaptionVolatilityCube for SABR-based swaption volatility cubes, but does not have a built-in ql.ZabrSwaptionVolatilityCube equivalent. However, since ZabrInterpolation is available (in the experimental volatility module), and the underlying architecture uses a templated XabrSwaptionVolatilityCube<Model> class that explicitly supports ZABR models alongside SABR variants, you can extend QuantLib to create a ZABR version. This requires modifying the C++ source code, adding SWIG bindings for Python exposure, and recompiling the library. Below, I'll outline the steps as an expert implementation guide, including code snippets to add. This assumes you have the QuantLib source code cloned from GitHub (e.g., version 1.36 or later, as of November 2025) and are comfortable building it. Step 1: Define the ZABR Model Struct The XabrSwaptionVolatilityCube template relies on a model struct that specifies the interpolation and smile section types. For SABR, this is SwaptionVolCubeSabrModel, which uses SabrInterpolation and SabrSmileSection. For ZABR, add a similar struct. ZABR has an additional parameter (gamma), so ensure your usage accounts for it in parameter guesses and fixed flags (vector of 5 booleans instead of 4). Also, ZABR supports different evaluation kernels (e.g., short-maturity normal, local volatility)—choose one based on your needs. For example, use the short-maturity kernel for efficiency in short expiries. Edit ql/termstructures/volatility/swaption/sabrswaptionvolatilitycube.hpp (or create a new header like zabrswaptionvolatilitycube.hpp in the same directory for cleanliness). Add the following:

#include <ql/experimental/volatility/zabrinterpolation.hpp>
#include <ql/experimental/volatility/zabrsmilesection.hpp>

// Define the model struct for ZABR (example using short-maturity kernel; adjust as needed)
struct SwaptionVolCubeZabrModel {
    typedef ZabrInterpolation<detail::ZabrShortKernel> interpolation;  // Or use ZabrLocalVolatilityKernel, ZabrFullKernel, etc.
    typedef detail::ZabrSmileSection<detail::ZabrShortKernel> smileSection;  // Match the kernel
};

// Typedef the ZABR cube using the generic template
typedef XabrSwaptionVolatilityCube<SwaptionVolCubeZabrModel> ZabrSwaptionVolatilityCube;

Note: If using a different kernel (e.g., ZabrLocalVolatilityKernel), update the typedefs accordingly. Check zabrinterpolation.hpp and zabrsmilesection.hpp for available options and ensure compatibility (e.g., the interface must match what XabrSwaptionVolatilityCube expects for fitting and interpolation). Step 2: Adjust for ZABR's Extra Parameter (Gamma) The generic cube assumes a model with parameters like alpha, beta, nu, rho (4 for SABR), but ZABR adds gamma (5 total). The template handles this flexibly via the parametersGuess (a vector of vectors of quotes) and isParameterFixed (vector).

In your code, provide 5 elements in isParameterFixed (e.g., for fixing beta and gamma if desired). parametersGuess should be sized accordingly (nOptionTenors x nSwapTenors x 5). During fitting, the optimization will handle the extra parameter since ZabrInterpolation supports it internally.

If the template's fitting logic (e.g., in sabrCalibrationSection) hardcodes 4 parameters, you'll need to generalize it slightly—inspect the source, but from documentation, it's model-agnostic via the template. Step 3: Add SWIG Bindings for Python To expose ql.ZabrSwaptionVolatilityCube in Python, edit the SWIG interface file QuantLib/quantlib.i or the specific swaption volatility SWIG file (e.g., swaptionvolstructure.i). Add the template instantiation:

%template(ZabrSwaptionVolatilityCube) QuantLib::XabrSwaptionVolatilityCube<SwaptionVolCubeZabrModel>;

This will make ql.ZabrSwaptionVolatilityCube available in Python, with the same constructor signature as ql.SabrSwaptionVolatilityCube. Step 4: Build and Install QuantLib

Recompile QuantLib with the changes: Follow the standard build instructions (e.g., using CMake or Autotools). For Python bindings: Ensure Boost and SWIG are installed, then build/install the Python module (e.g., python setup.py install from the QuantLib-Python directory). Test: In Python, import quantlib as ql and instantiate ql.ZabrSwaptionVolatilityCube(...) with your ATM vol structure, tenors, spreads, etc.

Example Usage in Python (After Building)

import QuantLib as ql

# Assume you have your inputs: atmVol, optionTenors, swapTenors, strikeSpreads, volSpreads, etc.
# parametersGuess should be a list of lists with 5 params per point (alpha, beta, nu, rho, gamma)
# isParameterFixed = [False, True, False, False, True]  # e.g., fix beta and gamma

cube = ql.ZabrSwaptionVolatilityCube(
    atmVolHandle,
    optionTenors,
    swapTenors,
    strikeSpreads,
    volSpreads,
    swapIndex,
    shortSwapIndex,
    vegaWeighted=True,
    parametersGuess=parametersGuess,
    isParameterFixed=isParameterFixed,
    isAtmCalibrated=True
)

# Use it like the SABR version, e.g., cube.volatility(optionDate, swapTenor, strike)

Caveats and Testing

Parameter Count: Verify the fitting works with 5 params; if the cube's internal Cube objects (for param interpolation) assume 4 layers, add a fifth Cube for gamma in the class implementation. Experimental Status: ZABR is in experimental/volatility, so it may require defining QL_ENABLE_EXPERIMENTAL or similar in your build flags. Calibration: ZABR calibration can be slower/more sensitive due to the extra param—tune endCriteria, optMethod, and maxGuesses. Validation: Test against known ZABR smiles or compare with SABR (set gamma=1 to mimic SABR). If this is for production, submit a pull request to QuantLib's GitHub for official inclusion.

richardsb1103 avatar Nov 02 '25 14:11 richardsb1103

Mostly correct but there are a few hallucinations. details:: ZabrShortKernel and similar classes don't exist; the available structs are

struct ZabrShortMaturityLognormal {};
struct ZabrShortMaturityNormal {};
struct ZabrLocalVolatility {};
struct ZabrFullFd {};

Also, QL_ENABLE_EXPERIMENTAL doesn't exist either and is not needed.

(In general, when posting AI-generated content, it would be better to at least say it, even when it's kind of obvious. This way people will know that the posted code was not checked. Thanks!)

lballabio avatar Nov 05 '25 11:11 lballabio