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
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
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