Exemplo n.º 1
0
    def add_weekdays(self, numDays: int):
        """ Returns a new date that is numDays working days after Date. Note
        that only weekends are taken into account. Other Holidays are not. If
        you want to include regional holidays then use add_business_days from
        the FinCalendar class. """

        # TODO: REMOVE DATETIME DEPENDENCE HERE

        if isinstance(numDays, int) is False:
            raise FinError("Num days must be an integer")

        positiveNumDays = (numDays > 0)
        numDays = abs(numDays)

        # 5 week days make up a week
        numWeeks = int(numDays / 5)
        remainingDays = numDays % 5

        if (positiveNumDays):
            if (self._weekday + remainingDays > self.FRI):
                # add weekend
                remainingDays += 2

            return self.add_days(numWeeks * 7 + remainingDays)
        else:
            if (self._weekday - remainingDays < self.MON):
                # add weekend
                remainingDays += 2

            return self.add_days(-(numWeeks * 7 + remainingDays))
Exemplo n.º 2
0
    def add_months(self,
                   mm: (list, int)):
        """ Returns a new date that is mm months after the Date. If mm is an
        integer or float you get back a single date. If mm is a vector you get
        back a vector of dates."""

        num_months = 1
        scalarFlag = False

        if isinstance(mm, int) or isinstance(mm, float):
            mmVector = [mm]
            scalarFlag = True
        else:
            mmVector = mm

        num_months = len(mmVector)

        dateList = []

        for i in range(0, num_months):

            mmi = mmVector[i]

            # If I get a float I check it has no decimal places
            if int(mmi) != mmi:
                raise FinError("Must only pass integers or float integers.")

            mmi = int(mmi)

            d = self._d
            m = self._m + mmi
            y = self._y

            while m > 12:
                m = m - 12
                y += 1

            while m < 1:
                m = m + 12
                y -= 1

            leap_year = is_leap_year(y)

            if leap_year:
                if d > monthDaysLeapYear[m - 1]:
                    d = monthDaysLeapYear[m-1]
            else:
                if d > monthDaysNotLeapYear[m - 1]:
                    d = monthDaysNotLeapYear[m-1]

            newDt = Date(d, m, y)
            dateList.append(newDt)

        if scalarFlag is True:
            return dateList[0]
        else:
            return dateList
Exemplo n.º 3
0
def days_in_month(m, y):
    """ Get the number of days in the month (1-12) of a given year y. """

    if m < 1 or m > 12:
        raise FinError("Month must be 1-12")

    if is_leap_year(y) is False:
        return monthDaysNotLeapYear[m - 1]
    else:
        return monthDaysLeapYear[m - 1]
Exemplo n.º 4
0
    def add_hours(self, hours):
        """ Returns a new date that is h hours after the Date. """

        if hours < 0:
            raise FinError("Number of hours must be positive")

        startHour = self._hh
        finalHour = startHour + hours
        days = int(finalHour / 24)
        hour = finalHour % 24

        # Move forward a specific number of days
        dt1 = self.add_days(days)

        # On that date we then move to the correct hour
        dt2 = Date(dt1._d, dt1._m, dt1._y, hour, dt1._mm, dt1._ss)
        return dt2
Exemplo n.º 5
0
    def third_wednesday_of_month(self,
                                 m: int,  # Month number
                                 y: int):  # Year number
        """ For a specific month and year this returns the day number of the
            3rd Wednesday by scanning through dates in the third week. """

        # Suppose 1st is Weds then 8th is Wed and 15th is 3rd Wed
        # Suppose 1st is Thur then 7th is Wed and 14th is 2nd Wed so 21 is 3rd
        # so earliest and latest dates are 15th and 21st

        d_start = 15
        d_end = 21

        for d in range(d_start, d_end+1):
            immDate = Date(d, m, y)
            if immDate._weekday == self.WED:
                return d

        # Should never reach this line but just to be defensive
        raise FinError("Third Wednesday not found")
Exemplo n.º 6
0
    def print(self, *args):
        """ Print comma separated output to GOLDEN or COMPARE directory. """

        if self._mode == FinTestCaseMode.DEBUG_TEST_CASES:
            print(args)
            return

        if not self._foldersExist:
            print("Cannot print as GOLDEN and COMPARE folders don't exist")
            return

        if self._headerFields is None:
            print("ERROR: Need to set header fields before printing results")
        elif len(self._headerFields) != len(args):
            n1 = len(self._headerFields)
            n2 = len(args)
            raise FinError("ERROR: Number of data columns is " + str(n1)
                           + " but must equal " + str(n2)
                           + " to align with headers.")

        if self._mode == FinTestCaseMode.SAVE_TEST_CASES:
            filename = self._goldenFilename
        else:
            filename = self._compareFilename

        f = open(filename, 'a')
        f.write("RESULTS,")

        for arg in args:
            if isinstance(arg, float):
                f.write("%10.8f" % (arg))
            else:
                f.write(str(arg))
            f.write(",")

        f.write("\n")
        f.close()
Exemplo n.º 7
0
    def __repr__(self):
        """ returns a formatted string of the date """

        global gDateFormatType

        dayNameStr = short_day_names[self._weekday]

        if self._d < 10:
            dayStr = "0" + str(self._d)
        else:
            dayStr = "" + str(self._d)

        if self._m < 10:
            shortMonthStr = "0" + str(self._m)
        else:
            shortMonthStr = str(self._m)

        longMonthStr = shortMonthNames[self._m - 1]

        shortYearStr = str(self._y)[2:]
        longYearStr = str(self._y)

        if gDateFormatType == DateFormatTypes.UK_LONGEST:

            sep = " "
            date_str = dayNameStr + " " + dayStr + sep + longMonthStr + sep + longYearStr
            return date_str

        elif gDateFormatType == DateFormatTypes.UK_LONG:

            sep = "-"
            date_str = dayStr + sep + longMonthStr + sep + longYearStr
            return date_str

        elif gDateFormatType == DateFormatTypes.UK_MEDIUM:

            sep = "/"
            date_str = dayStr + sep + shortMonthStr + sep + longYearStr
            return date_str

        elif gDateFormatType == DateFormatTypes.UK_SHORT:

            sep = "/"
            date_str = dayStr + sep + shortMonthStr + sep + shortYearStr
            return date_str

        elif gDateFormatType == DateFormatTypes.US_LONGEST:

            sep = " "
            date_str = dayNameStr + " " + longMonthStr + sep + dayStr + sep + longYearStr
            return date_str

        elif gDateFormatType == DateFormatTypes.US_LONG:

            sep = "-"
            date_str = longMonthStr + sep + dayStr + sep + longYearStr
            return date_str

        elif gDateFormatType == DateFormatTypes.US_MEDIUM:

            sep = "-"
            date_str = shortMonthStr + sep + dayStr + sep + longYearStr
            return date_str

        elif gDateFormatType == DateFormatTypes.US_SHORT:

            sep = "-"
            date_str = shortMonthStr + sep + dayStr + sep + shortYearStr
            return date_str

        elif gDateFormatType == DateFormatTypes.BLOOMBERG:

            sep = "/"
            date_str = shortMonthStr + sep + dayStr + sep + shortYearStr
            return date_str

        elif gDateFormatType == DateFormatTypes.DATETIME:

            sep = "/"

            if self._hh < 10:
                hourStr = "0" + str(self._hh)
            else:
                hourStr = str(self._hh)

            if self._mm < 10:
                minuteStr = "0" + str(self._mm)
            else:
                minuteStr = str(self._mm)

            if self._ss < 10:
                secondStr = "0" + str(self._ss)
            else:
                secondStr = str(self._ss)

            timeStr = hourStr + ":" + minuteStr + ":" + secondStr
            date_str = dayStr + sep + shortMonthStr + sep + longYearStr
            date_str = date_str + " " + timeStr
            return date_str

        else:

            raise FinError("Unknown date format")
Exemplo n.º 8
0
    def add_tenor(self, tenor: (list, str)):
        """ Return the date following the Date by a period given by the
        tenor which is a string consisting of a number and a letter, the
        letter being d, w, m , y for day, week, month or year. This is case
        independent. For example 10Y means 10 years while 120m also means 10
        years. The date is NOT weekend or holiday calendar adjusted. This must
        be done AFTERWARDS. """

        listFlag = False

        if isinstance(tenor, list) is True:
            listFlag = True
            for ten in tenor:
                if isinstance(ten, str) is False:
                    raise FinError("Tenor must be a string e.g. '5Y'")
        else:
            if isinstance(tenor, str) is True:
                tenor = [tenor]
            else:
                raise FinError("Tenor must be a string e.g. '5Y'")

        newDates = []

        for tenStr in tenor:
            tenStr = tenStr.upper()
            DAYS = 1
            WEEKS = 2
            MONTHS = 3
            YEARS = 4

            periodType = 0
            num_periods = 0

            if tenStr == "ON":  # overnight - should be used only if spot days = 0
                periodType = DAYS
                num_periods = 1
            elif tenStr == "TN":  # overnight - should be used when spot days > 0
                periodType = DAYS
                num_periods = 1
            elif tenStr[-1] == "D":
                periodType = DAYS
                num_periods = int(tenStr[0:-1])
            elif tenStr[-1] == "W":
                periodType = WEEKS
                num_periods = int(tenStr[0:-1])
            elif tenStr[-1] == "M":
                periodType = MONTHS
                num_periods = int(tenStr[0:-1])
            elif tenStr[-1] == "Y":
                periodType = YEARS
                num_periods = int(tenStr[0:-1])
            else:
                raise FinError("Unknown tenor type in " + tenor)

            newDate = Date(self._d, self._m, self._y)

            if periodType == DAYS:
                for _ in range(0, num_periods):
                    newDate = newDate.add_days(1)
            elif periodType == WEEKS:
                for _ in range(0, num_periods):
                    newDate = newDate.add_days(7)
            elif periodType == MONTHS:
                for _ in range(0, num_periods):
                    newDate = newDate.add_months(1)
            elif periodType == YEARS:
                for _ in range(0, num_periods):
                    newDate = newDate.add_months(12)

            newDates.append(newDate)

        if listFlag is True:
            return newDates
        else:
            return newDates[0]
Exemplo n.º 9
0
    def __init__(self, d, m, y, hh=0, mm=0, ss=0):
        """ Create a date given a day of month, month and year. The arguments
        must be in the order of day (of month), month number and then the year.
        The year must be a 4-digit number greater than or equal to 1900. The
        user can also supply an hour, minute and second for intraday work.

        Example Input:
        start_date = Date(1, 1, 2018)
        """

        global gStartYear
        global gEndYear

        # If the date has been entered as y, m, d we flip it to d, m, y
        # This message should be removed after a few releases
        if d >= gStartYear and d < gEndYear and y > 0 and y <= 31:
            raise FinError(
                "Date arguments must now be in the order Date(dd, mm, yyyy)")

        if gDateCounterList is None:
            calculate_list()

        if y < 1900:
            raise FinError("Year cannot be before 1900")

        # Resize date list dynamically if required
        if y < gStartYear:
            gStartYear = y
            calculate_list()

        if y > gEndYear:
            gEndYear = y
            calculate_list()

        if y < gStartYear or y > gEndYear:
            raise FinError("Date: year " + str(y) + " should be " +
                           str(gStartYear) + " to " + str(gEndYear))

        if d < 1:
            raise FinError("Date: Leap year. Day not valid.")

        leap_year = is_leap_year(y)

        if leap_year:
            if d > monthDaysLeapYear[m - 1]:
                print(d, m, y)
                raise FinError("Date: Leap year. Day not valid.")
        else:
            if d > monthDaysNotLeapYear[m - 1]:
                print(d, m, y)
                raise FinError("Date: Not Leap year. Day not valid.")

        if hh < 0 or hh > 23:
            raise FinError("Hours must be in range 0-23")

        if mm < 0 or mm > 59:
            raise FinError("Minutes must be in range 0-59")

        if ss < 0 or ss > 59:
            raise FinError("Seconds must be in range 0-59")

        self._y = y
        self._m = m
        self._d = d

        self._hh = hh
        self._mm = mm
        self._ss = ss

        self._excel_date = 0  # This is a float as it includes intraday time

        # update the excel date used for doing lots of financial calculations
        self._refresh()

        dayFraction = self._hh / 24.0
        dayFraction += self._mm / 24.0 / 60.0
        dayFraction += self._ss / 24.0 / 60.0 / 60.0

        self._excel_date += dayFraction  # This is a float as it includes intraday time
Exemplo n.º 10
0
    def __init__(self, moduleName, mode):
        """ Create the TestCase given the module name and whether we are in
        GOLDEN or COMPARE mode. """

        rootFolder, moduleFilename = split(moduleName)

        self._carefulMode = False
        self._verbose = False

        if mode in FinTestCaseMode:
            self._mode = mode
        else:
            raise FinError("Unknown TestCase Mode")

        if mode == FinTestCaseMode.DEBUG_TEST_CASES:
            # Don't do anything
            self._verbose = True
            return

        self._moduleName = moduleFilename[0:-3]
        self._foldersExist = True
        self._rootFolder = rootFolder
        self._headerFields = None
        self._globalNumWarnings = 0
        self._globalNumErrors = 0

#        print("Root folder:",self._rootFolder)
#        print("Modulename:",self._moduleName)

        self._goldenFolder = join(rootFolder, "golden")
        self._differencesFolder = join(rootFolder, "differences")

        if exists(self._goldenFolder) is False:
            print("Looking for:", self._goldenFolder)
            print("GOLDEN Folder DOES NOT EXIST. You must create it. Exiting")
            self._foldersExist = False
            return None

        self._compareFolder = join(rootFolder, "compare")

        if exists(self._compareFolder) is False:
            print("Looking for:", self._compareFolder)
            print("COMPARE Folder DOES NOT EXIST. You must create it. Exiting")
            self._foldersExist = False
            return None

        self._goldenFilename = join(self._goldenFolder,
                                    self._moduleName + "_GOLDEN.testLog")

        self._compareFilename = join(self._compareFolder,
                                     self._moduleName + "_COMPARE.testLog")

        self._differencesFilename = join(self._differencesFolder,
                                         self._moduleName + "_DIFFS.testLog")

        if self._mode == FinTestCaseMode.SAVE_TEST_CASES:

            print("GOLDEN Test Case Creation for module:", moduleFilename)

            if exists(self._goldenFilename) and self._carefulMode:
                overwrite = input("File " + self._goldenFilename
                                  + " exists. Overwrite (Y/N) ?")
                if overwrite == "N":
                    print("Not overwriting. Saving test cases failed.")
                    return
                elif overwrite == "Y":
                    print("Overwriting existing file...")

            creationTime = time.strftime("%Y%m%d_%H%M%S")
            f = open(self._goldenFilename, 'w')
            f.write("File Created on:" + creationTime)
            f.write("\n")
            f.close()

        else:

            #            print("GENERATING NEW OUTPUT FOR MODULE", moduleFilename,
            #                "FOR COMPARISON.")

            if exists(self._compareFilename) and self._carefulMode:
                overwrite = input("File " + self._compareFilename +
                                  " exists. Overwrite (Y/N) ?")
                if overwrite == "N":
                    print("Not overwriting. Saving test cases failed.")
                    return
                elif overwrite == "Y":
                    print("Overwriting existing file...")

#            print("Creating empty file",self._compareFilename)
            creationTime = time.strftime("%Y%m%d_%H%M%S")
            f = open(self._compareFilename, 'w')
            f.write("File Created on:" + creationTime)
            f.write("\n")
            f.close()
Exemplo n.º 11
0
    def add_weekdays(self,
                     numDays: int):
        """ Returns a new date that is numDays working days after Date. Note
        that only weekends are taken into account. Other Holidays are not. If
        you want to include regional holidays then use add_business_days from
        the FinCalendar class. """

        # TODO: REMOVE DATETIME DEPENDENCE HERE

        end_date = self;
        
        if isinstance(numDays, int) is False:
            raise FinError("Num days must be an integer")

        positiveNumDays = (numDays > 0)
        numDays = abs(numDays)

        # 5 week days make up a week
        oldLogic = False

        if oldLogic is True:
            numWeeks = int(numDays / 5)
            remainingDays = numDays % 5
            
            if self._weekday == Date.SAT:
                weekendAdjust = 1
            elif self._weekday == Date.SUN:
                weekendAdjust = 0
            else:
                weekendAdjust = 2
    
            if (positiveNumDays):
                if (self._weekday + remainingDays > self.FRI):
                    # add weekend
                    remainingDays += weekendAdjust
    
                return self.add_days(numWeeks * 7 + remainingDays)
            else:
                if (self._weekday - remainingDays < self.MON):
                    # add weekend
                    remainingDays += weekendAdjust
    
            return self.add_days(-(numWeeks * 7 + remainingDays))

        else: # new logic

            numDaysLeft = numDays
            end_date = self
            
            while numDaysLeft > 0:

                if positiveNumDays is True:
                    end_date = end_date.add_days(1)
                else:
                    end_date = end_date.add_days(-1)

                if end_date._weekday == Date.SAT or end_date._weekday == Date.SUN:
                    pass
                else:
                    numDaysLeft -= 1

            return end_date