Пример #1
0
def rolldate(dt, calendar, convention):
    """ Roll date to the business day

    Roll date of the date to the business day according to the convention.
    For 'follow' convention, if date falls on a holiday, finds first working day after it
    For 'previous' convention, if date falls on a holiday, finds latest working day before it
    For 'modfollow' convention, if date falls on a holiday, finds first working day after it, unless date is the end of month in which case previous workday is found
    For 'previous' convention, if date falls on a holiday, finds latest working day before it, unless date is the beginning of month in which case following workday is found

    Parameters
    ----------
    dt: datetime.date, datetime.datetime or date string
    calendar: Calendar object that has is_holiday method
    convention: one of 'follow', 'previous', 'modfollow', 'modprevious'

    Returns
    -------
    datetime.datetime of the next business day according to the convention
    """
    convention = convention.lower()
    dt = dateutils.asdatetime(dt)
    rolled = dt
    if convention == "follow":
        rolled = _roll_forward(dt, calendar)
    elif convention == 'modfollow':
        rolled = _roll_forward(dt, calendar)
        if rolled.month > dt.month:
            rolled = _roll_backward(dt, calendar)
    elif convention == 'previous':
        rolled = _roll_backward(dt, calendar)
    elif convention == 'modprevious':
        rolled = _roll_backward(dt, calendar)
        if rolled.month < dt.month:
            rolled = _roll_forward(dt, calendar)
    return rolled
Пример #2
0
def rolldate(dt, calendar, convention):
    """ Roll date to the business day

    Roll date of the date to the business day according to the convention.
    For 'follow' convention, if date falls on a holiday, finds first working day after it
    For 'previous' convention, if date falls on a holiday, finds latest working day before it
    For 'modfollow' convention, if date falls on a holiday, finds first working day after it, unless date is the end of month in which case previous workday is found
    For 'previous' convention, if date falls on a holiday, finds latest working day before it, unless date is the beginning of month in which case following workday is found

    Parameters
    ----------
    dt: datetime.date, datetime.datetime or date string
    calendar: Calendar object that has is_holiday method
    convention: one of 'follow', 'previous', 'modfollow', 'modprevious'

    Returns
    -------
    datetime.datetime of the next business day according to the convention
    """
    convention = convention.lower()
    dt = dateutils.asdatetime(dt)
    rolled = dt
    if convention == "follow":
        rolled = _roll_forward(dt, calendar)
    elif convention == 'modfollow':
        rolled = _roll_forward(dt, calendar)
        if rolled.month > dt.month:
            rolled = _roll_backward(dt, calendar)
    elif convention == 'previous':
        rolled = _roll_backward(dt, calendar)
    elif convention == 'modprevious':
        rolled = _roll_backward(dt, calendar)
        if rolled.month < dt.month:
            rolled = _roll_forward(dt, calendar)
    return rolled
Пример #3
0
 def is_holiday(self, dt):
     """ Check if specific date is holiday
     """
     dt = dateutils.asdatetime(dt)
     year = dt.year
     if not year in self._holiday_cache:
         # create year cache
         self._holiday_cache[year] = set()
         current = datetime.datetime(year, 1, 1)
         end_year = datetime.datetime(year, 12, 31)
         while current <= end_year:
             b_holiday, name, move_day = self._verify_holiday(current)
             if b_holiday:
                 self._holiday_cache[year].add(current)
             if move_day is not None:
                 self._holiday_cache[year].add(move_day)
             current = current + datetime.timedelta(days = 1)
     return dt in self._holiday_cache[year]
Пример #4
0
 def is_holiday(self, dt):
     """ Check if specific date is holiday
     """
     dt = dateutils.asdatetime(dt)
     year = dt.year
     if not year in self._holiday_cache:
         # create year cache
         self._holiday_cache[year] = set()
         current = datetime.datetime(year, 1, 1)
         end_year = datetime.datetime(year, 12, 31)
         while current <= end_year:
             b_holiday, name, move_day = self._verify_holiday(current)
             if b_holiday:
                 self._holiday_cache[year].add(current)
             if move_day is not None:
                 self._holiday_cache[year].add(move_day)
             current = current + datetime.timedelta(days = 1)
     return dt in self._holiday_cache[year]
Пример #5
0
def _daycount_parameters(dt1, dt2, convention, **kwargs):
    """ Return number of days and total number of days (i.e. numerator and
        denominator in the counting of year fraction between dates
    """
    convention = _normalize_daycount_convention(convention)
    dt1 = dateutils.asdatetime(dt1)
    dt2 = dateutils.asdatetime(dt2)
    y1, m1, d1 = dt1.year, dt1.month, dt1.day
    y2, m2, d2 = dt2.year, dt2.month, dt2.day
    factor = None

    if convention in {'30/360 US', '30E/360', '30E/360 ISDA', '30E+/360'}:
        eom = 'eom' in kwargs and kwargs['eom']

        if convention == '30/360 US':
            # US adjustments
            if eom and dt1.month == 2 and dateutils.iseom(
                    dt1) and dt2.month == 2 and dateutils.iseom(dt2):
                d2 = 30
            if eom and dt1.month == 2 and dateutils.iseom(dt1):
                d1 = 30
            if d2 == 31 and d1 >= 30:
                d2 = 30
            if d1 == 31:
                d1 = 30
        elif convention == '30E/360':
            if d1 == 31:
                d1 = 30
            if d2 == 31:
                d2 = 30
        elif convention == '30E/360 ISDA':
            if dateutils.iseom(dt1):
                d1 = 30
            if dateutils.iseom(dt2) and m2 != 2:
                d2 = 30
        elif convention == '30E+/360':
            if d1 == 31:
                d1 = 30
            if d2 == 31:
                m2 += 1
                if m2 == 13:
                    m2 = 1
                    y2 += 1
                d2 = 1

        num_days = (360 * (y2 - y1) + 30 * (m2 - m1) + (d2 - d1))
        year_days = 360

    elif convention == 'ACTUAL/ACTUAL ISDA':
        num_days = 0
        year_days = 0

        if y2 == y1:
            num_days = (dt2 - dt1).days
            year_days = dateutils.yeardays(y1)
        else:
            # we need to calculate factor properly
            factor = 0.0
            # full years between y1 and y2 exclusive
            for y in range(y1 + 1, y2):
                yd = dateutils.yeardays(y)
                num_days += yd
                year_days += yd
                factor += float(num_days) / year_days
            # days in the remaining part of the first year
            num = (datetime.datetime(y1 + 1, 1, 1) - dt1).days
            den = dateutils.yeardays(y1)
            num_days += num
            year_days += den
            factor += float(num) / den
            # days in the beginning of the last year
            num = (dt2 - datetime.datetime(y2, 1, 1)).days
            den = dateutils.yeardays(y2)
            num_days += num
            year_days += den
            factor += float(num) / den

    elif convention == 'ACTUAL/365 FIXED':
        num_days = (dt2 - dt1).days
        year_days = 365
    elif convention == 'ACTUAL/360':
        num_days = (dt2 - dt1).days
        year_days = 360
    elif convention == 'ACTUAL/365L':
        yearly_frequency = 'frequency' in kwargs and kwargs[
            'frequency'] == 'yearly'
        if yearly_frequency:
            year_days = 366 if _period_has_29feb(dt1, dt2) else 365
        else:
            year_days = 366 if dateutils.leapyear(dt2) else 365
        num_days = (dt2 - dt1).days
    elif convention == 'ACTUAL/ACTUAL AFB':
        year_days = 366 if _period_has_29feb(dt1, dt2) else 365
        num_days = (dt2 - dt1).days
    else:
        raise ValueError('Unknown daycount convention \'%s\'' % convention)

    if factor is None:
        factor = float(num_days) / year_days

    return num_days, year_days, factor
Пример #6
0
def _daycount_parameters(dt1, dt2, convention, **kwargs):
    """ Return number of days and total number of days (i.e. numerator and
        denominator in the counting of year fraction between dates
    """
    convention = convention.upper()
    convention = _normalize_daycount_convention(convention)
    dt1 = dateutils.asdatetime(dt1)
    dt2 = dateutils.asdatetime(dt2)
    y1, m1, d1 = dt1.year, dt1.month, dt1.day
    y2, m2, d2 = dt2.year, dt2.month, dt2.day
    factor = None

    if convention in {'30/360 US', '30E/360', '30E/360 ISDA', '30E+/360'}:
        eom = 'eom' in kwargs and kwargs['eom']

        if convention == '30/360 US':
            # US adjustments
            if eom and dt1.month == 2 and dateutils.iseom(dt1) and dt2.month == 2 and dateutils.iseom(dt2):
                d2 = 30
            if eom and dt1.month == 2 and dateutils.iseom(dt1):
                d1 = 30
            if d2 == 31 and d1>=30:
                d2 = 30
            if d1 == 31:
                d1 = 30
        elif convention == '30E/360':
            if d1 == 31:
                d1 = 30
            if d2 == 31:
                d2 = 30
        elif convention == '30E/360 ISDA':
            if dateutils.iseom(dt1):
                d1 = 30
            if dateutils.iseom(dt2) and m2 != 2:
                d2 = 30
        elif convention == '30E+/360':
            if d1 == 31:
                d1 = 30
            if d2 == 31:
                m2 += 1
                if m2 == 13:
                    m2 = 1
                    y2 += 1
                d2 = 1

        num_days = (360*(y2-y1)+30*(m2-m1)+(d2-d1))
        year_days = 360

    elif convention == 'ACTUAL/ACTUAL ISDA':
        num_days = 0
        year_days = 0

        if y2 == y1:
            num_days = (dt2 - dt1).days
            year_days = dateutils.yeardays(y1)
        else:
            # we need to calculate factor properly
            factor = 0.0
            # full years between y1 and y2 exclusive
            for y in range(y1+1, y2):
                yd = dateutils.yeardays(y)
                num_days += yd
                year_days += yd
                factor += float(num_days)/year_days
            # days in the remaining part of the first year
            num = (datetime.datetime(y1+1, 1, 1) - dt1).days
            den = dateutils.yeardays(y1)
            num_days += num
            year_days += den
            factor += float(num)/den
            # days in the beginning of the last year
            num = (dt2 - datetime.datetime(y2, 1, 1)).days
            den = dateutils.yeardays(y2)
            num_days += num
            year_days += den
            factor += float(num)/den

    elif convention == 'ACTUAL/365 FIXED':
        num_days = (dt2-dt1).days
        year_days = 365
    elif convention == 'ACTUAL/360':
        num_days = (dt2-dt1).days
        year_days = 360
    elif convention == 'ACTUAL/365L':
        yearly_frequency = 'frequency' in kwargs and kwargs['frequency'] =='yearly'
        if yearly_frequency:
            year_days = 366 if _period_has_29feb(dt1, dt2) else 365
        else:
            year_days = 366 if dateutils.leapyear(dt2) else 365
        num_days = (dt2-dt1).days
    elif convention == 'ACTUAL/ACTUAL AFB':
        year_days = 366 if _period_has_29feb(dt1, dt2) else 365
        num_days = (dt2-dt1).days
    else:
        raise ValueError('Unknown daycount convention \'%s\'' % convention)

    if factor is None:
        factor = float(num_days)/year_days

    return num_days, year_days, factor