Calibrate to the Market

Calibrate SABR to a Volatility Smile

The editable Java generates synthetic market vols from the selected true SABR parameters, then fits alpha, rho and nu with L-BFGS using adjoint gradients.

Smile definition
Fixed at 0.5 in this demo
Target market (synthetic)
SolverOptional
Java source
SabrCalibrationRiskStudio.java

This exact source runs in TeaVM. Form changes update its Java literals and reset manual edits.

import com.nablatensor.engine.ADouble;
import com.nablatensor.quant.Calibrator;
import com.nablatensor.quant.SabrHagan;

public final class SabrCalibrationRiskStudio {
  private static final double BETA = 0.5, F = 0.0500000000000, T = 1.00000000000, A_TRUE = 0.284000000000,
      R_TRUE = -0.310000000000, N_TRUE = 0.570000000000;
  private static final double[] K = {
    0.030, 0.038, 0.045, 0.055, 0.062, 0.070
  };
  public static void main(String[] args) {
    double[] target = new double[K.length];
    for (int i = 0; i < K.length; i++) target[i] = SabrHagan.blackVol(A_TRUE, BETA, R_TRUE, N_TRUE,
        F, K[i], T);
    Calibrator.Result r = Calibrator.of(rec -> {
      ADouble alpha = rec.input("alpha", 0.200000000000), rho = rec.input("rho", 0.00000000000),
          nu = rec.input("nu", 0.300000000000), beta = rec.constant(BETA), sse = rec.constant(0.0); for (int i = 0; i < K.length; i++) {
        ADouble d = SabrHagan.blackVol(rec, alpha, beta, rho, nu, F, K[i], T)
            .sub(target[i]); sse = sse.add(d.mul(d));
      }
      rec.output(sse);
    })
        .parameter("alpha", 0.200000000000, 1e-4, 2.0)
        .parameter("rho", 0.00000000000, -0.999, 0.999)
        .parameter("nu", 0.300000000000, 1e-4, 5.0)
        .maxIterations(80)
        .tolerance(1.00000000000e-12)
        .on("cpu")
        .solve();
    double alpha = r.parameters()
        .get("alpha"), rho = r.parameters()
        .get("rho"), nu = r.parameters()
        .get("nu");
    System.out.println("RESULT|" + alpha + "|" + rho + "|" + nu + "|" + r.objective() + "|" + r.iterations()
        + "|" + r.converged());
    for (int j = 0; j < K.length; j++) System.out.println("ROW|" + K[j] + "|" + target[j] + "|" + SabrHagan.blackVol(alpha,
        BETA, rho, nu, F, K[j], T));
  }
}
TeaVM compiles and runs the Java source above in this browser.
Implementation guide

Fit level, skew and curvature together

SABR calibration turns observed implied volatilities into model parameters that reproduce the market smile.

Core mechanism

An optimiser changes alpha, rho and nu to minimise residual error between model and market volatilities. Adjoint gradients provide the direction of change without separately finite-differencing each parameter.

Practical workflow

Choose quote conventions and weights, constrain parameters, inspect residuals by strike and expiry, and test parameter stability between calibration dates.

Key details

*Keywords: sabr calibration java, adjoint gradient calibration, volatility smile fit, L-BFGS option calibration, derivative-free vs gradient calibration*

Derivative-free smile calibration is an overnight batch. Record the objective once, get its exact gradient from one adjoint sweep per iteration, and it is a sub-second gradient fit.

Calibrator takes a *recording* that reads the parameters by name, builds the sum of squared residuals against the market, and calls rec.output(sse). It compiles that to one kernel; every L-BFGS iteration is a setInput + one adjoint sweep, so the gradient cost is one extra sweep regardless of the number of parameters.

The residual is driven to ~1e-25 and the known parameters are recovered to the printed precision. CalibrationTest asserts this and also checks the tape-level SabrHagan.blackVol against the plain-double reference to rounding.

The same machinery calibrates any recorded objective — a Heston characteristic function, a local-vol surface, a curve — by swapping the model function in the recording.

Scope and review point

A low objective value does not guarantee robust risk. Extrapolation, arbitrage checks, data quality and calibration stability need separate controls.