def _setup_tensors(self): """Sets up tensors for efficient computations.""" date_schedule = dates.PeriodicSchedule( start_date=self._start_date, end_date=self._maturity_date, tenor=self._reset_frequency).dates() # rates reset at the begining of coupon period reset_dates = date_schedule[:, :-1] # payments occur at the end of the coupon period payment_dates = date_schedule[:, 1:] daycount_fractions = rc.get_daycount_fraction( date_schedule[:, :-1], date_schedule[:, 1:], self._daycount_convention, dtype=self._dtype) contract_index = tf.repeat( tf.range(0, self._batch_size), payment_dates.shape.as_list()[-1]) self._num_caplets = daycount_fractions.shape.as_list()[-1] # TODO(b/152164086): Use the functionality from dates library self._rate_term = tf.repeat(tf.cast(reset_dates[:, 0].days_until( payment_dates[:, 0]), dtype=self._dtype) / 365.0, self._num_caplets) self._reset_dates = dates.DateTensor.reshape(reset_dates, [-1]) self._payment_dates = dates.DateTensor.reshape(payment_dates, [-1]) self._accrual_start_dates = dates.DateTensor.reshape(reset_dates, [-1]) self._accrual_end_dates = dates.DateTensor.reshape(payment_dates, [-1]) self._daycount_fractions = tf.reshape(daycount_fractions, [-1]) self._contract_index = contract_index self._strike = tf.repeat(self._strike, self._num_caplets) self._is_cap = tf.repeat(self._is_cap, self._num_caplets)
def _setup(self): """Setup relevant tensors for efficient computations.""" reset_dates = [] contract_idx = [] daycount_fractions = [] for i in range(self._batch_size): instr_reset_dates = dates.PeriodicSchedule( start_date=self._start_date[i] + self._rate_tenor, end_date=self._end_date[i], tenor=self._rate_tenor, holiday_calendar=self._holiday_calendar, roll_convention=dates.BusinessDayConvention.FOLLOWING).dates() # Append the start_date of the contract instr_reset_dates = dates.DateTensor.concat( [self._start_date[i].expand_dims(axis=0), instr_reset_dates], axis=0) # Add one day beyond the end of the delivery period to compute the # accrual on the last day of the delivery. one_period_past_enddate = self._end_date[i] + self._rate_tenor instr_reset_dates = dates.DateTensor.concat([ instr_reset_dates, one_period_past_enddate.expand_dims(axis=0) ], axis=0) instr_daycount_fractions = rc.get_daycount_fraction( instr_reset_dates[:-1], instr_reset_dates[1:], self._daycount_convention, self._dtype) reset_dates.append(instr_reset_dates[:-1]) daycount_fractions.append(instr_daycount_fractions) contract_idx.append(tf.fill(tf.shape(instr_daycount_fractions), i)) self._reset_dates = dates.DateTensor.concat(reset_dates, axis=0) self._accrual_start_dates = self._reset_dates self._accrual_end_dates = self._reset_dates + self._rate_tenor self._accrual_daycount = rc.get_daycount_fraction( self._accrual_start_dates, self._accrual_end_dates, self._daycount_convention, self._dtype) self._daycount_fractions = tf.concat(daycount_fractions, axis=0) self._contract_idx = tf.concat(contract_idx, axis=0)
def _generate_schedule( start_date: dateslib.DateTensor, end_date: dateslib.DateTensor, coupon_frequency: dateslib.PeriodTensor, calendar: dateslib.HolidayCalendar, roll_convention: dateslib.BusinessDayConvention, settlement_days: tf.Tensor, end_of_month: bool = False, first_coupon_date: Optional[dateslib.DateTensor] = None, penultimate_coupon_date: Optional[dateslib.DateTensor] = None) -> tf.Tensor: """Method to generate coupon dates. Args: start_date: Starting dates of schedule. end_date: End dates of the schedule. coupon_frequency: A `PeriodTensor` specifying the frequency of coupon payments. calendar: calendar: An instance of `BankHolidays`. roll_convention: Business day roll convention of the schedule. settlement_days: An integer `Tensor` with the shape compatible with `start_date` and `end_date` specifying the number of settlement days. end_of_month: Python `bool`. If `True`, shifts all dates in schedule to the ends of corresponding months, if `start_date` or `end_date` ( depending on `backward`) is at the end of a month. The shift is applied before applying `roll_convention`. first_coupon_date: First day of the irregular coupon, if any. penultimate_coupon_date: Penultimate day of the coupon, if any. Returns: A `DateTensor` containing the generated date schedule of shape `batch_shape + [max_num_coupon_days]`, where `max_num_coupon_days` is the number of coupon days for the longest living swap in the batch. The coupon days for the rest of the swaps are padded with their final coupon day. """ if first_coupon_date is not None and penultimate_coupon_date is not None: raise ValueError("Only first or last coupon dates can be specified " " for an irregular coupon.") start_date = first_coupon_date or start_date # Adjust with settlement days start_date = calendar.add_business_days( start_date, settlement_days, roll_convention=roll_convention) if penultimate_coupon_date is None: backward = False else: backward = True end_date = end_date or penultimate_coupon_date # Adjust with settlement days end_date = calendar.add_business_days( end_date, settlement_days, roll_convention=roll_convention) coupon_dates = dateslib.PeriodicSchedule( start_date=start_date, end_date=end_date, tenor=coupon_frequency, roll_convention=roll_convention, backward=backward, end_of_month=end_of_month).dates() # Add the regular coupons coupon_dates = dateslib.DateTensor.concat( [start_date.expand_dims(-1), coupon_dates, end_date.expand_dims(-1)], axis=-1) return coupon_dates
def _generate_schedule(self, cpn_frequency, roll_convention): """Method to generate coupon dates. Args: cpn_frequency: A `PeriodTensor` specifying the frequency of coupon payments. roll_convention: Scalar of type `BusinessDayConvention` specifying how dates are rolled if they fall on holidays. Returns: A tuple containing the generated date schedule and a boolean `Tensor` of the same shape as the schedule specifying whether the coupons are regular coupons. """ if (self._first_coupon_date is None) and (self._penultimate_coupon_date is None): cpn_dates = dates.PeriodicSchedule( start_date=self._start_date, end_date=self._end_date, tenor=cpn_frequency, roll_convention=roll_convention).dates() is_regular_cpn = tf.constant(True, dtype=bool, shape=cpn_dates[:, :-1].shape) elif self._first_coupon_date is not None: cpn_dates = dates.PeriodicSchedule( start_date=self._first_coupon_date, end_date=self._end_date, tenor=cpn_frequency, roll_convention=roll_convention).dates() cpn_dates = dates.DateTensor.concat( [self._start_date.expand_dims(-1), cpn_dates], axis=1) is_irregular_cpn = tf.constant(False, dtype=bool, shape=self._start_date.shape) is_regular_cpn = tf.concat([ tf.expand_dims(is_irregular_cpn, axis=-1), tf.constant(True, dtype=bool, shape=cpn_dates[:, :-2].shape) ], axis=1) else: cpn_dates = dates.PeriodicSchedule( start_date=self._start_date, end_date=self._penultimate_coupon_date, backward=True, tenor=cpn_frequency, roll_convention=roll_convention).dates() cpn_dates = dates.DateTensor.concat( [cpn_dates, self._end_date.expand_dims(-1)], axis=1) is_irregular_cpn = tf.constant(False, dtype=bool, shape=self._end_date.shape) is_regular_cpn = tf.concat([ tf.constant(True, dtype=bool, shape=cpn_dates[:, :-2].shape), tf.expand_dims(is_irregular_cpn, axis=-1) ], axis=1) return cpn_dates, is_regular_cpn