def get_discount_curve(discount_curve_types: List[
    Union[curve_types_lib.RiskFreeCurve,
          curve_types_lib.RateIndexCurve]], market: pmd.ProcessedMarketData,
                       mask: List[int]) -> rate_curve.RateCurve:
    """Builds a batched discount curve.

  Given a list of discount curve an integer mask, creates a discount curve
  object to compute discount factors against the list of discount curves.

  #### Example
  ```none
  curve_types = [RiskFreeCurve("USD"), RiskFreeCurve("AUD")]
  # A mask to price a batch of 7 instruments with the corresponding discount
  # curves ["USD", "AUD", "AUD", "AUD" "USD", "USD", "AUD"].
  mask = [0, 1, 1, 1, 0, 0, 1]
  market = MarketDataDict(...)
  get_discount_curve(curve_types, market, mask)
  # Returns a RateCurve object that can compute a discount factors for a
  # batch of 7 dates.
  ```

  Args:
    discount_curve_types: A list of curve types.
    market: an instance of the processed market data.
    mask: An integer mask.

  Returns:
    An instance of `RateCurve`.
  """
    discount_curves = [
        market.yield_curve(curve_type) for curve_type in discount_curve_types
    ]
    discounts = []
    dates = []
    interpolation_method = None
    interpolate_rates = None
    for curve in discount_curves:
        discount, date = curve.discount_factors_and_dates()
        discounts.append(discount)
        dates.append(date)
        interpolation_method = curve.interpolation_method
        interpolate_rates = curve.interpolate_rates

    all_discounts = tf.stack(pad.pad_tensors(discounts), axis=0)
    all_dates = pad.pad_date_tensors(dates)
    all_dates = dateslib.DateTensor.stack(dates, axis=0)
    prepare_discounts = tf.gather(all_discounts, mask)
    prepare_dates = dateslib.dates_from_ordinals(
        tf.gather(all_dates.ordinal(), mask))
    # All curves are assumed to have the same interpolation method
    # TODO(b/168411153): Extend to the case with multiple curve configs.
    discount_curve = rate_curve.RateCurve(prepare_dates,
                                          prepare_discounts,
                                          market.date,
                                          interpolator=interpolation_method,
                                          interpolate_rates=interpolate_rates)
    return discount_curve
def _get_fixings(start_dates, end_dates, reference_curve_types, reference_mask,
                 market):
    """Computes fixings for a list of reference curves."""
    num_curves = len(reference_curve_types)
    if num_curves > 1:
        # For each curve get corresponding cashflow indices
        split_indices = [
            tf.squeeze(tf.where(tf.equal(reference_mask, i)), -1)
            for i in range(num_curves)
        ]
    else:
        split_indices = [0]
    fixings = []
    start_dates_ordinal = start_dates.ordinal()
    end_dates_ordinal = end_dates.ordinal()
    for idx, reference_curve_type in zip(split_indices, reference_curve_types):
        if num_curves > 1:
            # Get all dates corresponding to the reference curve
            start_date = dateslib.dates_from_ordinals(
                tf.gather(start_dates_ordinal, idx))
            end_date = dateslib.dates_from_ordinals(
                tf.gather(end_dates_ordinal, idx))
        else:
            start_date = start_dates
            end_date = end_dates
        fixing, fixing_daycount = market.fixings(start_date,
                                                 reference_curve_type)
        if fixing_daycount is not None:
            fixing_daycount = market_data_utils.get_daycount_fn(
                fixing_daycount, dtype=market.dtype)
            year_fraction = fixing_daycount(start_date=start_date,
                                            end_date=end_date)
        else:
            year_fraction = 0.0
        fixings.append(fixing * year_fraction)
    fixings = pad.pad_tensors(fixings)
    all_indices = tf.concat(split_indices, axis=0)
    all_fixings = tf.concat(fixings, axis=0)
    if num_curves > 1:
        return tf.gather(all_fixings, tf.argsort(all_indices))
    else:
        return all_fixings
Ejemplo n.º 3
0
def get_vol_surface(equity_types: List[str], market: pmd.ProcessedMarketData,
                    mask: List[int]) -> volatility_surface.VolatilitySurface:
    """Builds a batched volatility surface.

  Given a list of discount curve an integer mask, creates a discount curve
  object to compute discount factors against the list of discount curves.

  #### Example
  ```none
  curve_types = ["GOOG", "MSFT"]
  # A mask to price a batch of 7 instruments with the corresponding discount
  # curves ["GOOG", "MSFT", "MSFT", "MSFT" "GOOG", "GOOG"].
  mask = [0, 1, 1, 1, 0, 0]
  market = MarketDataDict(...)
  get_vol_surface(curve_types, market, mask)
  # Returns a VolatilitySurface object that can compute a volatilities for a
  # batch of 6 expiry dates and strikes.
  ```

  Args:
    equity_types: A list of equity types.
    market: An instance of the processed market data.
    mask: An integer mask.

  Returns:
    An instance of `VolatilitySurface`.
  """
    vols = market.volatility_surface(equity_types)
    expiries = vols.node_expiries().ordinal()
    strikes = vols.node_strikes()
    volatilities = vols.node_volatilities()
    prepare_strikes = tf.gather(strikes, mask)
    prepare_vols = tf.gather(volatilities, mask)
    prepare_expiries = dateslib.dates_from_ordinals(tf.gather(expiries, mask))
    # All curves are assumed to have the same interpolation method
    # TODO(b/168411153): Extend to the case with multiple curve configs.
    vol_surface = volatility_surface.VolatilitySurface(
        valuation_date=market.date,
        expiries=prepare_expiries,
        strikes=prepare_strikes,
        volatilities=prepare_vols,
        daycount_convention=vols.daycount_convention)
    return vol_surface
Ejemplo n.º 4
0
def _get_fixings(start_dates, reference_curve_types, reset_frequencies,
                 reference_mask, market):
    """Computes fixings for a list of reference curves."""
    split_indices = [
        tf.squeeze(tf.where(tf.equal(reference_mask, i)), -1)
        for i in range(len(reference_curve_types))
    ]
    fixings = []
    for idx, reference_curve_type in zip(split_indices, reference_curve_types):
        start_date = dateslib.dates_from_ordinals(
            tf.gather(start_dates.ordinal(), idx))
        reset_quant = reset_frequencies.quantity()
        # Do not use gather, if only one reset frequency is supplied
        if reset_quant.shape.rank > 1:
            reset_quant = tf.gather(reset_quant, idx)
        fixings.append(
            market.fixings(start_date, reference_curve_type, reset_quant))
    fixings = pad.pad_tensors(fixings)
    all_indices = tf.concat(split_indices, axis=0)
    all_fixings = tf.concat(fixings, axis=0)
    return tf.gather(all_fixings, tf.argsort(all_indices))
    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)

            # Previous fixing date
            coupon_start_date_ord = self._coupon_start_dates.ordinal()
            coupon_end_date_ord = self._coupon_end_dates.ordinal()
            valuation_date_ord = valuation_date.ordinal()
            batch_shape = tf.shape(coupon_start_date_ord)[:-1]
            # Broadcast valuation date batch shape for tf.searchsorted
            valuation_date_ord += tf.expand_dims(tf.zeros(batch_shape,
                                                          dtype=tf.int32),
                                                 axis=-1)
            ind = tf.maximum(
                tf.searchsorted(coupon_start_date_ord, valuation_date_ord) - 1,
                0)
            # Fixings are assumed to be the same as coupon start dates
            # TODO(b/177047910): add fixing settlement dates.
            # Shape `batch_shape + [1]`
            fixing_dates_ord = tf.gather(
                coupon_start_date_ord,
                ind,
                batch_dims=len(coupon_start_date_ord.shape) - 1)
            fixing_end_dates_ord = tf.gather(
                coupon_end_date_ord,
                ind,
                batch_dims=len(coupon_start_date_ord.shape) - 1)
            fixing_dates = dateslib.dates_from_ordinals(fixing_dates_ord)
            fixing_end_dates = dateslib.dates_from_ordinals(
                fixing_end_dates_ord)
            # Get fixings. Shape batch_shape + [1]
            past_fixing = _get_fixings(fixing_dates, fixing_end_dates,
                                       self._reference_curve_type,
                                       self._reference_mask, market)
            forward_rates = reference_curve.forward_rate(
                self._accrual_start_date,
                self._accrual_end_date,
                day_count_fraction=self._daycount_fractions)
            # Shape batch_shape + [num_cashflows]
            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.
            # Shape batch_shape + [num_cashflows]
            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, past_fixing))
            return self._coupon_end_dates, forward_rates