Source code for finpricing.utils.calendar

from enum import Enum
from .error import NotSupportedError
from .date import Date
from .bus_day_adj import BusDayAdjustTypes
from .holiday import Holiday, CalendarTypes


[docs] class DateGenRuleTypes(Enum): FORWARD = 1 BACKWARD = 2
[docs] class Calendar: def __init__(self, calendarType: CalendarTypes) -> None: """ I think holiday should be a class dependent on the calendar type. """ if calendarType not in CalendarTypes: raise NotSupportedError("CalendarTypes is not supported") self._calendarType = calendarType self._holiday = Holiday(calendarType)
[docs] def is_holiday(self, date: Date) -> bool: return self._holiday.is_holiday(date)
[docs] def is_business_day(self, date: Date) -> bool: """Return True if the date is a business day Weekend or not is determined solely by the date itself. Holiday or not is determined by the calendar. """ if date.is_weekend is False and self.is_holiday(date) is False: return True else: return False
[docs] def add_business_days(self, date: Date, num_days: int) -> Date: """Return a new Date object by adding num_days business days to the date""" if num_days == 0: return date if num_days > 0: date = date.add_days(1) while self.is_business_day(date) is False: date = date.add_days(1) return self.add_business_days(date, num_days - 1) else: date = date.add_days(-1) while self.is_business_day(date) is False: date = date.add_days(-1) return self.add_business_days(date, num_days + 1)
[docs] def adjust(self, date: Date, busDayAdjType: BusDayAdjustTypes) -> Date: """Return a new Date object by adjusting the date according to the Business Day Convention For details, https://jollycontrarian.com/index.php?title=Business_Day_Convention_-_ISDA_Definition """ # no need to adjust if no calendar is specified if self._calendarType == CalendarTypes.NONE: return date # need to adjust but depend on the BusDayAdjustTypes if busDayAdjType == BusDayAdjustTypes.NONE: return date elif busDayAdjType == BusDayAdjustTypes.FOLLOWING: while self.is_business_day(date) is False: date = date.add_days(1) return date elif busDayAdjType == BusDayAdjustTypes.MODIFIED_FOLLOWING: initial_date = Date.from_tuple(date.to_tuple()) while self.is_business_day(date) is False: date = date.add_days(1) # if the following business day is in the different month, find the previous business day if date.month != initial_date.month: date = initial_date while self.is_business_day(date) is False: date = date.add_days(-1) return date elif busDayAdjType == BusDayAdjustTypes.PREVIOUS: while self.is_business_day(date) is False: date = date.add_days(-1) return date elif busDayAdjType == BusDayAdjustTypes.MODIFIED_PREVIOUS: initial_date = Date.from_tuple(date.to_tuple()) while self.is_business_day(date) is False: date = date.add_days(-1) # if the previous business day is in the different month, find the next business day if date.month != initial_date.month: date = initial_date while self.is_business_day(date) is False: date = date.add_days(1) return date else: raise NotSupportedError( "BusDayAdjustTypes is not supported, cannot adjust date")