Exemple #1
0
    def __init__(self,
                 settlement_date,
                 maturity_date,
                 coupon_spec,
                 start_date=None,
                 first_coupon_date=None,
                 penultimate_coupon_date=None,
                 holiday_calendar=None,
                 dtype=None,
                 name=None):
        """Initialize a batch of fixed coupon bonds.

    Args:
      settlement_date: A rank 1 `DateTensor` specifying the settlement date of
        the bonds.
      maturity_date: A rank 1 `DateTensor` specifying the maturity dates of the
        bonds. The shape of the input should be the same as that of
        `settlement_date`.
      coupon_spec: A list of `FixedCouponSpecs` specifying the coupon payments.
        The length of the list should be the same as the number of bonds
        being created.
      start_date: An optional `DateTensor` specifying the dates when the
        interest starts to accrue for the coupons. The input can be used to
        specify a forward start date for the coupons. The shape of the input
        correspond to the numbercof instruments being created.
        Default value: None in which case the coupons start to accrue from the
        `settlement_date`.
      first_coupon_date: An optional rank 1 `DateTensor` specifying the dates
        when first coupon will be paid for bonds with irregular first coupon.
      penultimate_coupon_date: An optional rank 1 `DateTensor` specifying the
        dates when the penultimate coupon (or last regular coupon) will be paid
        for bonds with irregular last coupon.
      holiday_calendar: An instance of `dates.HolidayCalendar` to specify
        weekends and holidays.
        Default value: None in which case a holiday calendar would be created
        with Saturday and Sunday being the holidays.
      dtype: `tf.Dtype`. If supplied the dtype for the real variables or ops
        either supplied to the bond object or created by the bond object.
        Default value: None which maps to the default dtype inferred by
        TensorFlow.
      name: Python str. The name to give to the ops created by this class.
        Default value: `None` which maps to 'bond'.
    """
        self._name = name or 'bond'

        if holiday_calendar is None:
            holiday_calendar = dates.create_holiday_calendar(
                weekend_mask=dates.WeekendMask.SATURDAY_SUNDAY)

        with tf.name_scope(self._name):
            self._dtype = dtype
            self._settlement_date = dates.convert_to_date_tensor(
                settlement_date)
            self._maturity_date = dates.convert_to_date_tensor(maturity_date)
            self._holiday_calendar = holiday_calendar
            self._setup(coupon_spec, start_date, first_coupon_date,
                        penultimate_coupon_date)
Exemple #2
0
    def __init__(self,
                 start_date,
                 maturity_date,
                 pay_leg,
                 receive_leg,
                 holiday_calendar=None,
                 dtype=None,
                 name=None):
        """Initialize a batch of IRS contracts.

    Args:
      start_date: A rank 1 `DateTensor` specifying the dates for the inception
        (start of the accrual) of the swap contracts. The shape of the input
        correspond to the number of instruments being created.
      maturity_date: A rank 1 `DateTensor` specifying the maturity dates for
        each contract. The shape of the input should be the same as that of
        `start_date`.
      pay_leg: A scalar or a list of either `FixedCouponSpecs` or
        `FloatCouponSpecs` specifying the coupon payments for the payment leg
        of the swap. If specified as a list then the length of the list should
        be the same as the number of instruments being created. If specified as
        a scalar, then the elements of the namedtuple must be of the same shape
        as (or compatible to) the shape of `start_date`.
      receive_leg: A scalar or a list of either `FixedCouponSpecs` or
        `FloatCouponSpecs` specifying the coupon payments for the receiving leg
        of the swap. If specified as a list then the length of the list should
        be the same as the number of instruments being created. If specified as
        a scalar, then the elements of the namedtuple must be of the same shape
        as (or compatible with) the shape of `start_date`.
      holiday_calendar: An instance of `dates.HolidayCalendar` to specify
        weekends and holidays.
        Default value: None in which case a holiday calendar would be created
        with Saturday and Sunday being the holidays.
      dtype: `tf.Dtype`. If supplied the dtype for the real variables or ops
        either supplied to the IRS object or created by the IRS object.
        Default value: None which maps to the default dtype inferred by
        TensorFlow.
      name: Python str. The name to give to the ops created by this class.
        Default value: `None` which maps to 'interest_rate_swap'.
    """
        self._name = name or 'interest_rate_swap'

        if holiday_calendar is None:
            holiday_calendar = dates.create_holiday_calendar(
                weekend_mask=dates.WeekendMask.SATURDAY_SUNDAY)

        with tf.name_scope(self._name):
            self._dtype = dtype
            self._start_date = dates.convert_to_date_tensor(start_date)
            self._maturity_date = dates.convert_to_date_tensor(maturity_date)
            self._holiday_calendar = holiday_calendar
            self._floating_leg = None
            self._fixed_leg = None
            self._pay_leg = self._setup_leg(pay_leg)
            self._receive_leg = self._setup_leg(receive_leg)
            self._is_payer = isinstance(self._pay_leg, cs.FixedCashflowStream)
    def __init__(self,
                 valuation_date: types.DateTensor,
                 expiries: types.DateTensor,
                 strikes: types.FloatTensor,
                 volatilities: types.FloatTensor,
                 daycount_convention: Optional[
                     _DayCountConventionsProtoType] = None,
                 dtype: Optional[tf.DType] = None,
                 name: Optional[str] = None):
        """Initializes the volatility surface.

    Args:
      valuation_date: A `DateTensor` specifying the valuation (or
        settlement) date for the curve.
      expiries: A `DateTensor` containing the expiry dates on which the
        implied volatilities are specified. Should have a compatible shape with
        valuation_date.
      strikes: A `Tensor` of real dtype specifying the strikes corresponding to
        the input maturities. The shape of this input should match the shape of
        `expiries`.
      volatilities: A `Tensor` of real dtype specifying the volatilities
        corresponding to  the input maturities. The shape of this input should
        match the shape of `expiries`.
      daycount_convention: `DayCountConventions` to use for the interpolation
        purpose.
        Default value: `None` which maps to actual/365 day count convention.
      dtype: `tf.Dtype`. Optional input specifying the dtype of the `rates`
        input.
      name: Python str. The name to give to the ops created by this function.
        Default value: `None` which maps to 'rate_curve'.
    """
        self._name = name or "VolatilitySurface"
        self._dtype = dtype or tf.float64
        with tf.name_scope(self._name):
            self._daycount_convention = (daycount_convention
                                         or _DayCountConventions.ACTUAL_365)
            self._day_count_fn = utils.get_daycount_fn(
                self._daycount_convention)
            self._valuation_date = dateslib.convert_to_date_tensor(
                valuation_date)
            self._expiries = dateslib.convert_to_date_tensor(expiries)
            self._strikes = tf.convert_to_tensor(strikes,
                                                 dtype=self._dtype,
                                                 name="strikes")
            self._volatilities = tf.convert_to_tensor(volatilities,
                                                      dtype=self._dtype,
                                                      name="volatilities")
            expiry_times = self._day_count_fn(start_date=self._valuation_date,
                                              end_date=self._expiries,
                                              dtype=self._dtype)
            self._interpolator = interpolation_2d.Interpolation2D(
                expiry_times, strikes, volatilities, dtype=self._dtype)
Exemple #4
0
    def discount_factor(
            self,
            interpolation_dates: Optional[types.DateTensor] = None,
            interpolation_times: Optional[types.FloatTensor] = None,
            name: Optional[str] = None):
        """Returns discount factors at `interpolation_dates`."""

        if interpolation_dates is None and interpolation_times is None:
            raise ValueError(
                "Either interpolation_dates or interpolation times "
                "must be supplied.")
        if interpolation_dates is not None:
            interpolation_dates = dateslib.convert_to_date_tensor(
                interpolation_dates)
            times = self._get_time(interpolation_dates)
        else:
            times = tf.convert_to_tensor(interpolation_times, self._dtype)
        if self._interpolate_rates:
            rates = self._interpolator(times, self._times,
                                       self.discount_rate_nodes)
            discount_factor = tf.math.exp(-rates * times)
        else:
            discount_factor = self._interpolator(times, self._times,
                                                 self.discount_factor_nodes)
        return tf.identity(discount_factor, name=name or "discount_factor")
    def __init__(self,
                 valuation_date: types.DateTensor,
                 market_data_dict: Dict[str, Any],
                 config: Optional[Dict[str, Any]] = None,
                 dtype: Optional[tf.DType] = None):
        """Market data constructor.

    ####Example

    ```python
    market_data_dict = {
    "Currency":  {
        curve_index : {"date": DateTensor, "discount": tf.Tensor},
        surface_id(curve_type): "to be specified",
        fixings: "to be specified"},
    "Asset": "to be specified"}
    ```
    Here `curve_index` refers to `curve_types.Index`. The user is expected to
    supply all necessary curves used for pricing. The pricing functions should
    decide which curve to use and how to map `RateIndexType` to
    `curve_types.Index`. Default mapping can be overridden via instrument
    configuration.

    Args:
      valuation_date: Valuation date.
      market_data_dict: Market data dictionary.
      config: Market data config. See `market_data_config` module description.
        Used to set up rate curve and volatility surface parameters.
      dtype: A `dtype` to use for float-like `Tensor`s.
        Default value: `tf.float64`.
    """
        self._valuation_date = dateslib.convert_to_date_tensor(valuation_date)
        self._market_data_dict = market_data_dict
        self._config = config
        self._dtype = dtype or tf.float64
  def cashflows(self,
                market: pmd.ProcessedMarketData,
                name: Optional[str] = None
                ) -> Tuple[types.DateTensor, types.FloatTensor]:
    """Returns cashflows for the fixed leg.

    Args:
      market: An instance of `ProcessedMarketData`.
      name: Python str. The name to give to the ops created by this function.
        Default value: `None` which maps to 'cashflows'.

    Returns:
      A tuple of two `Tensor`s of shape `batch_shape + [num_cashflows]` and
      containing the dates and the corresponding cashflows price for each
      stream based on the input market data.
    """
    name = name or (self._name + "_cashflows")
    with tf.name_scope(name):
      valuation_date = dateslib.convert_to_date_tensor(market.date)
      future_cashflows = tf.cast(self._payment_dates >= valuation_date,
                                 dtype=self._dtype)
      # self._notional is of shape [batch_shape], so broadcasting is needed
      notional = tf.expand_dims(self._notional, axis=-1)
      # Cashflow present values.
      cashflows = notional * (
          future_cashflows * self._daycount_fractions * self._coupon_rate)
      return  self._payment_dates, cashflows
Exemple #7
0
    def price(self,
              valuation_date,
              market,
              model=None,
              pricing_context=None,
              name=None):
        """Returns the present value of the instrument on the valuation date.

    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 interest rate swap.
      model: Reserved for future use.
      pricing_context: Additional context relevant for pricing.
      name: Python str. The name to give to the ops created by this function.
        Default value: `None` which maps to 'price'.

    Returns:
      A Rank 1 `Tensor` of real type containing the modeled price of each IRS
      contract based on the input market data.
    """

        name = name or (self._name + '_price')
        with tf.name_scope(name):
            valuation_date = dates.convert_to_date_tensor(valuation_date)
            pay_cf = self._pay_leg.price(valuation_date, market, model,
                                         pricing_context)
            receive_cf = self._receive_leg.price(valuation_date, market, model,
                                                 pricing_context)
            return receive_cf - pay_cf
Exemple #8
0
    def __init__(self, swap, expiry_date=None, dtype=None, name=None):
        """Initialize a batch of European swaptions.

    Args:
      swap: An instance of `InterestRateSwap` specifying the interest rate
        swaps underlying the swaptions. The batch size of the swaptions being
        created would be the same as the batch size of the `swap`.
      expiry_date: An optional rank 1 `DateTensor` specifying the expiry dates
        for each swaption. The shape of the input should be the same as the
        batch size of the `swap` input.
        Default value: None in which case the option expity date is the same as
        the start date of each underlying swap.
      dtype: `tf.Dtype`. If supplied the dtype for the real variables or ops
        either supplied to the Swaption object or created by the Swaption
        object.
        Default value: None which maps to the default dtype inferred by
        TensorFlow.
      name: Python str. The name to give to the ops created by this class.
        Default value: `None` which maps to 'swaption'.
    """
        self._name = name or 'swaption'

        with tf.name_scope(self._name):
            self._dtype = dtype
            self._expiry_date = dates.convert_to_date_tensor(expiry_date)
            self._swap = swap
Exemple #9
0
    def par_rate(self, valuation_date, market, model=None):
        """Returns the par swap rate for the swap."""

        valuation_date = dates.convert_to_date_tensor(valuation_date)
        swap_annuity = self._annuity(valuation_date, market, model, False)
        float_pv = self._floating_leg.price(valuation_date, market, model)

        return float_pv / swap_annuity
 def fixings(self,
             date: types.DateTensor,
             fixing_type: curve_types.RateIndexCurve,
             tenor: period_pb2.Period) -> types.FloatTensor:
   """Returns past fixings of the market rates at the specified dates."""
   date = dateslib.convert_to_date_tensor(date)
   return tf.zeros(tf.shape(date.ordinal()),
                   dtype=self._dtype, name="fixings")
Exemple #11
0
 def _refercence_rate_fn(t):
   # The input `t` is a real `Tensor` specifying the time from valuation.
   # We convert it into a `DateTensor` by first conversting it into the
   # corresponding ordinal (assuming ACT_365 convention).
   interpolation_ordinals = tf.cast(
       tf.round(t * 365.0 +  valuation_date_ordinal), dtype=tf.int32)
   interpolation_dates = dateslib.convert_to_date_tensor(
       interpolation_ordinals)
   return reference_curve.discount_rate(interpolation_dates)
Exemple #12
0
  def price(self, valuation_date, market, model=None, pricing_context=None,
            name=None):
    """Returns the present value of the stream on the valuation date.

    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 cashflow stream.
      model: An optional input of type `InterestRateModelType` to specify which
        model to use for pricing.
        Default value: `None` in which case `NORMAL_RATE` model is used.
      pricing_context: An optional input to provide additional parameters (such
        as model parameters) relevant for pricing.
      name: Python str. The name to give to the ops created by this function.
        Default value: `None` which maps to 'price'.

    Returns:
      A Rank 1 `Tensor` of real type containing the modeled price of each stream
      contract based on the input market data.
    """

    name = name or (self._name + '_price')
    with tf.name_scope(name):
      valuation_date = dates.convert_to_date_tensor(valuation_date)
      discount_curve = market.discount_curve
      past_fixing = rc.get_rate_index(
          market, self._start_date, rc.RateIndexType.SWAP, dtype=self._dtype)
      past_fixing = tf.repeat(
          tf.convert_to_tensor(past_fixing, dtype=self._dtype),
          self._num_cashflows)

      discount_factors = discount_curve.get_discount_factor(self._payment_dates)
      cms_rates = self._swap.par_rate(valuation_date, market, model)

      cms_rates = tf.where(self._daycount_fractions > 0., cms_rates,
                           tf.zeros_like(cms_rates))
      # If coupon end date is before the valuation date, the payment is in the
      # past. If valuation date is between coupon start date and coupon end
      # date, then the rate has been fixed but not paid. Otherwise the rate is
      # not fixed and should be read from the curve.
      cms_rates = tf.where(
          self._coupon_end_dates < valuation_date,
          tf.constant(0., dtype=self._dtype),
          tf.where(self._coupon_start_dates < valuation_date,
                   past_fixing, cms_rates))
      cms_rates = self._adjust_convexity(
          valuation_date, market, model, pricing_context, cms_rates,
          discount_factors)

      coupon_rate = self._coupon_multiplier * (
          cms_rates + self._coupon_basis)

      cashflow_pvs = self._notional * (
          self._daycount_fractions * coupon_rate * discount_factors)
      return tf.math.segment_sum(cashflow_pvs, self._contract_index)
Exemple #13
0
  def __init__(self,
               start_date,
               end_date,
               coupon_spec,
               dtype=None,
               name=None):
    """Initialize a batch of CMS cashflow streams.

    Args:
      start_date: A rank 1 `DateTensor` specifying the starting dates of the
        accrual of the first coupon of the cashflow stream. The shape of the
        input correspond to the numbercof streams being created.
      end_date: A rank 1 `DateTensor` specifying the end dates for accrual of
        the last coupon in each cashflow stream. The shape of the input should
        be the same as that of `start_date`.
      coupon_spec: A list of `CMSCouponSpecs` specifying the details of the
        coupon payment for the cashflow stream. The length of the list should
        be the same as the number of streams being created. Each coupon within
        the list must have the same daycount_convention and businessday_rule.
      dtype: `tf.Dtype`. If supplied the dtype for the real variables or ops
        either supplied to the FloatingCashflowStream object or created by the
        object.
        Default value: None which maps to the default dtype inferred by
        TensorFlow.
      name: Python str. The name to give to the ops created by this class.
        Default value: `None` which maps to 'floating_cashflow_stream'.
    """

    super(CMSCashflowStream, self).__init__()
    self._name = name or 'cms_cashflow_stream'

    with tf.name_scope(self._name):
      self._start_date = dates.convert_to_date_tensor(start_date)
      self._end_date = dates.convert_to_date_tensor(end_date)
      self._batch_size = self._start_date.shape[0]
      self._first_coupon_date = None
      self._penultimate_coupon_date = None
      self._dtype = dtype

      self._setup(coupon_spec)
def ratecurve_from_discounting_function(discount_fn, dtype=None):
    """Returns `RateCurve` object using the supplied function for discounting.

  Args:
    discount_fn: A python callable which takes a `DateTensor` as an input and
      returns the corresponding discount factor as an output.
    dtype: `tf.Dtype`. Optional input specifying the dtype of the real tensors
      and ops.

  Returns:
    An object of class `RateCurveFromDiscountingFunction` which uses the
    supplied function for discounting.
  """

    dtype = dtype or tf.constant(0.0).dtype
    pseudo_maturity_dates = dates.convert_to_date_tensor([(2020, 1, 1)])
    pseudo_rates = tf.convert_to_tensor([0.0], dtype=dtype)
    pseudo_valuation_date = dates.convert_to_date_tensor((2020, 1, 1))

    return RateCurveFromDiscountingFunction(pseudo_maturity_dates,
                                            pseudo_rates,
                                            pseudo_valuation_date, discount_fn,
                                            dtype)
    def get_forward_rate(self,
                         start_date,
                         maturity_date,
                         daycount_fraction=None):
        """Returns the simply accrued forward rate between [start_dt, maturity_dt].

    Args:
      start_date: A `DateTensor` specifying the start of the accrual period
        for the forward rate.
      maturity_date: A `DateTensor` specifying the end of the accrual period
        for the forward rate. The shape of `maturity_date` must be the same
        as the shape of the `DateTensor` `start_date`.
      daycount_fraction: An optional `Tensor` of real dtype specifying the
        time between `start_date` and `maturity_date` in years computed using
        the forward rate's day count basis. The shape of the input should be
        the same as that of `start_date` and `maturity_date`.
        Default value: `None`, in which case the daycount fraction is computed
        using `ACTUAL_365` convention.

    Returns:
      A real tensor of same shape as the inputs containing the simply compounded
      forward rate.
    """
        start_date = dates.convert_to_date_tensor(start_date)
        maturity_date = dates.convert_to_date_tensor(maturity_date)
        if daycount_fraction is None:
            daycount_fraction = dates.daycount_actual_365_fixed(
                start_date=start_date,
                end_date=maturity_date,
                dtype=self._dtype)
        else:
            daycount_fraction = tf.convert_to_tensor(daycount_fraction,
                                                     self._dtype)
        dfstart = self.get_discount_factor(start_date)
        dfmaturity = self.get_discount_factor(maturity_date)
        return (dfstart / dfmaturity - 1.) / daycount_fraction
Exemple #16
0
    def discount_factor(self,
                        interpolation_dates: types.DateTensor,
                        name: Optional[str] = None):
        """Returns discount factors at `interpolation_dates`."""

        interpolation_dates = dateslib.convert_to_date_tensor(
            interpolation_dates)
        times = self._get_time(interpolation_dates)
        if self._interpolate_rates:
            rates = self._interpolator(times, self._times,
                                       self.discount_rate_nodes)
            discount_factor = tf.math.exp(-rates * times)
        else:
            discount_factor = self._interpolator(times, self._times,
                                                 self.discount_factor_nodes)
        return tf.identity(discount_factor, name=name or "discount_factor")
    def __init__(self,
                 market_data_dict: Dict[str, Any],
                 dtype: Optional[tf.DType] = None):
        """Market data constructor.

    The dictionary must follow a format outlined in the doc:
    https://github.com/google/tf-quant-finance/tree/master/tf_quant_finance/experimental/pricing_platform/framework/market_data/market_data.pdf

    Args:
      market_data_dict: Market data dictionary.
      dtype: A `dtype` to use for float-like `Tensor`s.
        Default value: `tf.float64`.
    """
        self._valuation_date = dateslib.convert_to_date_tensor(
            market_data_dict["reference_date"])
        self._market_data_dict = market_data_dict
        self._dtype = dtype or tf.float64
Exemple #18
0
  def __init__(self,
               swap: interest_rate_swap.InterestRateSwap,
               expiry_date: Optional[Union[dateslib.DateTensor,
                                           List[List[int]]]],
               swaption_config: SwaptionConfig,
               batch_names: Optional[tf.Tensor] = None,
               dtype: Optional[types.Dtype] = None,
               name: Optional[str] = None):
    """Initialize a batch of European swaptions.

    Args:
      swap: An instance of `InterestRateSwap` specifying the interest rate
        swaps underlying the swaptions. The batch size of the swaptions being
        created would be the same as the batch size of the `swap`.
      expiry_date: An optional rank 1 `DateTensor` specifying the expiry dates
        for each swaption. The shape of the input should be the same as the
        batch size of the `swap` input.
        Default value: None in which case the option expity date is the same as
        the start date of each underlying swap.
      swaption_config: An input of type `SwaptionConfig` specifying the
        necessary information for swaption valuation.
      batch_names: A string `Tensor` of instrument names. Should be of shape
        `batch_shape + [2]` specying name and instrument type. This is useful
        when the `from_protos` method is used and the user needs to identify
        which instruments got batched together.
      dtype: `tf.Dtype`. If supplied the dtype for the real variables or ops
        either supplied to the Swaption object or created by the Swaption
        object.
        Default value: None which maps to the default dtype inferred by
        TensorFlow.
      name: Python str. The name to give to the ops created by this class.
        Default value: `None` which maps to 'swaption'.
    """
    self._name = name or "swaption"

    with tf.name_scope(self._name):
      if batch_names is not None:
        self._names = tf.convert_to_tensor(batch_names,
                                           name="batch_names")
      else:
        self._names = None
      self._dtype = dtype or tf.float64
      self._expiry_date = dateslib.convert_to_date_tensor(expiry_date)
      self._swap = swap
      self._config = swaption_config
Exemple #19
0
    def discount_rate(self,
                      interpolation_dates: types.DateTensor,
                      name: Optional[str] = None):
        """Returns interpolated rates at `interpolation_dates`."""

        interpolation_dates = dateslib.convert_to_date_tensor(
            interpolation_dates)
        times = self._get_time(interpolation_dates)
        rates = self._interpolator(times, self._times,
                                   self.discount_rate_nodes)
        if self._interpolate_rates:
            rates = self._interpolator(times, self._times,
                                       self.discount_rate_nodes)
        else:
            discount_factor = self._interpolator(times, self._times,
                                                 self.discount_factor_nodes)
            rates = -tf.math.divide_no_nan(tf.math.log(discount_factor), times)
        return tf.identity(rates, name=name or "discount_rate")
  def forward_rates(self,
                    market: pmd.ProcessedMarketData,
                    name: Optional[str] = None
                    ) -> Tuple[types.DateTensor, types.FloatTensor]:
    """Returns forward rates for the floating leg.

    Args:
      market: An instance of `ProcessedMarketData`.
      name: Python str. The name to give to the ops created by this function.
        Default value: `None` which maps to 'forward_rates'.

    Returns:
      A tuple of two `Tensor`s of shape `batch_shape + [num_cashflows]`
      containing the dates and the corresponding forward rates for each stream
      based on the input market data.
    """
    name = name or (self._name + "_forward_rates")
    with tf.name_scope(name):
      reference_curve = get_discount_curve(
          self._reference_curve_type, market, self._reference_mask)
      valuation_date = dateslib.convert_to_date_tensor(market.date)

      past_fixing = _get_fixings(
          self._start_date,
          self._reference_curve_type,
          self._reset_frequency,
          self._reference_mask,
          market)
      forward_rates = reference_curve.forward_rate(
          self._accrual_start_date,
          self._accrual_end_date,
          day_count_fraction=self._daycount_fractions)
      forward_rates = tf.where(self._daycount_fractions > 0., forward_rates,
                               tf.zeros_like(forward_rates))
      # If coupon end date is before the valuation date, the payment is in the
      # past. If valuation date is between coupon start date and coupon end
      # date, then the rate has been fixed but not paid. Otherwise the rate is
      # not fixed and should be read from the curve.
      forward_rates = tf.where(
          self._coupon_end_dates < valuation_date,
          tf.constant(0, dtype=self._dtype),
          tf.where(self._coupon_start_dates >= valuation_date,
                   forward_rates, tf.expand_dims(past_fixing, axis=-1)))
      return  self._coupon_end_dates, forward_rates
    def volatility_surface(
            self, currency: List[str],
            asset: List[str]) -> volatility_surface.VolatilitySurface:
        """The volatility surface object for the lsit of assets.

    Args:
      currency: A list of strings with currency names.
      asset: A list of strings with asset names.

    Returns:
      An instance of `VolatilitySurface`.
    """
        dates = []
        strikes = []
        implied_vols = []
        for cur, s in zip(currency, asset):
            if s not in self.supported_assets(cur):
                raise ValueError(f"No data for asset {s}")
            data_spot = self._market_data_dict["equities"][cur][s]
            if "volatility_surface" not in data_spot:
                raise ValueError(
                    f"No volatility surface 'volatility_surface' for asset {s}"
                )
            vol_surface = data_spot["volatility_surface"]
            vol_dates = dateslib.convert_to_date_tensor(vol_surface["dates"])
            vol_strikes = tf.convert_to_tensor(vol_surface["strikes"],
                                               dtype=self._dtype,
                                               name="strikes")
            vols = tf.convert_to_tensor(vol_surface["implied_volatilities"],
                                        dtype=self._dtype,
                                        name="implied_volatilities")
            dates.append(vol_dates)
            strikes.append(vol_strikes)
            implied_vols.append(vols)
        dates = math.pad.pad_date_tensors(dates)
        dates = dateslib.DateTensor.stack(dates, axis=0)
        implied_vols = math.pad.pad_tensors(implied_vols)
        implied_vols = tf.stack(implied_vols, axis=0)
        strikes = math.pad.pad_tensors(strikes)
        strikes = tf.stack(strikes, axis=0)
        vol_surface = volatility_surface.VolatilitySurface(
            self.date, dates, strikes, implied_vols)
        return vol_surface
    def volatility(self,
                   strike: types.FloatTensor,
                   expiry_dates: Optional[types.DateTensor] = None,
                   expiry_times: Optional[types.FloatTensor] = None,
                   term: Optional[types.Period] = None) -> types.FloatTensor:
        """Returns the interpolated volatility on a specified set of expiries.

    Args:
      strike: The strikes for which the interpolation is desired.
      expiry_dates: Optional input specifying the expiry dates for which
        interpolation is desired. The user should supply either `expiry_dates`
        or `expiry_times` for interpolation.
      expiry_times: Optional real `Tensor` containing the time to expiration
        for which interpolation is desired. The user should supply either
        `expiry_dates` or `expiry_times` for interpolation.
      term: Optional input specifying the term of the underlying rate for
        which the interpolation is desired. Relevant for interest rate implied
        volatility data.

    Returns:
      A `Tensor` of the same shape as `expiry` with the interpolated volatility
      from the volatility surface.

    Raises:
      ValueError is both `expiry_dates` and `expiry_times`  are specified.
    """
        del term
        if expiry_dates is not None and expiry_times is not None:
            raise ValueError(
                "Unexpected inputs: Both expiry_dates and expiry times "
                "are specified")

        if expiry_times is None:
            expiry_dates = dateslib.convert_to_date_tensor(expiry_dates)
            expiries = self._day_count_fn(start_date=self._valuation_date,
                                          end_date=expiry_dates,
                                          dtype=self._dtype)
        else:
            expiries = tf.convert_to_tensor(expiry_times, dtype=self._dtype)
        strike = tf.convert_to_tensor(strike, dtype=self._dtype, name="strike")
        return self._interpolator(expiries, strike)
    def price(self,
              valuation_date,
              market,
              model=None,
              pricing_context=None,
              name=None):
        """Returns the present value of the Cap/Floor on the valuation date.

    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.
      model: An optional input of type `InterestRateModelType` to specify which
        model to use for pricing.
        Default value: `None` in which case `LOGNORMAL_RATE` model is used.
      pricing_context: An optional input to provide additional parameters (such
        as model parameters) relevant for pricing.
      name: Python str. The name to give to the ops created by this function.
        Default value: `None` which maps to `"price"`.

    Returns:
      A Rank 1 `Tensor` of real type containing the modeled price of each cap
      (or floor) based on the input market data.

    Raises:
      ValueError: If an unsupported model is supplied to the function.
    """

        model = model or rc.InterestRateModelType.LOGNORMAL_RATE
        name = name or (self._name + '_price')
        with tf.name_scope(name):
            valuation_date = dates.convert_to_date_tensor(valuation_date)
            if model == rc.InterestRateModelType.LOGNORMAL_RATE:
                caplet_prices = self._price_lognormal_rate(
                    valuation_date, market, pricing_context)
            else:
                raise ValueError(f'Unsupported model {model}.')

            return tf.math.segment_sum(caplet_prices, self._contract_index)
Exemple #24
0
    def __init__(self,
                 valuation_date: types.DateTensor,
                 market_data_dict: Dict[str, Any],
                 config: Optional[Dict[str, Any]] = None,
                 dtype: Optional[tf.DType] = None):
        """Market data constructor.

    The dictionary must follow a format outlined in the doc:
    https://github.com/google/tf-quant-finance/tree/master/tf_quant_finance/experimental/pricing_platform/framework/market_data/market_data.pdf

    Args:
      valuation_date: Valuation date.
      market_data_dict: Market data dictionary.
      config: Market data config. See `market_data_config` module description.
        Used to set up rate curve and volatility surface parameters.
      dtype: A `dtype` to use for float-like `Tensor`s.
        Default value: `tf.float64`.
    """
        self._valuation_date = dateslib.convert_to_date_tensor(valuation_date)
        self._market_data_dict = market_data_dict
        self._config = config
        self._dtype = dtype or tf.float64
Exemple #25
0
  def price(self,
            market: pmd.ProcessedMarketData,
            name: Optional[str] = None):
    """Returns the present value of the swaption on the valuation date.

    Args:
      market: A instance of type `ProcessedMarketData` which contains the
        necessary information for pricing the swaption.
      name: Python str. The name to give to the ops created by this function.
        Default value: `None` which maps to 'price'.

    Returns:
      A Rank `Tensor` of shape `batch_shape` containing the modeled price of
      each  Swaption contract based on the input market data.

    Raises:
      ValueError: If an unsupported model is supplied to the function.
    """
    model = (self._config.model or
             models.InterestRateModelType.HULL_WHITE_ONE_FACTOR)
    name = name or (self._name + "_price")
    with tf.name_scope(name):
      valuation_date = dateslib.convert_to_date_tensor(market.date)
      strike = self._swap.fixed_rate()

      expiry_time = dateslib.daycount_actual_365_fixed(
          start_date=valuation_date,
          end_date=self._expiry_date,
          dtype=self._dtype)

      if model == models.InterestRateModelType.HULL_WHITE_ONE_FACTOR:
        option_value = self._price_hull_white_1_factor(
            valuation_date, market, strike, expiry_time)
      else:
        raise ValueError("Unsupported model.")

      return option_value
    def volatility(self,
                   expiry: types.DateTensor,
                   strike: types.FloatTensor,
                   term: Optional[types.Period] = None) -> types.FloatTensor:
        """Returns the interpolated volatility on a specified set of expiries.

    Args:
      expiry: The expiry dates for which the interpolation is desired.
      strike: The strikes for which the interpolation is desired.
      term: Optional input specifiying the term of the underlying rate for
        which the interpolation is desired. Relevant for interest rate implied
        volatility data.

    Returns:
      A `Tensor` of the same shape as `expiry` with the interpolated volatility
      from the volatility surface.
    """
        del term
        expiry = dateslib.convert_to_date_tensor(expiry)
        expiries = self._day_count_fn(start_date=self._valuation_date,
                                      end_date=expiry,
                                      dtype=self._dtype)
        strike = tf.convert_to_tensor(strike, dtype=self._dtype, name="strike")
        return self._interpolator.interpolate(expiries, strike)
Exemple #27
0
    def __init__(self,
                 contract_start_date,
                 contract_end_date,
                 daycount_convention=None,
                 averaging_type=None,
                 contract_unit=1.,
                 holiday_calendar=None,
                 dtype=None,
                 name=None):
        """Initialize the Overnight index futures object.

    Args:
      contract_start_date: A Rank 1 `DateTensor` specifying the start dates of
        the reference period (or delivery period) of each futures contract. The
        published overnight index during the reference period determines the
        final settlement price of the futures contract.
      contract_end_date: A Rank 1 `DateTensor` specifying the ending dates of
        the reference period (or delivery period) of each futures contract.
      daycount_convention: An optional scalar `DayCountConvention` corresponding
        to the day count convention for the underlying rate for each contract.
        Default value: None in which case each the day count convention equal to
        DayCountConvention.ACTUAL_360 is used.
      averaging_type: An optional `AverageType` corresponding to how the
        final settlement rate is computed from daily rates.
        Default value: None, in which case `AverageType.COMPOUNDING` is used.
      contract_unit: An optional scalar or Rank 1 `Tensor` of real dtype
        specifying the notional amount for the contract. If the notional is
        entered as a scalar, it is assumed that all of the contracts have a
        notional equal to the input value.
        Default value: 1.0
      holiday_calendar: An instance of `dates.HolidayCalenday` to specify
        weekends and holidays.
        Default value: None in which case a holiday calendar would be created
        with Saturday and Sunday being the holidays.
      dtype: `tf.Dtype`. If supplied the dtype for the real variables or ops
        either supplied to the EurodollarFuture object or created by the
        EurodollarFuture object.
        Default value: None which maps to the default dtype inferred by
        TensorFlow.
      name: Python str. The name to give to the ops created by this class.
        Default value: `None` which maps to 'eurodollar_future'.
    """
        self._name = name or 'overnight_rate_futures'

        with tf.compat.v2.name_scope(self._name):
            self._contract_unit = tf.convert_to_tensor(contract_unit,
                                                       dtype=dtype)
            self._dtype = dtype if dtype else self._contract_unit.dtype
            self._start_date = dates.convert_to_date_tensor(
                contract_start_date)
            self._end_date = dates.convert_to_date_tensor(contract_end_date)
            self._batch_size = self._start_date.shape[0]

            if daycount_convention is None:
                daycount_convention = rc.DayCountConvention.ACTUAL_360

            if averaging_type is None:
                averaging_type = rc.AverageType.COMPOUNDING

            if holiday_calendar is None:
                holiday_calendar = dates.create_holiday_calendar(
                    weekend_mask=dates.WeekendMask.SATURDAY_SUNDAY)

            self._daycount_convention = daycount_convention
            self._averaging_type = averaging_type
            self._holiday_calendar = holiday_calendar
            self._rate_tenor = dates.day()

            self._setup()
Exemple #28
0
    def __init__(self,
                 start_date: Union[dateslib.DateTensor, List[List[int]]],
                 maturity_date: Union[dateslib.DateTensor, List[List[int]]],
                 pay_leg: Union[coupon_specs.FixedCouponSpecs,
                                coupon_specs.FloatCouponSpecs],
                 receive_leg: Union[coupon_specs.FixedCouponSpecs,
                                    coupon_specs.FloatCouponSpecs],
                 pay_leg_schedule_fn=None,
                 pay_leg_schedule=None,
                 receive_leg_schedule_fn=None,
                 receive_leg_schedule=None,
                 config: Union[InterestRateSwapConfig, Dict[str, Any]] = None,
                 batch_names: Optional[tf.Tensor] = None,
                 dtype: Optional[types.Dtype] = None,
                 name: Optional[str] = None):
        """Initializes a batch of IRS contracts.

    Args:
      start_date: A `DateTensor` of `batch_shape` specifying the dates for the
        inception (start of the accrual) of the swap contracts. `batch_shape`
        corresponds to the number of instruments being created.
      maturity_date: A `DateTensor` broadcastable with `start_date` specifying
        the maturity dates for each contract.
      pay_leg: An instance of `FixedCouponSpecs` or `FloatCouponSpecs`
        specifying the coupon payments for the payment leg of the swap.
      receive_leg: An instance of `FixedCouponSpecs` or `FloatCouponSpecs`
        specifying the coupon payments for the receiving leg of the swap.
      pay_leg_schedule_fn:  A callable that accepts `start_date`, `end_date`,
        `coupon_frequency`, `settlement_days`, `first_coupon_date`, and
        `penultimate_coupon_date` as `Tensor`s and returns coupon payment
        days. Constructs schedule for the pay leg of the swap.
        Default value: `None`.
      pay_leg_schedule: A `DateTensor` of coupon payment dates for the pay leg.
      receive_leg_schedule_fn:  A callable that accepts `start_date`,
        `end_date`, `coupon_frequency`, `settlement_days`, `first_coupon_date`,
        and `penultimate_coupon_date` as `Tensor`s and returns coupon payment
        days. Constructs schedule for the receive leg of the swap.
        Default value: `None`.
      receive_leg_schedule: A `DateTensor` of coupon payment dates for the
        receive leg.
      config: Optional `InterestRateSwapConfig` or a dictionary.
        If dictionary, then the keys should be the same as the field names of
        `InterestRateSwapConfig`.
      batch_names: A string `Tensor` of instrument names. Should be of shape
        `batch_shape + [2]` specying name and instrument type. This is useful
        when the `from_protos` method is used and the user needs to identify
        which instruments got batched together.
      dtype: `tf.Dtype` of the input and output real `Tensor`s.
        Default value: None which maps to the default dtype inferred by
        TensorFlow.
      name: Python str. The name to give to the ops created by this class.
        Default value: `None` which maps to 'interest_rate_swap'.
    """
        self._name = name or "interest_rate_swap"

        with tf.name_scope(self._name):
            if batch_names is not None:
                self._names = tf.convert_to_tensor(batch_names,
                                                   name="batch_names")
            else:
                self._names = None
            self._dtype = dtype or tf.float64
            self._model = None  # Ignore

            self._config = _process_config(config)
            if isinstance(pay_leg, dict):
                self._discount_curve_type = pay_leg["discount_curve_type"]
                self._start_date = start_date
            else:
                currencies = cashflow_streams.to_list(pay_leg.currency)
                self._discount_curve_type = []
                if pay_leg.currency != receive_leg.currency:
                    raise ValueError(
                        "Pay and receive legs should have the same currency")
                for currency in currencies:
                    if currency in self._config.discounting_curve:
                        discount_curve = self._config.discounting_curve[
                            currency]
                        self._discount_curve_type.append(discount_curve)
                    else:
                        # Default discounting is the risk free curve
                        risk_free = curve_types_lib.RiskFreeCurve(
                            currency=currency)
                        self._discount_curve_type.append(risk_free)
            if isinstance(start_date, tf.Tensor):
                self._start_date = dateslib.dates_from_tensor(start_date)
            else:
                self._start_date = dateslib.convert_to_date_tensor(start_date)
            if isinstance(start_date, tf.Tensor):
                self._maturity_date = dateslib.dates_from_tensor(maturity_date)
            else:
                self._maturity_date = dateslib.convert_to_date_tensor(
                    maturity_date)
            self._pay_leg_schedule_fn = pay_leg_schedule_fn
            self._receive_leg_schedule_fn = receive_leg_schedule_fn
            self._pay_leg_schedule = pay_leg_schedule
            self._receive_leg_schedule = receive_leg_schedule
            self._pay_leg = _setup_leg(self._start_date, self._maturity_date,
                                       self._discount_curve_type, pay_leg,
                                       self._pay_leg_schedule_fn,
                                       self._pay_leg_schedule)
            self._receive_leg = _setup_leg(self._start_date,
                                           self._maturity_date,
                                           self._discount_curve_type,
                                           receive_leg,
                                           self._receive_leg_schedule_fn,
                                           self._receive_leg_schedule)
            self._batch_shape = self._pay_leg.batch_shape
    def __init__(self,
                 start_date: Union[dateslib.DateTensor, List[List[int]]],
                 maturity_date: Union[dateslib.DateTensor, List[List[int]]],
                 pay_leg: Union[coupon_specs.FixedCouponSpecs,
                                coupon_specs.FloatCouponSpecs],
                 receive_leg: Union[coupon_specs.FixedCouponSpecs,
                                    coupon_specs.FloatCouponSpecs],
                 swap_config: InterestRateSwapConfig = None,
                 batch_names: Optional[tf.Tensor] = None,
                 dtype: Optional[types.Dtype] = None,
                 name: Optional[str] = None):
        """Initializes a batch of IRS contracts.

    Args:
      start_date: A `DateTensor` of `batch_shape` specifying the dates for the
        inception (start of the accrual) of the swap contracts. `batch_shape`
        corresponds to the number of instruments being created.
      maturity_date: A `DateTensor` broadcastable with `start_date` specifying
        the maturity dates for each contract.
      pay_leg: An instance of `FixedCouponSpecs` or `FloatCouponSpecs`
        specifying the coupon payments for the payment leg of the swap.
      receive_leg: An instance of `FixedCouponSpecs` or `FloatCouponSpecs`
        specifying the coupon payments for the receiving leg of the swap.
      swap_config: Optional `InterestRateSwapConfig`.
      batch_names: A string `Tensor` of instrument names. Should be of shape
        `batch_shape + [2]` specying name and instrument type. This is useful
        when the `from_protos` method is used and the user needs to identify
        which instruments got batched together.
      dtype: `tf.Dtype` of the input and output real `Tensor`s.
        Default value: None which maps to the default dtype inferred by
        TensorFlow.
      name: Python str. The name to give to the ops created by this class.
        Default value: `None` which maps to 'interest_rate_swap'.
    """
        self._name = name or "interest_rate_swap"

        with tf.name_scope(self._name):
            if batch_names is not None:
                self._names = tf.convert_to_tensor(batch_names,
                                                   name="batch_names")
            else:
                self._names = None
            self._dtype = dtype or tf.float64
            self._model = None  # Ignore

            currency = pay_leg.currency
            if pay_leg.currency != receive_leg.currency:
                raise ValueError(
                    "Pay and receive legs should have the same currency")
            if swap_config is not None:
                try:
                    self._discount_curve_type = swap_config.discounting_index[
                        currency]
                except KeyError:
                    self._discount_curve_type = curve_types.CurveType(
                        currency=currency, index_type=curve_types.Index.OIS)
            else:
                self._discount_curve_type = curve_types.CurveType(
                    currency=currency, index_type=curve_types.Index.OIS)
            self._start_date = dateslib.convert_to_date_tensor(start_date)
            self._maturity_date = dateslib.convert_to_date_tensor(
                maturity_date)
            self._pay_leg = self._setup_leg(pay_leg)
            self._receive_leg = self._setup_leg(receive_leg)
            if self._receive_leg.batch_shape != self._pay_leg.batch_shape:
                raise ValueError(
                    "Batch shapes of pay and receive legs should be the "
                    "same.")
            self._batch_shape = self._pay_leg.batch_shape
    def get_discount_factor(self, interpolation_dates):
        """Returns discount factors at `interpolation_dates`."""

        idates = dates.convert_to_date_tensor(interpolation_dates)
        times = self._get_time(idates)
        return tf.math.exp(-self.get_rates(idates) * times)