def _price_lognormal_rate(self, valuation_date, market, pricing_context):
        """Computes caplet/floorlet prices using lognormal model for forward rates.

    The function computes individual caplet prices for the batch of caps/floors
    using the lognormal model for the forward rates. If the volatilities are
    are supplied (through the input `pricing_context`) then they are used as
    forward rate volatilies. Otherwise, volatilities are extracted using the
    volatility surface for `market`.

    Args:
      valuation_date: A scalar `DateTensor` specifying the date on which
        valuation is being desired.
      market: A namedtuple of type `InterestRateMarket` which contains the
        necessary information for pricing the Cap/Floor.
      pricing_context: An optional input containing the black volatility for
        for the forward rates.

    Returns:
      A Rank 1 `Tensor` of real type containing the price of each caplet
      (or floorlet) based using the lognormal model for forward rates.
    """

        discount_curve = market.discount_curve

        discount_factors = tf.where(
            self._payment_dates > valuation_date,
            discount_curve.get_discount_factor(self._payment_dates), 0.)

        forward_rates = self._get_forward_rate(valuation_date, market)

        if pricing_context is None:
            volatility_surface = market.volatility_curve
            black_vols = volatility_surface.interpolate(
                self._reset_dates, self._strike, self._term)
        else:
            black_vols = tf.convert_to_tensor(pricing_context,
                                              dtype=self._dtype)

        expiry_times = dates.daycount_actual_365_fixed(
            start_date=valuation_date,
            end_date=self._reset_dates,
            dtype=self._dtype)
        caplet_prices = black_scholes.option_price(
            forwards=forward_rates,
            strikes=self._strike,
            volatilities=black_vols,
            expiries=expiry_times,
            is_call_options=self._is_cap)
        intrinsic_value = tf.where(
            self._is_cap, tf.math.maximum(forward_rates - self._strike, 0.0),
            tf.math.maximum(self._strike - forward_rates, 0))
        caplet_prices = tf.where(
            self._payment_dates < valuation_date,
            tf.constant(0., dtype=self._dtype),
            tf.where(self._accrual_start_dates < valuation_date,
                     intrinsic_value, caplet_prices))
        caplet_prices = self._notional * self._daycount_fractions * caplet_prices
        return discount_factors * caplet_prices
Exemple #2
0
 def _option_price(expiry_time, strike):
   vols = implied_volatility_surface(strike=strike, expiry_times=expiry_time)
   c_k_t = black_scholes.option_price(volatilities=vols, strikes=strike,
                                      expiries=expiry_time,
                                      spots=initial_spot_price,
                                      discount_rates=risk_free_rate,
                                      continuous_dividends=dividend_yield,
                                      dtype=dtype)
   return c_k_t
 def _option_price(expiry_time, strike):
     discount_factors = tf.convert_to_tensor(
         discount_factor_fn(expiry_time), dtype=dtype)
     vols = implied_volatility_surface(strike=strike,
                                       expiry_times=expiry_time)
     c_k_t = black_scholes.option_price(volatilities=vols,
                                        strikes=strike,
                                        expiries=expiry_time,
                                        spots=initial_spot_price,
                                        dividend_rates=dividend_yield,
                                        discount_factors=discount_factors,
                                        dtype=dtype)
     return c_k_t
Exemple #4
0
    def _price_lognormal_rate(self, market, pricing_context, forward_swap_rate,
                              strike, expiry_time):
        """Price the swaption using lognormal model for rate."""

        # Ideally we would like the model to tell what piece of market data is
        # needed. For example, a Black lognormal model will tell us to pick
        # lognormal vols and Black normal model should tell us to pick normal
        # vols.
        if pricing_context is None:
            swaption_vol_cube = rc.get_implied_volatility_data(market)
            term = self._swap.swap_term
            black_vols = swaption_vol_cube.interpolate(self._expiry_date,
                                                       strike, term)
        else:
            black_vols = tf.convert_to_tensor(pricing_context,
                                              dtype=self._dtype)
        return black_scholes.option_price(volatilities=black_vols,
                                          strikes=strike,
                                          expiries=expiry_time,
                                          forwards=forward_swap_rate,
                                          is_call_options=self._swap.is_payer,
                                          dtype=self._dtype)
Exemple #5
0
def _option_prices(*,
                   volatilities=None,
                   strikes=None,
                   forwards=None,
                   expiries=None,
                   is_call_options=True,
                   is_normal_model=True,
                   dtype=None):
  """Computes prices of European options using normal model.

  Args:
    volatilities: Real `Tensor` of any shape and dtype. The volatilities to
      expiry of the options to price.
    strikes: A real `Tensor` of the same dtype and compatible shape as
      `volatilities`. The strikes of the options to be priced.
    forwards: A real `Tensor` of any shape that broadcasts to the shape of
      `volatilities`. The forwards to maturity. Either this argument or the
    expiries: A real `Tensor` of same dtype and compatible shape as
      `volatilities`. The expiry of each option. The units should be such that
      `expiry * volatility**2` is dimensionless.
    is_call_options: A boolean `Tensor` of a shape compatible with
      `volatilities`. Indicates whether the option is a call (if True) or a put
      (if False). If not supplied, call options are assumed.
    is_normal_model: A boolean `Tensor` of a shape compatible with
      `volatilities`. Indicates whether the options should be priced using
      normal model (if True) or lognormal model (if False). If not supplied,
      normal model is assumed.
    dtype: Optional `tf.DType`. If supplied, the dtype to be used for conversion
      of any supplied non-`Tensor` arguments to `Tensor`.
      Default value: `None` which maps to the default dtype inferred by
        TensorFlow.

  Returns:
    Options prices computed using normal model for the underlying.
  """
  dtype = dtype or tf.constant(0.0).dtype
  def _ncdf(x):
    sqrt_2 = tf.math.sqrt(tf.constant(2.0, dtype=dtype))
    return (tf.math.erf(x / sqrt_2) + 1) / 2

  sqrt_var = tf.math.sqrt(expiries) * volatilities
  d = (forwards - strikes) / sqrt_var
  mu = tf.constant(0., dtype=dtype)
  loc = tf.constant(1., dtype=dtype)
  value = tf.where(
      is_normal_model,
      tf.where(is_call_options, (forwards - strikes) * _ncdf(d) +
               sqrt_var * tfp.distributions.Normal(mu, loc).prob(d),
               (strikes - forwards) * _ncdf(-d) +
               sqrt_var * tfp.distributions.Normal(mu, loc).prob(d)),
      black_scholes.option_price(
          volatilities=volatilities,
          strikes=strikes,
          expiries=expiries,
          forwards=forwards,
          is_call_options=is_call_options,
          dtype=dtype))
  value = tf.where(
      expiries > 0, value,
      tf.where(is_call_options, tf.maximum(forwards - strikes, 0.0),
               tf.maximum(strikes - forwards, 0.0)))
  return value