33  Chapter 30. Model Risk, Calibration, and Financial AI

33.1 Learning Goals

By the end of this chapter, students should be able to:

  • explain model risk as the risk that a financial model is wrong, misused, poorly calibrated, or unstable outside its assumptions;
  • distinguish estimation, calibration, validation, backtesting, and stress testing;
  • formulate calibration as a weighted inverse problem;
  • diagnose identifiability, ill-conditioning, overfitting, extrapolation risk, and data leakage;
  • explain parameter uncertainty and model uncertainty using clean mathematical language;
  • use no-arbitrage restrictions as model-validation constraints;
  • understand how machine learning can be used for pricing, hedging, risk forecasting, and calibration surrogates;
  • describe the mathematical risks of AI-assisted financial modeling, including hallucinated formulas, hidden assumptions, regime shift, and false confidence;
  • write Python code to calibrate simple models, test robustness, and audit numerical outputs.

Mathematical finance is not only about deriving elegant formulas. It is also about knowing when formulas fail.

A model is a map

\[ M_\theta : \text{inputs} \longrightarrow \text{prices, hedges, risks, or decisions}, \]

where \(\theta\) is a vector of parameters. Calibration chooses parameters so that the model approximately matches observed market quantities:

\[ \widehat \theta = \arg\min_{\theta\in \Theta} \sum_{i=1}^n w_i\left(Y_i^{\mathrm{mkt}}-M_i(\theta)\right)^2. \]

This chapter studies the mathematics behind that optimization problem. We emphasize a central lesson: a calibrated model is not necessarily a correct model.

33.2 30.1 Why End with Model Risk?

The earlier chapters built a sequence of increasingly sophisticated models:

  • one-period no-arbitrage models;
  • binomial trees;
  • martingale pricing;
  • Brownian motion and Itô calculus;
  • Black–Scholes;
  • stochastic volatility;
  • jump models;
  • interest-rate models;
  • portfolio models;
  • risk measures;
  • credit-risk models.

Each model is useful because it reduces a complicated market problem to a mathematical structure. But every reduction loses information. The Black–Scholes model assumes continuous trading, constant volatility, no transaction costs, no jumps, and frictionless markets. A mean–variance portfolio model assumes that covariance is a sufficiently informative description of risk. A credit-intensity model assumes that default can be described by a stochastic intensity.

33.3 Model risk

Model risk is the risk of financial loss, poor decision-making, or misleading measurement caused by errors in model specification, calibration, implementation, interpretation, or use.

Model risk has several mathematical sources:

  1. Specification error: the true data-generating mechanism is not in the model family.
  2. Parameter uncertainty: even if the model family is reasonable, the parameter estimate is uncertain.
  3. Numerical error: the model is correct, but the computed output is inaccurate.
  4. Implementation error: the formula is coded incorrectly.
  5. Data error: the inputs are stale, noisy, biased, or inconsistent.
  6. Extrapolation error: the model is used outside the region where it was calibrated.
  7. Optimization error: calibration finds a local or unstable minimum.
  8. Governance error: users interpret model output as truth rather than as conditional output under assumptions.

Remark (The mathematical habit). Whenever a model produces a number, ask:

\[ \text{number} = \text{output of which function, under which assumptions, with which inputs?} \]

This question is more important than the number itself.

33.4 30.2 Models as Mathematical Maps

A model can be described as a parameterized map

\[ M_\theta:X\to Y, \]

where:

  • \(X\) is an input space;
  • \(Y\) is an output space;
  • \(\theta\in \Theta\) is a parameter vector;
  • \(M_\theta(x)\) is the model output for input \(x\).

For option pricing, \(x\) may contain spot price, strike, maturity, interest rate, dividend yield, and volatility. For risk management, \(x\) may contain positions, historical returns, risk factors, and horizon. For credit risk, \(x\) may contain exposure, recovery, default probability, and dependence parameters.

33.5 Black–Scholes as a map

For a European call option, the Black–Scholes model is the map

\[ M_\sigma(S_0,K,T,r)=S_0N(d_1)-Ke^{-rT}N(d_2), \]

where

\[ d_1= \frac{\log(S_0/K)+(r+\frac12\sigma^2)T}{\sigma\sqrt T}, \qquad d_2=d_1-\sigma\sqrt T. \]

If \(S_0\), \(K\), \(T\), and \(r\) are observed and the market call price is \(C^{\mathrm{mkt}}\), then implied volatility is a parameter \(\widehat\sigma\) satisfying approximately

\[ M_{\widehat\sigma}(S_0,K,T,r)=C^{\mathrm{mkt}}. \]

33.6 Model output error

Given observed quantities \(Y_i^{\mathrm{mkt}}\) and model quantities \(M_i(\theta)\), the residual is

\[ r_i(\theta)=Y_i^{\mathrm{mkt}}-M_i(\theta). \]

A small residual means the model fits the chosen observations. It does not prove that the model is true.

33.7 30.3 Estimation, Calibration, Validation, and Backtesting

Students often use the words estimation and calibration interchangeably. They are related but not identical.

33.8 Estimation

Estimation usually means choosing parameters from historical data under a statistical model. A typical estimator is

\[ \widehat\theta=\arg\max_{\theta\in\Theta} L(\theta;X_1,\ldots,X_n), \]

where \(L\) is a likelihood function.

33.9 Calibration

Calibration usually means choosing parameters so that the model matches observed market prices or curves. A typical calibration problem is

\[ \widehat\theta = \arg\min_{\theta\in\Theta} \sum_{i=1}^n w_i \left(Y_i^{\mathrm{mkt}}-M_i(\theta)\right)^2. \]

33.10 Validation

Validation is the process of checking whether the model is appropriate for its intended use. Validation includes checking assumptions, input quality, implementation, calibration stability, out-of-sample performance, and sensitivity to stress scenarios.

33.11 Backtesting

Backtesting compares model forecasts with realized outcomes. For a sequence of predicted losses or risk measures, backtesting studies whether realized data are statistically consistent with model predictions.

The distinction matters because different tasks use different probability measures. Historical estimation usually takes place under the physical measure \(\mathbb P\). Derivative pricing often takes place under a risk-neutral measure \(\mathbb Q\). Confusing these two is a common source of model misuse.

33.12 30.4 Calibration as an Inverse Problem

A forward problem computes model outputs from parameters:

\[ \theta \longmapsto M(\theta). \]

A calibration problem tries to invert this map from observed outputs:

\[ Y^{\mathrm{mkt}}\approx M(\theta). \]

This is an inverse problem. Inverse problems are often ill-conditioned: a small change in observed data may produce a large change in calibrated parameters.

33.13 Weighted least-squares calibration

Let \(Y^{\mathrm{mkt}}\in \mathbb R^n\) be observed market quantities and let \(M(\theta)\in \mathbb R^n\) be model outputs. Given weights \(w_i>0\), define

\[ J(\theta)= \sum_{i=1}^n w_i\left(Y_i^{\mathrm{mkt}}-M_i(\theta)\right)^2. \]

A calibrated parameter is any minimizer

\[ \widehat\theta\in\arg\min_{\theta\in\Theta}J(\theta). \]

Weights encode priorities. For example, one may put more weight on liquid instruments and less weight on stale or illiquid prices. A common statistical choice is

\[ w_i=\frac{1}{\operatorname{Var}(\varepsilon_i)}, \]

when the observation error satisfies

\[ Y_i^{\mathrm{mkt}}=M_i(\theta_0)+\varepsilon_i. \]

Remark (Calibration objective is a modeling choice). Choosing squared price errors, squared implied-volatility errors, relative errors, bid–ask normalized errors, or likelihood-based errors can produce different calibrated parameters. The objective function is part of the model.

33.14 30.5 First-Order Conditions and Sensitivity

Suppose \(M:\mathbb R^p\to\mathbb R^n\) is differentiable and

\[ J(\theta)=\|Y-M(\theta)\|_W^2 =(Y-M(\theta))^T W(Y-M(\theta)), \]

where \(W\) is a positive definite diagonal matrix. Let

\[ r(\theta)=Y-M(\theta), \]

and let \(D M(\theta)\) be the \(n\times p\) Jacobian matrix. Then

\[ \nabla J(\theta) = -2 D M(\theta)^T W r(\theta). \]

At an interior optimum \(\widehat\theta\),

\[ D M(\widehat\theta)^T W \left(Y-M(\widehat\theta)\right)=0. \]

This equation says that the weighted residual is orthogonal to the tangent space of model outputs at the calibrated point.

33.15 Local linear calibration sensitivity

Assume the model is locally approximated by

\[ M(\theta+\Delta\theta) \approx M(\theta)+A\Delta\theta, \]

where \(A=D M(\theta)\). Then the local least-squares parameter change produced by a data perturbation \(\Delta Y\) is approximately

\[ \Delta\theta \approx (A^TWA)^{-1}A^TW\Delta Y, \]

provided \(A^TWA\) is invertible.

This formula explains why calibration can be unstable. If \(A^TWA\) is nearly singular, then small market noise can produce large parameter changes.

33.16 Identifiability

A parameter \(\theta\) is identifiable from observations \(Y\) if different parameter values produce distinguishable model outputs. Locally, identifiability requires the Jacobian \(D M(\theta)\) to have full column rank.

33.17 30.6 Interactive: Calibration to a Volatility Smile

The following interactive demo shows a simple model-risk problem. Suppose market prices imply a volatility smile, but the model tries to fit the entire smile with one constant Black–Scholes volatility. The calibrated constant volatility may minimize squared error, but the residual pattern reveals misspecification.

33.17.1 Interactive demo: fitting one volatility to a smile

Move the smile-curvature slider. The dots represent a synthetic implied-volatility smile. The horizontal line is the best constant-volatility fit. The residual plot shows the remaining systematic pattern.

0.20

A good model diagnostic does not only report the loss value \(J(\widehat\theta)\). It also examines the structure of the residuals. Random-looking residuals may indicate noise. Systematic residuals often indicate misspecification.

33.18 30.7 Worked Example: Implied Volatility as Calibration

Suppose a European call has observed market price \(C^{\mathrm{mkt}}\). Under Black–Scholes, the model price is

\[ C^{\mathrm{BS}}(\sigma)=S_0N(d_1)-Ke^{-rT}N(d_2). \]

The implied volatility \(\widehat\sigma\) solves

\[ C^{\mathrm{BS}}(\widehat\sigma)=C^{\mathrm{mkt}}. \]

Equivalently,

\[ \widehat\sigma = \arg\min_{\sigma>0} \left(C^{\mathrm{mkt}}-C^{\mathrm{BS}}(\sigma)\right)^2. \]

Remark (Implied volatility is not historical volatility). Historical volatility is estimated from realized returns under the physical measure. Implied volatility is extracted from market option prices under a pricing model. It is a model-dependent summary of option prices, not a directly observed physical standard deviation.

import math

def N(x):
    return 0.5 * (1.0 + math.erf(x / math.sqrt(2.0)))

def bs_call(S0, K, T, r, sigma):
    if T <= 0:
        return max(S0 - K, 0.0)
    d1 = (math.log(S0 / K) + (r + 0.5 * sigma**2) * T) / (sigma * math.sqrt(T))
    d2 = d1 - sigma * math.sqrt(T)
    return S0 * N(d1) - K * math.exp(-r * T) * N(d2)

def implied_vol_bisection(price, S0, K, T, r, low=1e-6, high=5.0, tol=1e-10):
    intrinsic = max(S0 - K * math.exp(-r * T), 0.0)
    upper_bound = S0
    if not (intrinsic <= price <= upper_bound):
        raise ValueError("Price violates simple no-arbitrage bounds.")
    for _ in range(200):
        mid = 0.5 * (low + high)
        model_price = bs_call(S0, K, T, r, mid)
        if abs(model_price - price) < tol:
            return mid
        if model_price < price:
            low = mid
        else:
            high = mid
    return 0.5 * (low + high)

S0, K, T, r = 100.0, 105.0, 1.0, 0.04
market_price = 9.25
sigma_hat = implied_vol_bisection(market_price, S0, K, T, r)
print("implied volatility:", round(sigma_hat, 4))
print("model price check:", round(bs_call(S0, K, T, r, sigma_hat), 4))
implied volatility: 0.2423
model price check: 9.25

The bisection method works because, for a European call, the Black–Scholes price is increasing in volatility. The derivative with respect to volatility is the vega:

\[ \frac{\partial C}{\partial \sigma}=S_0\sqrt T\,\varphi(d_1)>0 \]

for nondegenerate parameters.

33.19 30.8 Calibration Is Not Truth

Consider two models \(M^{(1)}\) and \(M^{(2)}\). It is possible that

\[ \|Y^{\mathrm{mkt}}-M^{(1)}(\widehat\theta_1)\| < \|Y^{\mathrm{mkt}}-M^{(2)}(\widehat\theta_2)\| \]

on today’s calibration instruments, while \(M^{(2)}\) gives better hedges or better out-of-sample predictions. Calibration quality depends on the objective and dataset.

Important questions include:

  • Which instruments were used for calibration?
  • Are they liquid?
  • Are bid–ask spreads included?
  • Are prices synchronous?
  • Are the parameters stable across days?
  • Does the model fit prices but fail hedges?
  • Is the model used for interpolation or extrapolation?

33.20 In-sample and out-of-sample error

The in-sample error is the error on data used to fit the model. The out-of-sample error is the error on data not used for fitting. Overfitting occurs when a model has small in-sample error but large out-of-sample error.

33.21 30.9 Interactive: Overfitting and Out-of-Sample Error

The next demo uses polynomial regression as an analogy. A high-degree model can fit training data very well but behave poorly between or beyond observations. In finance, similar behavior appears when too many parameters are calibrated to too few instruments.

33.21.1 Interactive demo: model complexity and overfitting

Move the polynomial degree slider. The training error usually decreases with degree, but the test error can increase.

3

The analogy is direct: adding parameters to a volatility surface, credit model, or portfolio optimizer may improve in-sample fit while making the model less stable.

33.22 30.10 Parameter Uncertainty

A calibrated parameter is itself uncertain. Suppose

\[ Y=M(\theta_0)+\varepsilon, \]

where \(\varepsilon\) is observation noise. Let \(\widehat\theta\) solve a least-squares problem. Under a local linear approximation,

\[ \widehat\theta-\theta_0 \approx (A^TWA)^{-1}A^TW\varepsilon. \]

If \(\operatorname{Cov}(\varepsilon)=\Sigma_\varepsilon\), then

\[ \operatorname{Cov}(\widehat\theta) \approx (A^TWA)^{-1}A^TW\Sigma_\varepsilon W A(A^TWA)^{-1}. \]

When \(W=\Sigma_\varepsilon^{-1}\), this simplifies to

\[ \operatorname{Cov}(\widehat\theta) \approx (A^T\Sigma_\varepsilon^{-1}A)^{-1}. \]

Remark (Uncertainty propagates). If a risk number is

\[ R=g(\widehat\theta), \]

then the delta-method approximation gives

\[ \operatorname{Var}(R) \approx \nabla g(\theta_0)^T \operatorname{Cov}(\widehat\theta) \nabla g(\theta_0). \]

A single reported risk number without uncertainty is incomplete.

import numpy as np

# Linearized calibration model: Y = A theta + noise
A = np.array([
    [1.00, 0.20],
    [1.00, 0.50],
    [1.00, 0.80],
    [1.00, 1.10],
    [1.00, 1.40]
])
theta_true = np.array([0.15, 0.04])
noise_sd = 0.005
rng = np.random.default_rng(7339)

n_rep = 5000
estimates = []
for _ in range(n_rep):
    y = A @ theta_true + rng.normal(0, noise_sd, size=A.shape[0])
    theta_hat = np.linalg.lstsq(A, y, rcond=None)[0]
    estimates.append(theta_hat)

estimates = np.array(estimates)
print("true theta:", theta_true)
print("mean estimate:", estimates.mean(axis=0).round(5))
print("std estimate:", estimates.std(axis=0, ddof=1).round(5))
print("condition number of A^T A:", round(np.linalg.cond(A.T @ A), 2))
true theta: [0.15 0.04]
mean estimate: [0.15011 0.0399 ]
std estimate: [0.00479 0.00528]
condition number of A^T A: 16.34

The condition number measures sensitivity. A high condition number means the calibration problem is close to being singular.

33.23 30.11 No-Arbitrage as a Validation Constraint

Model outputs should satisfy basic no-arbitrage restrictions. For European call prices with fixed maturity and strikes \(K\), absence of static arbitrage implies:

  1. Call prices are nonnegative:

\[ C(K)\ge 0. \]

  1. Call prices are decreasing in strike:

\[ K_1<K_2 \quad\Longrightarrow\quad C(K_1)\ge C(K_2). \]

  1. Call prices are convex in strike:

\[ C(\lambda K_1+(1-\lambda)K_2) \le \lambda C(K_1)+(1-\lambda)C(K_2), \qquad 0\le \lambda\le 1. \]

For equally spaced strikes, convexity is checked by second differences:

\[ C(K_{i-1})-2C(K_i)+C(K_{i+1})\ge 0. \]

33.24 Butterfly arbitrage

If

\[ C(K_{i-1})-2C(K_i)+C(K_{i+1})<0, \]

then a butterfly portfolio has negative cost and nonnegative payoff, which is a static arbitrage.

import numpy as np

K = np.array([80, 90, 100, 110, 120], dtype=float)
C_good = np.array([22.5, 14.4, 8.1, 4.1, 1.9])
C_bad = np.array([22.5, 14.4, 10.5, 4.1, 1.9])

def call_arbitrage_report(K, C):
    decreasing = np.all(np.diff(C) <= 1e-12)
    second_diff = C[:-2] - 2 * C[1:-1] + C[2:]
    convex = np.all(second_diff >= -1e-12)
    return {
        "decreasing": bool(decreasing),
        "convex": bool(convex),
        "second_differences": second_diff.round(4)
    }

print("good prices:", call_arbitrage_report(K, C_good))
print("bad prices:", call_arbitrage_report(K, C_bad))
good prices: {'decreasing': True, 'convex': True, 'second_differences': array([1.8, 2.3, 1.8])}
bad prices: {'decreasing': True, 'convex': False, 'second_differences': array([ 4.2, -2.5,  4.2])}

Machine-learning models for option prices should also obey these restrictions. A neural network that fits prices but violates monotonicity or convexity may create arbitrage-like outputs.

33.25 30.12 Stress Testing and Scenario Analysis

A model is calibrated near current market conditions. Risk management asks what happens under extreme but plausible changes.

33.26 Stress test

A stress test evaluates model outputs under severe scenarios such as large interest-rate shifts, volatility shocks, liquidity shocks, correlation breakdowns, default clusters, or regime changes.

Mathematically, a stress test replaces an input \(x\) by a shocked input

\[ x^{\mathrm{stress}}=x+\Delta x \]

and studies

\[ M_\theta(x^{\mathrm{stress}})-M_\theta(x). \]

For a first-order approximation,

\[ M_\theta(x+\Delta x)-M_\theta(x) \approx D_xM_\theta(x)\Delta x. \]

For nonlinear portfolios, second-order terms may be essential:

\[ M_\theta(x+\Delta x)-M_\theta(x) \approx D_xM_\theta(x)\Delta x + rac12 \Delta x^T D_x^2M_\theta(x)\Delta x. \]

The first derivative corresponds to delta or duration. The second derivative corresponds to gamma or convexity.

import math

def N_scalar(x):
    return 0.5 * (1.0 + math.erf(x / math.sqrt(2.0)))

def bs_call_scalar(S0, K, T, r, sigma):
    d1 = (math.log(S0 / K) + (r + 0.5 * sigma**2) * T) / (sigma * math.sqrt(T))
    d2 = d1 - sigma * math.sqrt(T)
    return S0 * N_scalar(d1) - K * math.exp(-r * T) * N_scalar(d2)

base = {"S0": 100, "K": 100, "T": 1, "r": 0.04, "sigma": 0.20}
base_price = bs_call_scalar(**base)

scenarios = [
    {"name": "spot down 10%", "S0": 90, "sigma": 0.20},
    {"name": "vol up to 35%", "S0": 100, "sigma": 0.35},
    {"name": "spot down and vol up", "S0": 90, "sigma": 0.35},
]

for sc in scenarios:
    params = base.copy()
    params.update({"S0": sc["S0"], "sigma": sc["sigma"]})
    shocked_price = bs_call_scalar(**params)
    print(sc["name"], "price change:", round(shocked_price - base_price, 4))
spot down 10% price change: -5.1626
vol up to 35% price change: 5.7431
spot down and vol up price change: 0.1829

Stress testing is not a substitute for probabilistic modeling. It answers a different question: not what is likely, but what the model says under specified adverse scenarios.

33.27 30.13 Machine Learning in Mathematical Finance

Machine learning enters finance in several roles:

  1. Prediction: forecasting returns, volatility, liquidity, default, or order flow.
  2. Pricing approximation: approximating expensive pricing maps.
  3. Calibration surrogate: learning a fast inverse map from prices to parameters.
  4. Hedging policy approximation: learning dynamic hedging strategies under frictions.
  5. Risk forecasting: estimating VaR, Expected Shortfall, or stress loss.
  6. Text and alternative data: extracting signals from filings, news, transcripts, or reports.
  7. Anomaly detection: finding unusual trades, quotes, or model outputs.

33.28 ML pricing surrogate

A pricing surrogate is a learned function \(\widehat M\) trained to approximate a slower pricing model \(M\):

\[ \widehat M(x,\theta)\approx M_\theta(x). \]

The surrogate is useful only if its approximation error is controlled in the region where it is used.

33.29 ML calibration surrogate

A calibration surrogate is a learned approximate inverse map

\[ \widehat G:Y^{\mathrm{mkt}}\mapsto \widehat\theta. \]

It should be tested for stability, out-of-sample accuracy, and no-arbitrage consistency.

Machine learning does not remove model risk. It often moves the risk from explicit formulas to data, architecture, loss functions, training procedures, and deployment choices.

33.30 30.14 Train/Test Splits and Data Leakage

In finance, time ordering matters. A random train/test split may leak future information into the training set. For time-series data, validation should respect chronology.

33.31 Data leakage

Data leakage occurs when information unavailable at prediction time enters the training or evaluation process. Leakage produces overly optimistic performance estimates.

Common forms of leakage include:

import numpy as np

rng = np.random.default_rng(7243)
n = 300
x = rng.normal(size=n)
# A synthetic target with time-varying coefficient
beta = np.where(np.arange(n) < 180, 0.4, -0.2)
y = beta * x + rng.normal(scale=0.5, size=n)

split = 200
X_train = np.column_stack([np.ones(split), x[:split]])
y_train = y[:split]
X_test = np.column_stack([np.ones(n - split), x[split:]])
y_test = y[split:]

theta_hat = np.linalg.lstsq(X_train, y_train, rcond=None)[0]
train_mse = np.mean((X_train @ theta_hat - y_train)**2)
test_mse = np.mean((X_test @ theta_hat - y_test)**2)

print("fitted intercept and slope:", theta_hat.round(4))
print("train MSE:", round(train_mse, 4))
print("test MSE:", round(test_mse, 4))
fitted intercept and slope: [0.0025 0.3093]
train MSE: 0.3182
test MSE: 0.4817

The change in the true coefficient creates regime shift. A model that looked reasonable in the training period may fail later.

33.32 30.15 Reinforcement Learning and Trading

Reinforcement learning can be used to model sequential decision problems such as execution, inventory management, market making, or hedging with transaction costs. The mathematical object is usually a Markov decision process:

\[ (S_t,A_t,R_{t+1},S_{t+1}). \]

A policy \(\pi\) maps states to actions. The value function is

\[ V^\pi(s) = \mathbb E^\pi\left[ \sum_{t=0}^{T}\gamma^t R_{t+1} \mid S_0=s \right]. \]

The optimal value satisfies the Bellman equation

\[ V^*(s)=\max_a \left\{ r(s,a)+\gamma\sum_{s'}P(s'\mid s,a)V^*(s') \right\}. \]

In finance, reinforcement learning is especially vulnerable to model risk because the environment is nonstationary, actions affect market outcomes, transaction costs matter, and historical simulation may not represent future execution conditions.

Remark (RL warning). A reinforcement-learning strategy that performs well in a simulated market may fail in a real market if the simulator omits liquidity, impact, latency, constraints, or regime changes.

33.33 30.16 AI-Assisted Mathematical Finance

Large language models and AI coding tools can help students and practitioners:

  • explain formulas in plain language;
  • generate prototype code;
  • check dimensions and units;
  • summarize assumptions;
  • produce test cases;
  • audit documentation;
  • compare alternative modeling choices.

But they introduce new risks:

  • hallucinated formulas;
  • incorrect sign conventions;
  • missing discount factors;
  • confusion between \(\mathbb P\) and \(\mathbb Q\);
  • hidden code bugs;
  • overconfident explanations;
  • privacy and data-governance violations;
  • inability to guarantee regulatory correctness.

33.34 AI-assisted audit prompt: model assumptions

Use an AI assistant to audit a pricing model with the following prompt:

I am using the following model in mathematical finance. List every mathematical assumption, every market assumption, and every numerical assumption. For each assumption, explain what can go wrong if it fails. Then suggest three tests I can run in Python to detect possible misuse.

A strong answer should mention the probability measure, information structure, admissible strategies, discounting convention, calibration data, numerical method, and intended use.

33.35 AI-assisted code-review prompt

Use an AI assistant to review code with the following prompt:

Check this option-pricing or risk-management code for mathematical errors. Pay special attention to discounting, sign conventions, units of volatility and time, physical versus risk-neutral drift, boundary cases, vectorization errors, and no-arbitrage violations. Give corrected code only after explaining the issue.

33.36 AI is not a validation authority

AI tools can support model development, but they do not replace mathematical proof, independent implementation checks, domain expertise, governance review, or empirical validation.

33.37 30.17 Model Governance as Mathematical Documentation

A model should be accompanied by documentation that answers:

  1. What is the model purpose?
  2. What are the state variables?
  3. What is the probability measure?
  4. What are the assumptions?
  5. What parameters are estimated from history?
  6. What parameters are calibrated to market prices?
  7. What instruments are used for calibration?
  8. What numerical method is used?
  9. What tests verify the implementation?
  10. What are the limitations?
  11. What is the approved use case?
  12. What are the prohibited uses?

33.38 Model inventory entry

A model inventory entry is a structured record of a model’s purpose, owner, mathematical specification, inputs, outputs, assumptions, validation status, version, and approved use.

For students, writing such documentation is an excellent way to learn mathematical finance. It forces precise thinking.

33.39 30.18 Python Example: Calibrating a Constant Volatility to Multiple Options

The following example creates synthetic option prices from a volatility smile and fits one constant volatility. The residuals reveal that the model is misspecified.

import numpy as np
import math

S0, T, r = 100.0, 1.0, 0.03
strikes = np.linspace(75, 125, 11)

def N_vec(x):
    erf_vec = np.vectorize(math.erf)
    return 0.5 * (1.0 + erf_vec(x / np.sqrt(2.0)))

def bs_call_vec(S0, K, T, r, sigma):
    K = np.asarray(K, dtype=float)
    d1 = (np.log(S0 / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
    d2 = d1 - sigma * np.sqrt(T)
    return S0 * N_vec(d1) - K * np.exp(-r * T) * N_vec(d2)

# Synthetic market smile in implied volatility
market_vols = 0.18 + 0.25 * (np.log(strikes / S0))**2 + 0.03 * np.maximum(-np.log(strikes / S0), 0)
market_prices = np.array([bs_call_vec(S0, [K], T, r, vol)[0] for K, vol in zip(strikes, market_vols)])

sigma_grid = np.linspace(0.05, 0.60, 2000)
losses = []
for sigma in sigma_grid:
    model_prices = bs_call_vec(S0, strikes, T, r, sigma)
    losses.append(np.mean((market_prices - model_prices)**2))

best_sigma = sigma_grid[int(np.argmin(losses))]
model_prices = bs_call_vec(S0, strikes, T, r, best_sigma)
residuals = market_prices - model_prices

print("best constant volatility:", round(best_sigma, 4))
print("root mean squared price error:", round(np.sqrt(np.mean(residuals**2)), 4))
print("residuals by strike:")
for K, res in zip(strikes, residuals):
    print(f"K={K:6.1f}, residual={res: .4f}")
best constant volatility: 0.1845
root mean squared price error: 0.1497
residuals by strike:
K=  75.0, residual= 0.2283
K=  80.0, residual= 0.2138
K=  85.0, residual= 0.1481
K=  90.0, residual= 0.0396
K=  95.0, residual=-0.0811
K= 100.0, residual=-0.1754
K= 105.0, residual=-0.1575
K= 110.0, residual=-0.0875
K= 115.0, residual= 0.0120
K= 120.0, residual= 0.1157
K= 125.0, residual= 0.2046

The fit may look acceptable by one metric but still display systematic residuals. This is one reason volatility surfaces are modeled rather than a single constant volatility.

33.40 30.19 Python Example: Bootstrap Parameter Uncertainty

Bootstrap methods approximate the sampling variability of calibrated parameters by repeatedly resampling or perturbing data.

import numpy as np

rng = np.random.default_rng(5110)
x = np.linspace(0.0, 1.0, 20)
true_theta = np.array([0.20, -0.05])
y_clean = true_theta[0] + true_theta[1] * x
noise_sd = 0.01
y_obs = y_clean + rng.normal(0, noise_sd, size=x.size)

X = np.column_stack([np.ones_like(x), x])
theta_hat = np.linalg.lstsq(X, y_obs, rcond=None)[0]
residuals = y_obs - X @ theta_hat

B = 2000
boot = []
for _ in range(B):
    sampled_resid = rng.choice(residuals, size=residuals.size, replace=True)
    y_boot = X @ theta_hat + sampled_resid
    boot.append(np.linalg.lstsq(X, y_boot, rcond=None)[0])
boot = np.array(boot)

lower = np.percentile(boot, 2.5, axis=0)
upper = np.percentile(boot, 97.5, axis=0)
print("theta_hat:", theta_hat.round(5))
print("95% bootstrap interval for intercept:", (float(round(lower[0], 5)), float(round(upper[0], 5))))
print("95% bootstrap interval for slope:", (float(round(lower[1], 5)), float(round(upper[1], 5))))
theta_hat: [ 0.20325 -0.05743]
95% bootstrap interval for intercept: (0.19515, 0.21167)
95% bootstrap interval for slope: (-0.07231, -0.04444)

The bootstrap interval communicates that calibrated parameters are estimates, not constants handed down by the market.

33.41 30.20 Python Example: A Simple Surrogate Model

The next example approximates Black–Scholes prices using polynomial regression in moneyness and volatility. This is not recommended as a production pricing method. Its purpose is to show the structure of a surrogate model.

import numpy as np
import math

rng = np.random.default_rng(6241)

def N_float(x):
    return 0.5 * (1.0 + math.erf(x / math.sqrt(2.0)))

def bs_call_float(S0, K, T, r, sigma):
    d1 = (math.log(S0 / K) + (r + 0.5 * sigma**2) * T) / (sigma * math.sqrt(T))
    d2 = d1 - sigma * math.sqrt(T)
    return S0 * N_float(d1) - K * math.exp(-r * T) * N_float(d2)

def features(m, sigma):
    return np.array([1.0, m, sigma, m**2, m * sigma, sigma**2, m**3, sigma**3])

n_train = 800
S0, T, r = 100.0, 1.0, 0.03
m_train = rng.uniform(-0.25, 0.25, size=n_train)       # log-moneyness log(S/K)
sig_train = rng.uniform(0.10, 0.50, size=n_train)
X_train = np.vstack([features(m, s) for m, s in zip(m_train, sig_train)])
y_train = np.array([
    bs_call_float(S0, S0 / math.exp(m), T, r, s)
    for m, s in zip(m_train, sig_train)
])
coef = np.linalg.lstsq(X_train, y_train, rcond=None)[0]

n_test = 200
m_test = rng.uniform(-0.25, 0.25, size=n_test)
sig_test = rng.uniform(0.10, 0.50, size=n_test)
X_test = np.vstack([features(m, s) for m, s in zip(m_test, sig_test)])
y_test = np.array([
    bs_call_float(S0, S0 / math.exp(m), T, r, s)
    for m, s in zip(m_test, sig_test)
])
y_pred = X_test @ coef

print("test RMSE:", round(np.sqrt(np.mean((y_test - y_pred)**2)), 4))
print("largest absolute error:", round(np.max(np.abs(y_test - y_pred)), 4))
test RMSE: 0.5682
largest absolute error: 2.2175

A surrogate must be tested not only on random points, but also near boundaries and under the exact input distribution expected in use.

33.42 30.21 Common Mistakes

  1. Reporting calibrated parameters without uncertainty.
  2. Using the same dataset for fitting and evaluation.
  3. Confusing low calibration error with good hedging performance.
  4. Ignoring bid–ask spreads.
  5. Ignoring parameter constraints.
  6. Using physical drift in a risk-neutral pricing formula.
  7. Using annual volatility with daily time units.
  8. Fitting a flexible model without checking arbitrage restrictions.
  9. Using machine-learning predictions without time-aware validation.
  10. Treating AI-generated code as correct without independent tests.

33.43 30.22 AI Component: A Model-Risk Checklist

33.44 AI-assisted model-risk checklist

Ask an AI assistant to produce a checklist for any model in this book. Then verify the checklist yourself.

A useful prompt is:

Create a model-risk checklist for this model. Organize the checklist into assumptions, inputs, parameters, calibration, numerical method, validation tests, stress tests, limitations, and prohibited uses. Include formulas where appropriate. Then list mistakes a student is likely to make.

A weak answer will only describe the model. A strong answer will identify what can fail and how to test it.

33.45 AI-assisted theorem audit

For a theorem such as the Fundamental Theorem of Asset Pricing, Girsanov theorem, Black–Scholes PDE, or Snell-envelope recursion, use:

State every assumption required for this theorem. For each assumption, give a counterexample or failure mode if the assumption is removed. Then explain how the assumption appears in the proof.

This prompt helps students connect assumptions to proof structure.

33.46 AI-assisted numerical audit

For Python code, use:

Write unit tests for this function. Include boundary cases, monotonicity checks, no-arbitrage checks, dimensional checks, and comparisons with known special cases.

For example, a Black–Scholes call-pricing function should satisfy monotonicity in \(S_0\) and \(\sigma\), put–call parity when paired with a put function, and convergence to intrinsic value as \(T\to 0\).

33.47 30.23 Chapter Summary

This chapter completes the book by changing the question from

\[ \text{What does the model imply?} \]

to

\[ \text{Should we trust the model for this purpose?} \]

The main lessons are:

  • A model is a parameterized mathematical map.
  • Calibration is an inverse problem, often ill-conditioned.
  • Small residuals do not prove that a model is correct.
  • Parameter uncertainty propagates to prices, hedges, and risk measures.
  • No-arbitrage restrictions provide powerful validation checks.
  • Out-of-sample testing is essential.
  • Stress testing asks different questions from probabilistic forecasting.
  • Machine learning can accelerate pricing and risk modeling, but it introduces its own model risks.
  • AI tools are useful assistants for explanation, coding, and auditing, but they are not substitutes for mathematical validation.

The broader message of mathematical finance is therefore:

\[ \text{A formula is useful only together with its assumptions, domain, and validation tests.} \]

33.48 30.24 Exercises

33.48.1 Conceptual Exercises

  1. Explain the difference between estimation and calibration. Give one example of each from mathematical finance.
  2. Why does small calibration error not imply that a model is correct?
  3. List five sources of model risk in the Black–Scholes model.
  4. Explain why a model calibrated under \(\mathbb Q\) may not forecast returns under \(\mathbb P\).
  5. Give an example of data leakage in a financial machine-learning problem.

33.48.2 Mathematical Exercises

  1. Let \(J(\theta)=\|Y-M(\theta)\|_W^2\). Derive the first-order condition for an interior minimizer.
  2. In the local linear model \(Y=A\theta+\varepsilon\), derive the least-squares estimator and its covariance matrix when \(\varepsilon\) has covariance \(\sigma^2I\).
  3. Prove that European call prices must be decreasing in strike under no arbitrage.
  4. Prove that European call prices must be convex in strike under no arbitrage.
  5. Suppose a model output is \(R=g(\widehat\theta)\). Use the delta method to derive an approximation for \(\operatorname{Var}(R)\).

33.48.3 Computational Exercises

  1. Generate synthetic Black–Scholes option prices with constant volatility. Add noise and recover volatility by calibration.
  2. Generate synthetic option prices from a volatility smile. Fit a constant volatility and plot residuals by strike.
  3. Implement a no-arbitrage checker for call prices across strikes.
  4. Simulate a regime shift and compare random train/test splitting with chronological train/test splitting.
  5. Build a simple pricing surrogate for Black–Scholes calls. Test it near the edge of the training region.

33.48.4 AI-Assisted Exercises

  1. Ask an AI assistant to explain why calibration is an inverse problem. Improve the explanation by adding a Jacobian and condition-number discussion.
  2. Ask an AI assistant to audit a Black–Scholes implementation. Check whether it catches time-unit, volatility-unit, and discounting mistakes.
  3. Ask an AI assistant to generate tests for a VaR function. Add at least three tests the AI missed.
  4. Ask an AI assistant to compare historical volatility and implied volatility. Identify any measure-confusion in the answer.
  5. Ask an AI assistant to write a model-risk checklist for one chapter of this book. Revise the checklist into a rigorous mathematical document.