tf_quant_finance.experimental.local_volatility.LocalVolatilityModel

Last updated: 2023-03-16.

tf_quant_finance.experimental.local_volatility.LocalVolatilityModel#

View source

Local volatility model for smile modeling.

Inherits From: GenericItoProcess

tf_quant_finance.experimental.local_volatility.LocalVolatilityModel(
    dim, risk_free_rate=None, dividend_yield=None, local_volatility_fn=None,
    corr_matrix=None, times_grid=None, spot_grid=None, precompute_iv=False,
    dtype=None, name=None
)

Local volatility (LV) model specifies that the dynamics of an asset is governed by the following stochastic differential equation:

  dS(t) / S(t) =  mu(t, S(t)) dt + sigma(t, S(t)) * dW(t)

where mu(t, S(t)) is the drift and sigma(t, S(t)) is the instantaneous volatility. The local volatility function sigma(t, S(t)) is state dependent and is computed by calibrating against a given implied volatility surface sigma_iv(T, K) using the Dupire’s formula [1]:

sigma(T,K)^2 = 2 * (dC(T,K)/dT + (r - q)K dC(T,K)/dK + qC(T,K)) /
                   (K^2 d2C(T,K)/dK2)

where the derivatives above are the partial derivatives. The LV model provides a flexible framework to model any (arbitrage free) volatility surface.

Example: Simulation of local volatility process.#

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

dtype = tf.float64
dim = 2
year = dim * [[2021, 2022]]
month = dim * [[1, 1]]
day = dim * [[1, 1]]
expiries = tff.datetime.dates_from_year_month_day(year, month, day)
valuation_date = [(2020, 1, 1)]
expiry_times = tff.datetime.daycount_actual_365_fixed(
    start_date=valuation_date, end_date=expiries, dtype=dtype)
strikes = dim * [[[0.1, 0.9, 1.0, 1.1, 3], [0.1, 0.9, 1.0, 1.1, 3]]]
iv = dim * [[[0.135, 0.13, 0.1, 0.11, 0.13],
             [0.135, 0.13, 0.1, 0.11, 0.13]]]
spot = dim * [1.0]
risk_free_rate = [0.02]
r = tf.convert_to_tensor(risk_free_rate, dtype=dtype)
df = lambda t: tf.math.exp(-r * t)

lv = tff.models.LocalVolatilityModel.from_market_data(
    dim, val_date, expiries, strikes, iv, spot, df, [0.0], dtype=dtype)
num_samples = 10000
paths = lv.sample_paths(
    [1.0, 1.5, 2.0],
    num_samples=num_samples,
    initial_state=spot,
    time_step=0.1,
    random_type=tff.math.random.RandomType.STATELESS_ANTITHETIC,
    seed=[1, 2])
# paths.shape = (10000, 3, 2)

#### References:
  [1]: Iain J. Clark. Foreign exchange option pricing - A Practitioner's
  guide. Chapter 5, Section 5.3.2. 2011.

#### Args:


* <b>`dim`</b>: A Python scalar which corresponds to the number of underlying assets
  comprising the model.
* <b>`risk_free_rate`</b>: One of the following: (a) An optional real `Tensor` of
  shape compatible with `[dim]` specifying the (continuously compounded)
  risk free interest rate. (b) A python callable accepting one real
  `Tensor` argument time t returning a `Tensor` of shape compatible with
  `[dim]`. If the underlying is an FX rate, then use this input to specify
  the domestic interest rate.
  Default value: `None` in which case the input is set to Zero.
* <b>`dividend_yield`</b>: A real `Tensor` of shape compatible with `spot_price`
  specifying the (continuously compounded) dividend yield. If the
  underlying is an FX rate, then use this input to specify the foreign
  interest rate.
  Default value: `None` in which case the input is set to Zero.
* <b>`local_volatility_fn`</b>: A Python callable which returns instantaneous
  volatility as a function of state and time. The function must accept a
  scalar `Tensor` corresponding to time 't' and a real `Tensor` of shape
  `[num_samples, dim]` corresponding to the underlying price (S) as inputs
  and return a real `Tensor` of shape `[num_samples, dim]` containing the
  local volatility computed at (S,t).
* <b>`corr_matrix`</b>: A `Tensor` of shape `[dim, dim]` and the same `dtype` as
  `risk_free_rate`. Corresponds to the instantaneous correlation between
  the underlying assets.
* <b>`times_grid`</b>: A `Tensor` of shape `[num_time_samples]`. The grid on which to
  do interpolation over time. Must be jointly specified with `spot_grid`.
  Default value: `None`.
* <b>`spot_grid`</b>: A `Tensor` of shape `[num_spot_samples]`. The grid on which to
  do interpolation over spots. Must be jointly specified with
  `times_grid`.
  Default value: `None`.
* <b>`precompute_iv`</b>: A bool. Whether or not to precompute implied volatility
  spline coefficients when using Dupire. If True, then `times_grid` and
  `spot_grid` must be supplied.
  Default value: False.
* <b>`dtype`</b>: The default dtype to use when converting values to `Tensor`s.
  Default value: `None` which means that default dtypes inferred by
    TensorFlow are used.
* <b>`name`</b>: Python string. The name to give to the ops created by this class.
  Default value: `None` which maps to the default name
    `local_volatility_model`.


#### Raises:


* <b>`ValueError`</b>: If `precompute_iv` is True, but grids are not supplied.

## Methods

<h3 id="dim"><code>dim</code></h3>

<a target="_blank" href="https://github.com/paolodelia99/tf-quant-finance/blob/main/tf_quant_finance/models/generic_ito_process.py">View source</a>

```python
dim()

The dimension of the process.

drift_fn

View source

drift_fn()

Python callable calculating instantaneous drift.

The callable should accept two real Tensor arguments of the same dtype. The first argument is the scalar time t, the second argument is the value of Ito process X - Tensor of shape batch_shape + sample_shape + [dim], where batch_shape represents a batch of models and sample_shape represents samples for each of the models. The result is value of drift a(t, X). The return value of the callable is a real Tensor of the same dtype as the input arguments and of shape batch_shape + sample_shape + [dim]. For example, sample_shape can stand for [num_samples] for Monte Carlo sampling, or [num_grid_points_1, ..., num_grid_points_dim] for Finite Difference solvers.

Returns:#

The instantaneous drift rate callable.

dtype

View source

dtype()

The data type of process realizations.

fd_solver_backward

View source

fd_solver_backward(
    start_time, end_time, coord_grid, values_grid, discounting=None,
    one_step_fn=None, boundary_conditions=None, start_step_count=0, num_steps=None,
    time_step=None, values_transform_fn=None, dtype=None, name=None, **kwargs
)

Returns a solver for Feynman-Kac PDE associated to the process.

This method applies a finite difference method to solve the final value problem as it appears in the Feynman-Kac formula associated to this Ito process. The Feynman-Kac PDE is closely related to the backward Kolomogorov equation associated to the stochastic process and allows for the inclusion of a discounting function.

For more details of the Feynman-Kac theorem see [1]. The PDE solved by this method is:

  V_t + Sum[mu_i(t, x) V_i, 1<=i<=n] +
    (1/2) Sum[ D_{ij} V_{ij}, 1 <= i,j <= n] - r(t, x) V = 0

In the above, V_t is the derivative of V with respect to t, V_i is the partial derivative with respect to x_i and V_{ij} the (mixed) partial derivative with respect to x_i and x_j. mu_i is the drift of this process and D_{ij} are the components of the diffusion tensor:

  D_{ij}(t,x) = (Sigma(t,x) . Transpose[Sigma(t,x)])_{ij}

This method evolves a spatially discretized solution of the above PDE from time t0 to time t1 < t0 (i.e. backwards in time). The solution V(t,x) is assumed to be discretized on an n-dimensional rectangular grid. A rectangular grid, G, in n-dimensions may be described by specifying the coordinates of the points along each axis. For example, a 2 x 4 grid in two dimensions can be specified by taking the cartesian product of [1, 3] and [5, 6, 7, 8] to yield the grid points with coordinates: [(1, 5), (1, 6), (1, 7), (1, 8), (3, 5) ... (3, 8)].

This method allows batching of solutions. In this context, batching means the ability to represent and evolve multiple independent functions V (e.g. V1, V2 …) simultaneously. A single discretized solution is specified by stating its values at each grid point. This can be represented as a Tensor of shape [d1, d2, … dn] where di is the grid size along the ith axis. A batch of such solutions is represented by a Tensor of shape: batch_shape + payoff_shape + [d1, d2, ... dn] where batch_shape is the batch of processes as in the underlying drift_fn and volatility_fn and payoff_shape are the equations to be solved for each batch element.

The evolution of the solution from t0 to t1 is often done by discretizing the differential equation to a difference equation along the spatial and temporal axes. The temporal discretization is given by a (sequence of) time steps [dt_1, dt_2, … dt_k] such that the sum of the time steps is equal to the total time step t0 - t1. If a uniform time step is used, it may equivalently be specified by stating the number of steps (n_steps) to take. This method provides both options via the time_step and num_steps parameters. However, not all methods need discretization along time direction (e.g. method of lines) so this argument may not be applicable to some implementations.

The workhorse of this method is the one_step_fn. For the commonly used methods, see functions in math.pde.steppers module.

The mapping between the arguments of this method and the above equation are described in the Args section below.

For a simple instructive example of implementation of this method, see models.GenericItoProcess.fd_solver_backward.

Examples#

import tensorflow as tf
import numpy as np

import tf_quant_finance as tff
dtype = tf.float64

# Specify volatilities, interest rates and strikes for the options
volatilities = tf.constant([[0.3], [0.15], [0.1]], dtype)
rates = tf.constant([[0.01], [0.03], [0.01]], dtype)
expiries = 1.0

# Define Generic Ito Process

# Process dimensionality
dim = 1

# Batch size of the process
num_processes = 3

def drift_fn(t, x):
  del t
  # `x` is expected to be of shape [num_processes] + sample_shape + [dim]
  # We need to expand rank of rates to
  # `[num_processes] + extra_rank * [1] + [1]`
  expand_rank = x.shape.rank - 2
  rates_expand = tf.reshape(
      rates, [num_processes] + (expand_rank + 1) * [1])
  # Output is of shape [num_processes] + sample_shape + [dim]
  return rates_expand * x

def vol_fn(t, x):
  del t
  # `x` is expected to be of shape [num_processes] + sample_shape + [dim]
  # As before, need to expand rank of volatilities to
  # `[num_processes] + extra_rank * [1] + [1]`
  expand_rank = x.shape.rank - 2
  volatilities_expand = tf.reshape(
      volatilities, [num_processes] + (expand_rank + 1) * [1])
  # Output is of shape [num_processes] + sample_shape + [dim, dim]
  return (tf.expand_dims(volatilities_expand * x, axis=-1)
          * tf.eye(dim, batch_shape=x.shape.as_list()[:-1], dtype=x.dtype))

process = tff.models.GenericItoProcess(dim=dim,
                                       drift_fn=drift_fn,
                                       volatility_fn=vol_fn,
                                       dtype=dtype)
# Define a 2 strikes for each batch process,
num_strikes = 2
# Shape [num_processes, num_strikes, 1]. Here 1 at the end is just for
# convenience
strikes = tf.constant([[[50], [60]], [[100], [90]], [[120], [90]]], dtype)

# Price a batch of European call options
@tff.math.pde.boundary_conditions.dirichlet
def upper_boundary_fn(t, grid):
  del grid
  # Shape (num_processes, num_strikes)
  return tf.squeeze(s_max - strikes * tf.exp(-rates  * (expiries - t)))

# Define discounting function
def discounting(t, x):
  del t, x
  rates_expand = tf.expand_dims(rates, axis=-1)
  # Shape compatible with (num_processes, num_strikes)
  return rates_expand

# Build a uniform grid
s_min = 0
s_max = 200
num_grid_points = 256  # Number of grid points

grid = tff.math.pde.grids.uniform_grid(minimums=[s_min],
                                       maximums=[s_max],
                                       sizes=[num_grid_points],
                                       dtype=dtype)

# Shape [num_processes, num_strikes, num_grid_points]
final_value_grid = tf.nn.relu(grid[0] - strikes)

# Estimated prices for the European options
process.fd_solver_backward(
    start_time=expiries,
    end_time=0,
    time_step=0.1,
    coord_grid=grid,
    values_grid=final_value_grid,
    discounting=discounting,
    boundary_condtions=[(None, upper_boundary_fn)])[0]
# Shape of the output is [num_processes, num_strikes, num_grid_points]

Args:#

  • start_time: Real positive scalar Tensor. The start time of the grid. Corresponds to time t0 above.

  • end_time: Real scalar Tensor smaller than the start_time and greater than zero. The time to step back to. Corresponds to time t1 above.

  • coord_grid: List of n rank 1 real Tensors. n is the dimension of the domain. The i-th Tensor has shape, [d_i] where d_i is the size of the grid along axis i. The coordinates of the grid points. Corresponds to the spatial grid G above.

  • values_grid: Real Tensor containing the function values at time start_time which have to be stepped back to time end_time. The shape of the Tensor must broadcast with batch_shape + payoff_shape + [d_1, d_2, ..., d_n]. batch_shape represents the batch of the processes as in the underlying drift_fn and volatility_fn. payoff_shape specifies equations to be solved for each batch element (with potentially different boundary/final conditions and for various coordinate grids). When the batch dimensions batch_shape or payoff_shape are present, the shape of values_gridmust be at leastbatch_shape + payoff_shape + dim * [1]`.

  • discounting: Callable corresponding to r(t,x) above. If not supplied, zero discounting is assumed.

  • one_step_fn: The transition kernel. A callable that consumes the following arguments by keyword:

    1. ‘time’: Current time

    2. ‘next_time’: The next time to step to. For the backwards in time evolution, this time will be smaller than the current time.

    3. ‘coord_grid’: The coordinate grid.

    4. ‘values_grid’: The values grid.

    5. ‘boundary_conditions’: The boundary conditions.

    6. ‘quadratic_coeff’: A callable returning the quadratic coefficients of the PDE (i.e. (1/2)D_{ij}(t, x) above). The callable accepts the time and coordinate grid as keyword arguments and returns a Tensor with shape that broadcasts with [dim, dim].

    7. ‘linear_coeff’: A callable returning the linear coefficients of the PDE (i.e. mu_i(t, x) above). Accepts time and coordinate grid as keyword arguments and returns a Tensor with shape that broadcasts with [dim].

    8. ‘constant_coeff’: A callable returning the coefficient of the linear homogeneous term (i.e. r(t,x) above). Same spec as above. The one_step_fn callable returns a 2-tuple containing the next coordinate grid, next values grid.

  • boundary_conditions: The boundary conditions. Only rectangular boundary conditions are supported. A list of tuples of size n (space dimension of the PDE). The elements of the Tuple can be either a Python Callable or None representing the boundary conditions at the minimum and maximum values of the spatial variable indexed by the position in the list. E.g., for n=2, the length of boundary_conditions should be 2, boundary_conditions[0][0] describes the boundary (y_min, x), and boundary_conditions[1][0]- the boundary (y, x_min). None values mean that the second order terms for that dimension on the boundary are assumed to be zero, i.e., if boundary_conditions[k][0] is None, ‘dV/dt + Sum[a_ij d2(A_ij V)/dx_i dx_j, 1 <= i, j <= n, i!=k+1, j!=k+1]

    • Sum[b_i d(B_i V)/dx_i, 1 <= i <= n] + c V = 0.’ For not None values, the boundary conditions are accepted in the form alpha(t, x) V + beta(t, x) V_n = gamma(t, x), where V_n is the derivative with respect to the exterior normal to the boundary. Each callable receives the current time t and the coord_grid at the current time, and should return a tuple of alpha, beta, and gamma. Each can be a number, a zero-rank Tensor or a Tensor whose shape is the grid shape with the corresponding dimension removed. For example, for a two-dimensional grid of shape (b, ny, nx), where b is the batch size, boundary_conditions[0][i] with i = 0, 1 should return a tuple of either numbers, zero-rank tensors or tensors of shape (b, nx). Similarly for boundary_conditions[1][i], except the tensor shape should be (b, ny). alpha and beta can also be None in case of Neumann and Dirichlet conditions, respectively. Default value: None. Unlike setting None to individual elements of boundary_conditions, setting the entire boundary_conditions object to None means Dirichlet conditions with zero value on all boundaries are applied.

  • start_step_count: Scalar integer Tensor. Initial value for the number of time steps performed. Default value: 0 (i.e. no previous steps performed).

  • num_steps: Positive int scalar Tensor. The number of time steps to take when moving from start_time to end_time. Either this argument or the time_step argument must be supplied (but not both). If num steps is k>=1, uniform time steps of size (t0 - t1)/k are taken to evolve the solution from t0 to t1. Corresponds to the n_steps parameter above.

  • time_step: The time step to take. Either this argument or the num_steps argument must be supplied (but not both). The type of this argument may be one of the following (in order of generality): (a) None in which case num_steps must be supplied. (b) A positive real scalar Tensor. The maximum time step to take. If the value of this argument is dt, then the total number of steps taken is N = (t0 - t1) / dt rounded up to the nearest integer. The first N-1 steps are of size dt and the last step is of size t0 - t1 - (N-1) * dt. (c) A callable accepting the current time and returning the size of the step to take. The input and the output are real scalar Tensors.

  • values_transform_fn: An optional callable applied to transform the solution values at each time step. The callable is invoked after the time step has been performed. The callable should accept the time of the grid, the coordinate grid and the values grid and should return the values grid. All input arguments to be passed by keyword.

  • dtype: The dtype to use.

  • name: The name to give to the ops. Default value: None which means solve_backward is used.

  • **kwargs: Additional keyword args: (1) pde_solver_fn: Function to solve the PDE that accepts all the above arguments by name and returns the same tuple object as required below. Defaults to tff.math.pde.fd_solvers.solve_backward.

Returns:#

A tuple object containing at least the following attributes: final_values_grid: A Tensor of same shape and dtype as values_grid. Contains the final state of the values grid at time end_time. final_coord_grid: A list of Tensors of the same specification as the input coord_grid. Final state of the coordinate grid at time end_time. step_count: The total step count (i.e. the sum of the start_step_count and the number of steps performed in this call.). final_time: The final time at which the evolution stopped. This value is given by max(min(end_time, start_time), 0).

fd_solver_forward

View source

fd_solver_forward(
    start_time, end_time, coord_grid, values_grid, one_step_fn=None,
    boundary_conditions=None, start_step_count=0, num_steps=None, time_step=None,
    values_transform_fn=None, dtype=None, name=None, **kwargs
)

Returns a solver for the Fokker Plank equation of this process.

The Fokker Plank equation (also known as the Kolmogorov Forward equation) associated to this Ito process is given by:

  V_t + Sum[(mu_i(t, x) V)_i, 1<=i<=n]
    - (1/2) Sum[ (D_{ij} V)_{ij}, 1 <= i,j <= n] = 0

with the initial value condition $\(V(0, x) = u(x)\)$.

This method evolves a spatially discretized solution of the above PDE from time t0 to time t1 > t0 (i.e. forwards in time). The solution V(t,x) is assumed to be discretized on an n-dimensional rectangular grid. A rectangular grid, G, in n-dimensions may be described by specifying the coordinates of the points along each axis. For example, a 2 x 4 grid in two dimensions can be specified by taking the cartesian product of [1, 3] and [5, 6, 7, 8] to yield the grid points with coordinates: [(1, 5), (1, 6), (1, 7), (1, 8), (3, 5) ... (3, 8)].

This method allows batching of solutions. In this context, batching means the ability to represent and evolve multiple independent functions V (e.g. V1, V2 …) simultaneously. A single discretized solution is specified by stating its values at each grid point. This can be represented as a Tensor of shape [d1, d2, … dn] where di is the grid size along the ith axis. A batch of such solutions is represented by a Tensor of shape: batch_shape + payoff_shape + [d1, d2, ... dn] where batch_shape is the batch of processes as in the underlying drift_fn and volatility_fn and payoff_shape are the equations to be solved for each batch element.

The evolution of the solution from t0 to t1 is often done by discretizing the differential equation to a difference equation along the spatial and temporal axes. The temporal discretization is given by a (sequence of) time steps [dt_1, dt_2, … dt_k] such that the sum of the time steps is equal to the total time step t1 - t0. If a uniform time step is used, it may equivalently be specified by stating the number of steps (n_steps) to take. This method provides both options via the time_step and num_steps parameters. However, not all methods need discretization along time direction (e.g. method of lines) so this argument may not be applicable to some implementations.

The workhorse of this method is the one_step_fn. For the commonly used methods, see functions in math.pde.steppers module.

The mapping between the arguments of this method and the above equation are described in the Args section below.

For a simple instructive example of implementation of this method, see models.GenericItoProcess.fd_solver_forward.

Args:#

  • start_time: Real positive scalar Tensor. The start time of the grid. Corresponds to time t0 above.

  • end_time: Real scalar Tensor smaller than the start_time and greater than zero. The time to step back to. Corresponds to time t1 above.

  • coord_grid: List of n rank 1 real Tensors. n is the dimension of the domain. The i-th Tensor has shape, [d_i] where d_i is the size of the grid along axis i. The coordinates of the grid points. Corresponds to the spatial grid G above.

  • values_grid: Real Tensor containing the function values at time start_time which have to be stepped back to time end_time. The shape of the Tensor must broadcast with batch_shape + payoff_shape + [d_1, d_2, ..., d_n]. batch_shape represents the batch of the processes as in the underlying drift_fn and volatility_fn. payoff_shape specifies equations to be solved for each batch element (with potentially different boundary/final conditions and for various coordinate grids). When the batch dimensions batch_shape or payoff_shape are present, the shape of values_gridmust be at leastbatch_shape + payoff_shape + dim * [1]`.

  • one_step_fn: The transition kernel. A callable that consumes the following arguments by keyword:

    1. ‘time’: Current time

    2. ‘next_time’: The next time to step to. For the backwards in time evolution, this time will be smaller than the current time.

    3. ‘coord_grid’: The coordinate grid.

    4. ‘values_grid’: The values grid.

    5. ‘quadratic_coeff’: A callable returning the quadratic coefficients of the PDE (i.e. (1/2)D_{ij}(t, x) above). The callable accepts the time and coordinate grid as keyword arguments and returns a Tensor with shape that broadcasts with [dim, dim].

    6. ‘linear_coeff’: A callable returning the linear coefficients of the PDE (i.e. mu_i(t, x) above). Accepts time and coordinate grid as keyword arguments and returns a Tensor with shape that broadcasts with [dim].

    7. ‘constant_coeff’: A callable returning the coefficient of the linear homogeneous term (i.e. r(t,x) above). Same spec as above. The one_step_fn callable returns a 2-tuple containing the next coordinate grid, next values grid.

  • boundary_conditions: The boundary conditions. Only rectangular boundary conditions are supported. A list of tuples of size n (space dimension of the PDE). The elements of the Tuple can be either a Python Callable or None representing the boundary conditions at the minimum and maximum values of the spatial variable indexed by the position in the list. E.g., for n=2, the length of boundary_conditions should be 2, boundary_conditions[0][0] describes the boundary (y_min, x), and boundary_conditions[1][0]- the boundary (y, x_min). None values mean that the second order terms for that dimension on the boundary are assumed to be zero, i.e., if boundary_conditions[k][0] is None, ‘dV/dt + Sum[a_ij d2(A_ij V)/dx_i dx_j, 1 <= i, j <= n, i!=k+1, j!=k+1]

    • Sum[b_i d(B_i V)/dx_i, 1 <= i <= n] + c V = 0.’ For not None values, the boundary conditions are accepted in the form alpha(t, x) V + beta(t, x) V_n = gamma(t, x), where V_n is the derivative with respect to the exterior normal to the boundary. Each callable receives the current time t and the coord_grid at the current time, and should return a tuple of alpha, beta, and gamma. Each can be a number, a zero-rank Tensor or a Tensor whose shape is the grid shape with the corresponding dimension removed. For example, for a two-dimensional grid of shape (b, ny, nx), where b is the batch size, boundary_conditions[0][i] with i = 0, 1 should return a tuple of either numbers, zero-rank tensors or tensors of shape (b, nx). Similarly for boundary_conditions[1][i], except the tensor shape should be (b, ny). alpha and beta can also be None in case of Neumann and Dirichlet conditions, respectively. Default value: None. Unlike setting None to individual elements of boundary_conditions, setting the entire boundary_conditions object to None means Dirichlet conditions with zero value on all boundaries are applied.

  • start_step_count: Scalar integer Tensor. Initial value for the number of time steps performed. Default value: 0 (i.e. no previous steps performed).

  • num_steps: Positive int scalar Tensor. The number of time steps to take when moving from start_time to end_time. Either this argument or the time_step argument must be supplied (but not both). If num steps is k>=1, uniform time steps of size (t0 - t1)/k are taken to evolve the solution from t0 to t1. Corresponds to the n_steps parameter above.

  • time_step: The time step to take. Either this argument or the num_steps argument must be supplied (but not both). The type of this argument may be one of the following (in order of generality): (a) None in which case num_steps must be supplied. (b) A positive real scalar Tensor. The maximum time step to take. If the value of this argument is dt, then the total number of steps taken is N = (t1 - t0) / dt rounded up to the nearest integer. The first N-1 steps are of size dt and the last step is of size t1 - t0 - (N-1) * dt. (c) A callable accepting the current time and returning the size of the step to take. The input and the output are real scalar Tensors.

  • values_transform_fn: An optional callable applied to transform the solution values at each time step. The callable is invoked after the time step has been performed. The callable should accept the time of the grid, the coordinate grid and the values grid and should return the values grid. All input arguments to be passed by keyword.

  • dtype: The dtype to use.

  • name: The name to give to the ops. Default value: None which means solve_forward is used.

  • **kwargs: Additional keyword args: (1) pde_solver_fn: Function to solve the PDE that accepts all the above arguments by name and returns the same tuple object as required below. Defaults to tff.math.pde.fd_solvers.solve_forward.

Returns:#

A tuple object containing at least the following attributes: final_values_grid: A Tensor of same shape and dtype as values_grid. Contains the final state of the values grid at time end_time. final_coord_grid: A list of Tensors of the same specification as the input coord_grid. Final state of the coordinate grid at time end_time. step_count: The total step count (i.e. the sum of the start_step_count and the number of steps performed in this call.). final_time: The final time at which the evolution stopped. This value is given by max(min(end_time, start_time), 0).

from_market_data

View source

@classmethod
from_market_data(
    cls, dim, valuation_date, expiry_dates, strikes, implied_volatilities, spot,
    discount_factor_fn, dividend_yield=None, local_volatility_from_iv=True,
    times_grid=None, spot_grid=None, precompute_iv=False, dtype=None, name=None
)

Creates a LocalVolatilityModel from market data.

Args:#

  • dim: A Python scalar which corresponds to the number of underlying assets comprising the model.

  • valuation_date: A DateTensor specifying the valuation (or settlement) date for the market data.

  • expiry_dates: A DateTensor of shape (dim, num_expiries) containing the expiry dates on which the implied volatilities are specified.

  • strikes: A Tensor of real dtype and shape (dim, num_expiries, num_strikes)specifying the strike prices at which implied volatilities are specified.

  • implied_volatilities: A Tensor of real dtype and shape (dim, num_expiries, num_strikes) specifying the implied volatilities.

  • spot: A real Tensor of shape (dim,) specifying the underlying spot price on the valuation date.

  • discount_factor_fn: A python callable accepting one real Tensor argument time t. It should return a Tensor specifying the discount factor to time t.

  • dividend_yield: A real Tensor of shape compatible with spot_price specifying the (continuously compounded) dividend yield. If the underlying is an FX rate, then use this input to specify the foreign interest rate. Default value: None in which case the input is set to Zero.

  • local_volatility_from_iv: A bool. If True, calculates the Dupire local volatility function from implied volatilities. Otherwise, it computes the local volatility using option prices. Default value: True.

  • times_grid: A Tensor of shape [num_time_samples]. The grid on which to do interpolation over time. Must be jointly specified with spot_grid or None. Default value: None.

  • spot_grid: A Tensor of shape [num_spot_samples]. The grid on which to do interpolation over spots. Must be jointly specified with times_grid or None. Default value: None.

  • precompute_iv: A bool. Whether or not to precompute implied volatility spline coefficients when using Dupire’s formula. This is done by precomputing values of implied volatility on the grid times_grid x spot_grid. The algorithm then steps through times_grid in sample_paths. Default value: False.

  • 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 class. Default value: None which maps to the default name from_market_data.

Returns:#

An instance of LocalVolatilityModel constructed using the input data.

from_volatility_surface

View source

@classmethod
from_volatility_surface(
    cls, dim, spot, implied_volatility_surface, discount_factor_fn,
    dividend_yield=None, local_volatility_from_iv=True, times_grid=None,
    spot_grid=None, precompute_iv=False, dtype=None, name=None
)

Creates a LocalVolatilityModel from implied volatility data.

Args:#

  • dim: A Python scalar which corresponds to the number of underlying assets comprising the model.

  • spot: A real Tensor of shape (dim,) specifying the underlying spot price on the valuation date.

  • implied_volatility_surface: Either an instance of processed_market_data.VolatilitySurface or a Python object containing the implied volatility market data. If the input is a Python object, then the object must implement a function volatility(strike, expiry_times) which takes real Tensors corresponding to option strikes and time to expiry and returns a real Tensor containing the corresponding market implied volatility. The shape of strike is (n,dim) where dim is the dimensionality of the local volatility process and t is a scalar tensor. The output from the callable is a Tensor of shape (n,dim) containing the interpolated implied volatilties.

  • discount_factor_fn: A python callable accepting one real Tensor argument time t. It should return a Tensor specifying the discount factor to time t.

  • dividend_yield: A real Tensor of shape compatible with spot_price specifying the (continuously compounded) dividend yield. If the underlying is an FX rate, then use this input to specify the foreign interest rate. Default value: None in which case the input is set to Zero.

  • local_volatility_from_iv: A bool. If True, calculates the Dupire local volatility function from implied volatilities. Otherwise, it computes the local volatility using option prices. Default value: True.

  • times_grid: A Tensor of shape [num_time_samples]. The grid on which to do interpolation over time. Must be jointly specified with spot_grid or None. Default value: None.

  • spot_grid: A Tensor of shape [num_spot_samples]. The grid on which to do interpolation over spots. Must be jointly specified with times_grid or None. Default value: None.

  • precompute_iv: A bool. Whether or not to precompute implied volatility spline coefficients when using Dupire’s formula. This is done by precomputing values of implied volatility on the grid times_grid x spot_grid. The algorithm then steps through times_grid in sample_paths. Default value: False.

  • 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 class. Default value: None which maps to the default name from_volatility_surface.

Returns:#

An instance of LocalVolatilityModel constructed using the input data.

local_volatility_fn

View source

local_volatility_fn()

Local volatility function.

name

View source

name()

The name to give to ops created by this class.

precompute_iv

View source

precompute_iv()

Whether or not to precompute IV in Dupire’s formula.

sample_paths

View source

sample_paths(
    times, num_samples=1, initial_state=None, random_type=None, seed=None,
    swap_memory=True, time_step=None, num_time_steps=None, skip=0,
    precompute_normal_draws=True, times_grid=None, normal_draws=None,
    watch_params=None, validate_args=False, name=None
)

Returns samples from the LV process.

See GenericItoProcess.sample_paths. If times_grid is supplied to __init__, then times_grid cannot be supplied here.

Raises:#

  • ValueError: If precompute_iv is True, but time_step, num_time_steps or times_grid are given.

volatility_fn

View source

volatility_fn()

Python callable calculating the instantaneous volatility.

The callable should accept two real Tensor arguments of the same dtype and shape times_shape. The first argument is the scalar time t, the second argument is the value of Ito process X - Tensor of shape batch_shape + sample_shape + [dim], where batch_shape represents a batch of models and sample_shape represents samples for each of the models. The result is value of volatility S_{ij}(t, X). The return value of the callable is a real Tensor of the same dtype as the input arguments and of shape batch_shape + sample_shape + [dim, dim]. For example, sample_shape can stand for [num_samples] for Monte Carlo sampling, or [num_grid_points_1, ..., num_grid_points_dim] for Finite Difference solvers.

Returns:#

The instantaneous volatility callable.