Last updated: 2023-03-16.
tf_quant_finance.models.hull_white.calibration_from_cap_floors#
Calibrates the Hull-White model using the observed Cap/Floor prices.
tf_quant_finance.models.hull_white.calibration_from_cap_floors(
*, prices, strikes, expiries, maturities, daycount_fractions, reference_rate_fn,
mean_reversion, volatility, notional=None, is_cap=True,
use_analytic_pricing=True, num_samples=1, random_type=None, seed=None, skip=0,
time_step=None, optimizer_fn=None, mean_reversion_lower_bound=0.001,
mean_reversion_upper_bound=0.5, volatility_lower_bound=1e-05,
volatility_upper_bound=0.1, tolerance=1e-06, maximum_iterations=50, dtype=None,
name=None
)
This function estimates the mean-reversion rate and volatility parameters of a Hull-White 1-factor model using a set of Cap/Floor prices as the target. The calibration is performed using least-squares optimization where the loss function minimizes the squared error between the observed option prices and the model implied prices.
Example#
The example shows how to calibrate a Hull-White model with constant mean reversion rate and constant volatility.
import numpy as np
import tensorflow as tf
import tf_quant_finance as tff
# In this example, we synthetically generate some prices. Then we use our
# calibration to back out these prices.
dtype = tf.float64
daycount_fractions = np.array([
[0.25, 0.25, 0.25, 0.25, 0.0, 0.0, 0.0, 0.0],
[0.25, 0.25, 0.25, 0.25, 0.0, 0.0, 0.0, 0.0],
[0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25],
[0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25],
])
expiries = np.array([
[0.0, 0.25, 0.5, 0.75, 1.0, 0.0, 0.0, 0.0],
[0.0, 0.25, 0.5, 0.75, 1.0, 0.0, 0.0, 0.0],
[0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.50, 1.75],
[0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.50, 1.75],
])
maturities = np.array([
[0.25, 0.5, 0.75, 1.0, 0.0, 0.0, 0.0, 0.0],
[0.25, 0.5, 0.75, 1.0, 0.0, 0.0, 0.0, 0.0],
[0.25, 0.5, 0.75, 1.0, 1.25, 1.50, 1.75, 2.0],
[0.25, 0.5, 0.75, 1.0, 1.25, 1.50, 1.75, 2.0],
])
is_cap = np.array([True, False, True, False])
strikes = 0.01 * np.ones_like(expiries)
# Setup - generate some observed prices using the model.
expected_mr = [0.4]
expected_vol = [0.01]
zero_rate_fn = lambda x: 0.01 * tf.ones_like(x, dtype=dtype)
prices = tff.models.hull_white.cap_floor_price(
strikes=strikes,
expiries=expiries,
maturities=maturities,
daycount_fractions=daycount_fractions,
reference_rate_fn=zero_rate_fn,
notional=1.0,
mean_reversion=expected_mr,
volatility=expected_vol,
is_cap=tf.expand_dims(is_cap, axis=1),
use_analytic_pricing=True,
dtype=dtype)
# Calibrate the model.
calibrated_model, is_converged, _ = (
tff.models.hull_white.calibration_from_cap_floors(
prices=tf.squeeze(prices),
strikes=strikes,
expiries=expiries,
maturities=maturities,
daycount_fractions=daycount_fractions,
reference_rate_fn=zero_rate_fn,
mean_reversion=[0.3],
volatility=[0.02],
notional=1.0,
is_cap=tf.expand_dims(is_cap, axis=1),
use_analytic_pricing=True,
optimizer_fn=None,
num_samples=1000,
random_type=tff.math.random.RandomType.STATELESS_ANTITHETIC,
seed=[0, 0],
time_step=0.1,
maximum_iterations=200,
dtype=dtype))
calibrated_mr = calibrated_model.mean_reversion.values()
calibrated_vol = calibrated_model.volatility.values()
# Running this inside a unit test passes:
#
# calibrated_mr, calibrated_vol = self.evaluate(
# [calibrated_mr, calibrated_vol])
# self.assertTrue(is_converged)
# self.assertAllClose(calibrated_mr, expected_mr, atol=1e-3, rtol=1e-2)
# self.assertAllClose(calibrated_vol, expected_vol, atol=1e-3, rtol=1e-2)
Args:#
prices: A realTensorof shape [num_capfloors], holding the prices of cap/floors used for calibration; e.g.prices[i]holds the price for the i-th cap/floor.strikes: A realTensorof shape [num_capfloors, num_optionlets], where the second axis corresponds to the strikes of the caplets or floorlets contained within each option; e.g.strikes[i, j]holds the strike price for the j-th caplet/floorlet of the i-th cap/floor.expiries: A realTensorof shape [num_capfloors, num_optionlets], whereexpiries[i, j]holds the reset time for the j-th caplet/floorlet of the i-th cap/floor.maturities: A realTensorof shape [num_capfloors, num_optionlets], wherematurities[i, j]holds the maturity time (aka the end of accrual) of the underlying forward rate for the j-th caplet/floorlet of the i-th cap/floor. The payment occurs on the maturity as well.daycount_fractions: A realTensorof shape [num_capfloors, num_optionlets], wheredaycount_fractions[i, j]holds the daycount fractions associated with the underlying forward rate of the j-th caplet/floorlet of the i-th cap/floor.reference_rate_fn: A Python callable that accepts expiry time as a realTensorand returns aTensorof either shapeinput_shapeorinput_shape. Returns the continuously compounded zero rate at the present time for the input expiry time.mean_reversion: A real positive scalarTensoror a Python callable. The callable can be one of the following: (a) A left-continuous piecewise constant object (e.g.,tff.math.piecewise.PiecewiseConstantFunc) that has a propertyis_piecewise_constantset toTrue. In this case the object should have a methodjump_locations(self)that returns aTensorof shape[num_jumps]. The return value ofmean_reversion(t)should return aTensorof shapet.shape,tis a rank 1Tensorof the samedtypeas the output. See example in the class docstring. (b) A callable that accepts scalars (stands for timet) and returns a scalarTensorof the samedtypeasstrikes. Corresponds to the mean reversion rate.volatility: A real positiveTensorof the samedtypeasmean_reversionor a callable with the same specs as above. Corresponds to the long run price variance.notional: A realTensorbroadcast to [num_capfloors], such thatnotional[i]is the notional amount for the i-th cap/floor.is_cap: A boolean tensor broadcastable to [num_capfloors], such thatis_cap[i]represents whether or not the i-th instrument is a cap (True) or floor (False).use_analytic_pricing: A Python boolean specifying if cap/floor pricing is done analytically during calibration. Analytic valuation is only supported for constantmean_reversionand piecewise constantvolatility. If the input isFalse, then valuation using Monte-Carlo simulations is performed. Default value: The default value isTrue.num_samples: Positive scalarint32Tensor. The number of simulation paths during Monte-Carlo valuation of cap/floors. This input is ignored during analytic valuation. Default value: The default value is 1.random_type: Enum value ofRandomType. The type of (quasi)-random number generator to use to generate the simulation paths. This input is relevant only for Monte-Carlo valuation and ignored during analytic valuation. Default value:Nonewhich maps to the standard pseudo-random numbers.seed: Seed for the random number generator. The seed is only relevant ifrandom_typeis one of[STATELESS, PSEUDO, HALTON_RANDOMIZED, PSEUDO_ANTITHETIC, STATELESS_ANTITHETIC]. ForPSEUDO,PSEUDO_ANTITHETICandHALTON_RANDOMIZEDthe seed should be an Python integer. ForSTATELESSandSTATELESS_ANTITHETICmust be supplied as an integerTensorof shape[2]. This input is relevant only for Monte-Carlo valuation and ignored during analytic valuation. Default value:Nonewhich means no seed is set.skip:int320-dTensor. The number of initial points of the Sobol or Halton sequence to skip. Used only whenrandom_typeis ‘SOBOL’, ‘HALTON’, or ‘HALTON_RANDOMIZED’, otherwise ignored. Default value:0.time_step: Scalar realTensor. Maximal distance between time grid points in Euler scheme. Relevant when Euler scheme is used for simulation. This input is ignored during analytic valuation. Default value:None.optimizer_fn: Optional Python callable which implements the algorithm used to minimize the objective function during calibration. It should have the following interface: result = optimizer_fn(value_and_gradients_function, initial_position, tolerance, max_iterations)value_and_gradients_functionis a Python callable that accepts a point as a realTensorand returns a tuple ofTensors of real dtype containing the value of the function and its gradient at that point. ‘initial_position’ is a realTensorcontaining the starting point of the optimization, ‘tolerance’ is a real scalarTensorfor stopping tolerance for the procedure andmax_iterationsspecifies the maximum number of iterations.optimizer_fnshould return a namedtuple containing the items:position(a tensor containing the optimal value),converged(a boolean indicating whether the optimize converged according the specified criteria),failed(a boolean indicating if the optimization resulted in a failure),num_iterations(the number of iterations used), andobjective_value( the value of the objective function at the optimal value). The default value foroptimizer_fnis None and conjugate gradient algorithm is used.mean_reversion_lower_bound: An optional scalarTensorspecifying the lower limit of mean reversion rate during calibration. Default value: 0.001.mean_reversion_upper_bound: An optional scalarTensorspecifying the upper limit of mean reversion rate during calibration. Default value: 0.5.volatility_lower_bound: An optional scalarTensorspecifying the lower limit of Hull White volatility during calibration. Default value: 0.00001 (0.1 basis points).volatility_upper_bound: An optional scalarTensorspecifying the upper limit of Hull White volatility during calibration. Default value: 0.1.tolerance: ScalarTensorof real dtype. The absolute tolerance for terminating the iterations. Default value: 1e-6.maximum_iterations: Scalar positive int32Tensor. The maximum number of iterations during the optimization. Default value: 50.dtype: The default dtype to use when converting values toTensors. Default value:Nonewhich means that default dtypes inferred frompricesis used.name: Python string. The name to give to the ops created by this function. Default value:Nonewhich maps to the default namehw_capfloor_calibration.
Returns:#
A Tuple of three elements:
The first element is an instance of
CalibrationResultwhose parameters are calibrated to the input cap/floor prices.A
Tensorof optimization status for each batch element (whether the optimization algorithm succeeded in finding the optimal point based on the specified convergance criteria).A
Tensorcontaining the number of iterations performed by the optimization algorithm.