tf_quant_finance.models.hull_white.bermudan_swaption_price

Last updated: 2023-03-16.

tf_quant_finance.models.hull_white.bermudan_swaption_price#

View source

Calculates the price of Bermudan Swaptions using the Hull-White model.

tf_quant_finance.models.hull_white.bermudan_swaption_price(
    *, exercise_times, floating_leg_start_times, floating_leg_end_times,
    fixed_leg_payment_times, floating_leg_daycount_fractions,
    fixed_leg_daycount_fractions, fixed_leg_coupon, reference_rate_fn,
    mean_reversion, volatility, notional=None, is_payer_swaption=True,
    use_finite_difference=False, lsm_basis=None, num_samples=100, random_type=None,
    seed=None, skip=0, time_step=None, time_step_finite_difference=None,
    num_grid_points_finite_difference=101, dtype=None, name=None
)

A Bermudan Swaption is a contract that gives the holder an option to enter a swap contract on a set of future exercise dates. The exercise dates are typically the fixing dates (or a subset thereof) of the underlying swap. If T_N denotes the final payoff date and T_i, i = {1,...,n} denote the set of exercise dates, then if the option is exercised at T_i, the holder is left with a swap with first fixing date equal to T_i and maturity T_N.

Simulation based pricing of Bermudan swaptions is performed using the least squares Monte-carlo approach [1].

References:#

[1]: D. Brigo, F. Mercurio. Interest Rate Models-Theory and Practice. Second Edition. 2007.

Example#

The example shows how value a batch of 5-no-call-1 and 5-no-call-2 swaptions using the Hull-White model.

import numpy as np
import tensorflow as tf
import tf_quant_finance as tff

dtype = tf.float64

exercise_swaption_1 = [1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5]
exercise_swaption_2 = [2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.0]
exercise_times = [exercise_swaption_1, exercise_swaption_2]

float_leg_start_times_1y = [1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5]
float_leg_start_times_18m = [1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0]
float_leg_start_times_2y = [2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.0]
float_leg_start_times_30m = [2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.0, 5.0]
float_leg_start_times_3y = [3.0, 3.5, 4.0, 4.5, 5.0, 5.0, 5.0, 5.0]
float_leg_start_times_42m = [3.5, 4.0, 4.5, 5.0, 5.0, 5.0, 5.0, 5.0]
float_leg_start_times_4y = [4.0, 4.5, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0]
float_leg_start_times_54m = [4.5, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0]
float_leg_start_times_5y = [5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0]

float_leg_start_times_swaption_1 = [float_leg_start_times_1y,
                                    float_leg_start_times_18m,
                                    float_leg_start_times_2y,
                                    float_leg_start_times_30m,
                                    float_leg_start_times_3y,
                                    float_leg_start_times_42m,
                                    float_leg_start_times_4y,
                                    float_leg_start_times_54m]

float_leg_start_times_swaption_2 = [float_leg_start_times_2y,
                                    float_leg_start_times_30m,
                                    float_leg_start_times_3y,
                                    float_leg_start_times_42m,
                                    float_leg_start_times_4y,
                                    float_leg_start_times_54m,
                                    float_leg_start_times_5y,
                                    float_leg_start_times_5y]
float_leg_start_times = [float_leg_start_times_swaption_1,
                       float_leg_start_times_swaption_2]

float_leg_end_times = np.clip(np.array(float_leg_start_times) + 0.5, 0.0, 5.0)

fixed_leg_payment_times = float_leg_end_times
float_leg_daycount_fractions = (np.array(float_leg_end_times) -
                                np.array(float_leg_start_times))
fixed_leg_daycount_fractions = float_leg_daycount_fractions
fixed_leg_coupon = 0.011 * np.ones_like(fixed_leg_payment_times)
zero_rate_fn = lambda x: 0.01 * tf.ones_like(x, dtype=dtype)
price = bermudan_swaption_price(
    exercise_times=exercise_times,
    floating_leg_start_times=float_leg_start_times,
    floating_leg_end_times=float_leg_end_times,
    fixed_leg_payment_times=fixed_leg_payment_times,
    floating_leg_daycount_fractions=float_leg_daycount_fractions,
    fixed_leg_daycount_fractions=fixed_leg_daycount_fractions,
    fixed_leg_coupon=fixed_leg_coupon,
    reference_rate_fn=zero_rate_fn,
    notional=100.,
    mean_reversion=[0.03],
    volatility=[0.01],
    num_samples=1000000,
    time_step=0.1,
    random_type=tff.math.random.RandomType.PSEUDO_ANTITHETIC,
    seed=0,
    dtype=dtype)
# Expected value: [1.8913050118443016, 1.6618681421434984] # shape = (2,)

Args:#

  • exercise_times: A real Tensor of any shape [batch_size, num_exercise] and real dtype. The times corresponding to exercise dates of the swaptions. num_exercise` corresponds to the number of exercise dates for the Bermudan swaption. The shape of this input determines the number (and shape) of Bermudan swaptions to be priced and the shape of the output.

  • floating_leg_start_times: A real Tensor of the same dtype as exercise_times. The times when accrual begins for each payment in the floating leg upon exercise of the option. The shape of this input should be exercise_times.shape + [m] where m denotes the number of floating payments in each leg of the underlying swap until the swap maturity.

  • floating_leg_end_times: A real Tensor of the same dtype as exercise_times. The times when accrual ends for each payment in the floating leg upon exercise of the option. The shape of this input should be exercise_times.shape + [m] where m denotes the number of floating payments in each leg of the underlying swap until the swap maturity.

  • fixed_leg_payment_times: A real Tensor of the same dtype as exercise_times. The payment times for each payment in the fixed leg. The shape of this input should be exercise_times.shape + [n] where n denotes the number of fixed payments in each leg of the underlying swap until the swap maturity.

  • floating_leg_daycount_fractions: A real Tensor of the same dtype and compatible shape as floating_leg_start_times. The daycount fractions for each payment in the floating leg.

  • fixed_leg_daycount_fractions: A real Tensor of the same dtype and compatible shape as fixed_leg_payment_times. The daycount fractions for each payment in the fixed leg.

  • fixed_leg_coupon: A real Tensor of the same dtype and compatible shape as fixed_leg_payment_times. The fixed rate for each payment in the fixed leg.

  • reference_rate_fn: A Python callable that accepts expiry time as a real Tensor and returns a Tensor of either shape input_shape or input_shape. Returns the continuously compounded zero rate at the present time for the input expiry time.

  • mean_reversion: A real positive scalar Tensor or 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 property is_piecewise_constant set to True. In this case the object should have a method jump_locations(self) that returns a Tensor of shape [num_jumps]. The return value of mean_reversion(t) should return a Tensor of shape t.shape, t is a rank 1 Tensor of the same dtype as the output. See example in the class docstring. (b) A callable that accepts scalars (stands for time t) and returns a scalar Tensor of the same dtype as strikes. Corresponds to the mean reversion rate.

  • volatility: A real positive Tensor of the same dtype as mean_reversion or a callable with the same specs as above. Corresponds to the long run price variance.

  • notional: An optional Tensor of same dtype and compatible shape as strikesspecifying the notional amount for the underlying swap. Default value: None in which case the notional is set to 1.

  • is_payer_swaption: A boolean Tensor of a shape compatible with expiries. Indicates whether the swaption is a payer (if True) or a receiver (if False) swaption. If not supplied, payer swaptions are assumed.

  • use_finite_difference: A Python boolean specifying if the valuation should be performed using the finite difference and PDE. Default value: False, in which case valuation is performed using least squares monte-carlo method.

  • lsm_basis: A Python callable specifying the basis to be used in the LSM algorithm. The callable must accept a Tensors of shape [num_samples, dim] and output Tensors of shape [m, num_samples] where m is the nimber of basis functions used. This input is only used for valuation using LSM. Default value: None, in which case a polynomial basis of order 2 is used.

  • num_samples: Positive scalar int32 Tensor. The number of simulation paths during Monte-Carlo valuation. This input is only used for valuation using LSM. Default value: The default value is 100.

  • random_type: Enum value of RandomType. The type of (quasi)-random number generator to use to generate the simulation paths. This input is only used for valuation using LSM. Default value: None which maps to the standard pseudo-random numbers.

  • seed: Seed for the random number generator. The seed is only relevant if random_type is one of [STATELESS, PSEUDO, HALTON_RANDOMIZED, PSEUDO_ANTITHETIC,   STATELESS_ANTITHETIC]. For PSEUDO, PSEUDO_ANTITHETIC and HALTON_RANDOMIZED the seed should be an Python integer. For STATELESS and STATELESS_ANTITHETIC must be supplied as an integer Tensor of shape [2]. This input is only used for valuation using LSM. Default value: None which means no seed is set.

  • skip: int32 0-d Tensor. The number of initial points of the Sobol or Halton sequence to skip. Used only when random_type is ‘SOBOL’, ‘HALTON’, or ‘HALTON_RANDOMIZED’, otherwise ignored. This input is only used for valuation using LSM. Default value: 0.

  • time_step: Scalar real Tensor. Maximal distance between time grid points in Euler scheme. Relevant when Euler scheme is used for simulation. This input is only used for valuation using LSM. Default value: None.

  • time_step_finite_difference: Scalar real Tensor. Spacing between time grid points in finite difference discretization. This input is only relevant for valuation using finite difference. Default value: None, in which case a time_step corresponding to 100 discrete steps is used.

  • num_grid_points_finite_difference: Scalar real Tensor. Number of spatial grid points for discretization. This input is only relevant for valuation using finite difference. Default value: 100.

  • dtype: The default dtype to use when converting values to Tensors. Default value: None which means that default dtypes inferred by TensorFlow are used.

  • name: Python string. The name to give to the ops created by this function. Default value: None which maps to the default name hw_bermudan_swaption_price.

Returns:#

A Tensor of real dtype and shape [batch_size] containing the computed swaption prices.

Raises:#

(a) ValueError if exercise_times.rank is less than floating_leg_start_times.rank - 1, which would mean exercise times are not specified for all swaptions. (b) ValueError if time_step is not specified for Monte-Carlo simulations.