Ejemplo n.º 1
0
def actual_365_actual(*,
                      start_date,
                      end_date,
                      schedule_info=None,
                      dtype=None,
                      name=None):
  """Computes the year fraction between the specified dates.

  The actual/365 actual convention specifies the year fraction between the
  start and end date as the actual number of days between the two dates divided
  365 if no leap day is contained in the date range and 366 otherwise.

  When determining whether a leap day is contained in the date range,
  'start_date' is excluded and 'end_date' is included.

  Note that the schedule info is not needed for this convention and is ignored
  if supplied.

  Args:
    start_date: A `DateTensor` object of any shape.
    end_date: A `DateTensor` object of compatible shape with `start_date`.
    schedule_info: The schedule info. Ignored for this convention.
    dtype: The dtype of the result. Either `tf.float32` or `tf.float64`. If not
      supplied, `tf.float32` is returned.
    name: Python `str` name prefixed to ops created by this function. If not
      supplied, `actual_365_actual` is used.

  Returns:
    A real `Tensor` of supplied `dtype` and shape of `start_date`. The year
    fraction between the start and end date as computed by Actual/365 Actual
    convention.
  """
  del schedule_info
  with tf.name_scope(name or 'actual_365_actual'):
    end_date = dt.convert_to_date_tensor(end_date)
    start_date = dt.convert_to_date_tensor(start_date)
    dtype = dtype or tf.constant(0.).dtype
    actual_days = tf.cast(start_date.days_until(end_date), dtype=dtype)
    # Add a day to start_date and end_date so that start_date is excluded and
    # end_date is included.
    day = periods.day()
    leap_days_between = du.leap_days_between(
        start_date=start_date + day, end_date=end_date + day)
    denominator = tf.cast(tf.where(leap_days_between > 0, 366, 365),
                          dtype=dtype)
    return actual_days / denominator
Ejemplo n.º 2
0
def actual_365_fixed(*,
                     start_date,
                     end_date,
                     schedule_info=None,
                     dtype=None,
                     name=None):
  """Computes the year fraction between the specified dates.

  The actual/365 convention specifies the year fraction between the start and
  end date as the actual number of days between the two dates divided by 365.

  Note that the schedule info is not needed for this convention and is ignored
  if supplied.

  For more details see:
  https://en.wikipedia.org/wiki/Day_count_convention#Actual/365_Fixed

  Args:
    start_date: A `DateTensor` object of any shape.
    end_date: A `DateTensor` object of compatible shape with `start_date`.
    schedule_info: The schedule info. Ignored for this convention.
    dtype: The dtype of the result. Either `tf.float32` or `tf.float64`. If not
      supplied, `tf.float32` is returned.
    name: Python `str` name prefixed to ops created by this function. If not
      supplied, `actual_365_fixed` is used.

  Returns:
    A real `Tensor` of supplied `dtype` and shape of `start_date`. The year
    fraction between the start and end date as computed by Actual/365 fixed
    convention.
  """
  del schedule_info
  with tf.name_scope(name or 'actual_365_fixed'):
    end_date = dt.convert_to_date_tensor(end_date)
    start_date = dt.convert_to_date_tensor(start_date)
    dtype = dtype or tf.constant(0.).dtype
    actual_days = tf.cast(start_date.days_until(end_date), dtype=dtype)
    return actual_days / 365
Ejemplo n.º 3
0
    def business_days_between(self, from_dates, to_dates):
        """Calculates number of business between pairs of dates.

    For each pair, the initial date is included in the difference, and the final
    date is excluded. If the final date is the same or earlier than the initial
    date, zero is returned.

    Args:
      from_dates: `DateTensor` of initial dates.
      to_dates: `DateTensor` of final dates, should be broadcastable to
        `from_dates`.

    Returns:
       An int32 Tensor with the number of business days between the
       corresponding pairs of dates.
    """
        from_biz, from_is_bizday = self._to_biz_space(
            dt.convert_to_date_tensor(from_dates).ordinal())
        to_biz, to_is_bizday = self._to_biz_space(
            dt.convert_to_date_tensor(to_dates).ordinal())
        from_biz = tf.where(from_is_bizday, from_biz, from_biz + 1)
        to_biz = tf.where(to_is_bizday, to_biz, to_biz + 1)
        return tf.math.maximum(to_biz - from_biz, 0)
Ejemplo n.º 4
0
  def __init__(
      self,
      weekend_mask=None,
      holidays=None,
      start_year=None,
      end_year=None):
    """Initializer.

    Args:
      weekend_mask: Tensor of 7 elements, where "0" means work day and "1" -
        day off. The first element is Monday. By default, no weekends are
        applied. Some of the common weekend patterns are defined in
        `dates.WeekendMask`.
        Default value: None which maps to no weekend days.
      holidays: Defines the holidays that are added to the weekends defined by
      `weekend_mask`. An instance of `dates.DateTensor` or an object
       convertible to `DateTensor`.
       Default value: None which means no holidays other than those implied by
       the weekends (if any).
      start_year: Integer giving the earliest year this calendar includes. If
        `holidays` is specified, then `start_year` and `end_year` are ignored,
        and the boundaries are derived from `holidays`. If `holidays` is `None`,
        both `start_year` and `end_year` must be specified.
      end_year: Integer giving the latest year this calendar includes. If
        `holidays` is specified, then `start_year` and `end_year` are ignored,
        and the boundaries are derived from `holidays`. If `holidays` is `None`,
        both `start_year` and `end_year` must be specified.
    """
    self._weekend_mask = tf.convert_to_tensor(weekend_mask or
                                              constants.WeekendMask.NONE)
    if holidays is None:
      self._holidays = None
    else:
      self._holidays = dt.convert_to_date_tensor(holidays)
    start_year, end_year = _resolve_calendar_boundaries(self._holidays,
                                                        start_year, end_year)
    self._ordinal_offset = dt.from_year_month_day(start_year, 1, 1).ordinal()
    self._calendar_size = (
        dt.from_year_month_day(end_year + 1, 1, 1).ordinal() -
        self._ordinal_offset)

    # Precomputed tables. These are constant 1D Tensors, mapping each day in the
    # [start_year, end_year] period to some quantity of interest, e.g. next
    # business day. The tables should be indexed with
    # `date.ordinal - self._offset`. All tables are computed lazily.
    # All tables have an extra element at the beginning and the end, see comment
    # in _compute_is_bus_day_table().
    self._table_cache = _TableCache()
  def roll_to_business_day(self, date_tensor, roll_convention):
    """Rolls the given dates to business dates according to given convention.

    Args:
      date_tensor: `DateTensor` of dates to roll from.
      roll_convention: BusinessDayConvention. Determines how to roll a date that
        falls on a holiday.

    Returns:
      The resulting `DateTensor`.
    """
    if roll_convention == constants.BusinessDayConvention.NONE:
      return date_tensor
    ordinals = dt.convert_to_date_tensor(date_tensor).ordinal()
    biz_days, is_bizday = self._to_biz_space(ordinals)
    biz_days_rolled = self._apply_roll_biz_space(date_tensor, biz_days,
                                                 is_bizday, roll_convention)
    return dt.from_ordinals(self._from_biz_space(biz_days_rolled))
Ejemplo n.º 6
0
    def add_business_days(
            self,
            date_tensor,
            num_days,
            roll_convention=constants.BusinessDayConvention.NONE):
        """Adds given number of business days to given dates.

    Note that this is different from calling `add_period_and_roll` with
    PeriodType.DAY. For example, adding 5 business days to Monday gives the next
    Monday (unless there are holidays on this week or next Monday). Adding 5
    days and rolling means landing on Saturday and then rolling either to next
    Monday or to Friday of the same week, depending on the roll convention.

    If any of the dates in `date_tensor` are not business days, they will be
    rolled to business days before doing the addition. If `roll_convention` is
    `NONE`, and any dates are not business days, an exception is raised.

    Args:
      date_tensor: `DateTensor` of dates to advance from.
      num_days: Tensor of int32 type broadcastable to `date_tensor`.
      roll_convention: BusinessDayConvention. Determines how to roll a date that
        falls on a holiday.

    Returns:
      The resulting `DateTensor`.
    """
        control_deps = []
        biz_days, is_bizday = self._to_biz_space(
            dt.convert_to_date_tensor(date_tensor).ordinal())
        if roll_convention == constants.BusinessDayConvention.NONE:
            control_deps.append(
                tf.debugging.assert_equal(
                    is_bizday,
                    True,
                    message='Non business starting day with no roll convention.'
                ))

        with tf.compat.v1.control_dependencies(control_deps):
            biz_days_rolled = self._apply_roll_biz_space(
                date_tensor, biz_days, is_bizday, roll_convention)
            return dt.from_ordinals(
                self._from_biz_space(biz_days_rolled + num_days))
Ejemplo n.º 7
0
    def __init__(self, weekend_mask=None, holidays=None):
        """Initializer.

    Args:
      weekend_mask: Boolean `Tensor` of 7 elements one for each day of the week
        starting with Monday at index 0. A `True` value indicates the day is
        considered a weekend day and a `False` value implies a week day.
        Default value: None which means no weekends are applied.
      holidays: Defines the holidays that are added to the weekends defined by
        `weekend_mask`. An instance of `dates.DateTensor` or an object
        convertible to `DateTensor`.
        Default value: None which means no holidays other than those implied by
          the weekends (if any).
    """
        if weekend_mask is not None:
            weekend_mask = tf.cast(weekend_mask, dtype=tf.bool)
        if holidays is not None:
            holidays = dt.convert_to_date_tensor(holidays).ordinal()
        self._to_biz_space, self._from_biz_space = hol.business_day_mappers(
            weekend_mask=weekend_mask, holidays=holidays)
Ejemplo n.º 8
0
 def is_business_day(self, date_tensor):
     """Returns a tensor of bools for whether given dates are business days."""
     ordinals = dt.convert_to_date_tensor(date_tensor).ordinal()
     return self._to_biz_space(ordinals)[1]