Ejemplo n.º 1
0
 def __add__(self, period):
     if isinstance(period, Period):
         return _advance(self, period.length, period.units)
     elif isinstance(period, int):
         return Date(serialNumber=self.__serialNumber__ + period)
     else:
         period = Period(period)
         return _advance(self, period.length, period.units)
Ejemplo n.º 2
0
 def __sub__(self, period):
     if isinstance(period, Period):
         return _advance(self, -period.length, period.units)
     elif isinstance(period, int):
         return Date(serial_number=self.__serialNumber__ - period)
     elif isinstance(period, Date):
         return self.__serialNumber__ - period.__serialNumber__
     else:
         period = Period(period)
         return _advance(self, -period.length, period.units)
Ejemplo n.º 3
0
    def testPeriodPickle(self):
        p1 = Period('36m')

        f = tempfile.NamedTemporaryFile('w+b', delete=False)
        pickle.dump(p1, f)
        f.close()

        with open(f.name, 'rb') as f2:
            pickled_period = pickle.load(f2)
            self.assertEqual(p1, pickled_period)

        os.unlink(f.name)
Ejemplo n.º 4
0
    def advanceDate(self,
                    d,
                    period,
                    c=BizDayConventions.Following,
                    endOfMonth=False):

        if isinstance(period, str):
            period = Period(period)

        n = period.length
        units = period.units

        if n == 0:
            return self.adjustDate(d, c)
        elif units == TimeUnits.BDays:
            d1 = d
            if n > 0:
                while n > 0:
                    d1 += 1
                    while self.isHoliday(d1):
                        d1 += 1
                    n -= 1
            else:
                while n < 0:
                    d1 -= 1
                    while self.isHoliday(d1):
                        d1 -= 1
                    n += 1
            return d1
        elif units == TimeUnits.Days or units == TimeUnits.Weeks:
            d1 = d + period
            return self.adjustDate(d1, c)
        else:
            d1 = d + period
            if endOfMonth and self.isEndOfMonth(d):
                return self.endOfMonth(d1)
            return self.adjustDate(d1, c)
Ejemplo n.º 5
0
    def testPeriodDeepCopy(self):
        p1 = Period('36m')
        p2 = copy.deepcopy(p1)

        self.assertEqual(p1, p2)
Ejemplo n.º 6
0
    def testWeeksDaysAlgebra(self):
        two_weeks = Period(length=2, units=TimeUnits.Weeks)
        one_week = Period(length=1, units=TimeUnits.Weeks)
        three_days = Period(length=3, units=TimeUnits.Days)
        one_day = Period(length=1, units=TimeUnits.Days)

        n = 2
        flag = two_weeks / n == one_week
        self.assertTrue(flag, "division error: {0} / {1:d}"
                              " not equal to {2}".format(two_weeks, n, one_week))

        n = 7
        flag = one_week / 7 == one_day
        self.assertTrue(flag, "division error: {0} / {1:d}"
                              " not equal to {2}".format(one_week, n, one_day))

        sum = three_days
        sum += one_day
        flag = sum == Period(length=4, units=TimeUnits.Days)
        self.assertTrue(flag, "sum error: {0}"
                              " + {1}"
                              " != {2}".format(three_days, one_day, Period(length=4, units=TimeUnits.Days)))

        sum += one_week
        flag = sum == Period(length=11, units=TimeUnits.Days)
        self.assertTrue(flag, "sum error: {0}"
                              " + {1}"
                              " + {2}"
                              " != {3}".format(three_days, one_day, one_week, Period(length=11, units=TimeUnits.Days)))

        sevenDays = Period(length=7, units=TimeUnits.Days)
        flag = sevenDays.length == 7
        self.assertTrue(flag, "normalization error: sevenDays.length"
                              " is {0:d}"
                              " instead of 7".format(sevenDays.length))
        flag = sevenDays.units == TimeUnits.Days
        self.assertTrue(flag, "normalization error: sevenDays.units"
                              " is {0:d}"
                              " instead of {1:d}".format(sevenDays.units, TimeUnits.Days))

        normalized_seven_days = sevenDays.normalize()
        flag = normalized_seven_days.length == 1
        self.assertTrue(flag, "normalization error: normalized_seven_days.length"
                              " is {0:d}"
                              " instead of 1".format(normalized_seven_days.length))
        flag = normalized_seven_days.units == TimeUnits.Weeks
        self.assertTrue(flag, "normalization error: TwelveMonths.units"
                              " is {0:d}"
                              " instead of {1:d}".format(normalized_seven_days.units, TimeUnits.Weeks))
Ejemplo n.º 7
0
    def testYearsMonthsAlgebra(self):
        one_year = Period(length=1, units=TimeUnits.Years)
        six_months = Period(length=6, units=TimeUnits.Months)
        three_months = Period(length=3, units=TimeUnits.Months)

        n = 4
        flag = one_year / n == three_months
        self.assertTrue(flag, "division error: {0} / {1:d}"
                              " not equal to {2}".format(one_year, n, three_months))

        n = 2
        flag = one_year / n == six_months
        self.assertTrue(flag, "division error: {0} / {1:d}"
                              " not equal to {2}".format(one_year, n, six_months))

        test_sum = three_months
        test_sum += six_months
        flag = test_sum == Period(length=9, units=TimeUnits.Months)
        self.assertTrue(flag, "test_sum error: {0}"
                              " + {1}"
                              " != {2}".format(three_months, six_months, Period(length=9, units=TimeUnits.Months)))

        test_sum += one_year
        flag = test_sum == Period(length=21, units=TimeUnits.Months)
        self.assertTrue(flag, "test_sum error: {0}"
                              " + {1}"
                              " + {2}"
                              " != {3}".format(three_months, six_months, one_year,
                                               Period(length=21, units=TimeUnits.Months)))

        twelve_months = Period(length=12, units=TimeUnits.Months)
        flag = twelve_months.length == 12
        self.assertTrue(flag, "normalization error: TwelveMonths.length"
                              " is {0:d}"
                              " instead of 12".format(twelve_months.length))
        flag = twelve_months.units == TimeUnits.Months
        self.assertTrue(flag, "normalization error: TwelveMonths.units"
                              " is {0:d}"
                              " instead of {1:d}".format(twelve_months.units, TimeUnits.Months))

        normalized_twelve_months = Period(length=12, units=TimeUnits.Months)
        normalized_twelve_months = normalized_twelve_months.normalize()
        flag = normalized_twelve_months.length == 1
        self.assertTrue(flag, "normalization error: TwelveMonths.length"
                              " is {0:d}"
                              " instead of 1".format(twelve_months.length))
        flag = normalized_twelve_months.units == TimeUnits.Years
        self.assertTrue(flag, "normalization error: TwelveMonths.units"
                              " is {0:d}"
                              " instead of {1:d}".format(twelve_months.units, TimeUnits.Years))

        thirty_days = Period(length=30, units=TimeUnits.Days)
        normalized_thirty_days = thirty_days.normalize()
        flag = normalized_thirty_days.units == TimeUnits.Days
        self.assertTrue(flag, "normalization error: ThirtyDays.units"
                              " is {0:d}"
                              " instead of {1:d}".format(normalized_thirty_days.units, TimeUnits.Days))

        thirty_b_days = Period(length=30, units=TimeUnits.BDays)
        normalized_thirty_b_days = thirty_b_days.normalize()
        flag = normalized_thirty_b_days.units == TimeUnits.BDays
        self.assertTrue(flag, "normalization error: ThirtyBDays.units"
                              " is {0:d}"
                              " instead of {1:d}".format(normalized_thirty_b_days.units, TimeUnits.BDays))
Ejemplo n.º 8
0
    def testComparingOperators(self):
        p1 = Period(length=0, units=TimeUnits.Days)
        p2 = Period(length=1, units=TimeUnits.Days)
        self.assertTrue(p1 < p2)

        p1 = Period(length=13, units=TimeUnits.Months)
        p2 = Period(length=1, units=TimeUnits.Years)
        self.assertTrue(not p1 < p2)

        p1 = Period(length=1, units=TimeUnits.Years)
        p2 = Period(length=13, units=TimeUnits.Months)
        self.assertTrue(p1 < p2)

        p1 = Period(length=13, units=TimeUnits.Days)
        p2 = Period(length=2, units=TimeUnits.Weeks)
        self.assertTrue(p1 < p2)

        p1 = Period(length=2, units=TimeUnits.Weeks)
        p2 = Period(length=13, units=TimeUnits.Days)
        self.assertTrue(not p1 < p2)

        p1 = Period(length=1, units=TimeUnits.Years)
        p2 = Period(length=56, units=TimeUnits.Weeks)
        self.assertTrue(p1 < p2)

        p1 = Period(length=56, units=TimeUnits.Weeks)
        p2 = Period(length=1, units=TimeUnits.Years)
        self.assertTrue(not p1 < p2)

        p1 = Period(length=21, units=TimeUnits.Weeks)
        p2 = Period(length=5, units=TimeUnits.Months)

        with self.assertRaises(ValueError):
            _ = p1 < p2

        p1 = Period(length=21, units=TimeUnits.BDays)
        with self.assertRaises(ValueError):
            _ = p1 < p2

        # test not equal operator
        p1 = Period(length=1, units=TimeUnits.Days)
        p2 = Period(length=1, units=TimeUnits.Days)
        self.assertTrue(not p1 != p2)

        p2 = Period(length=1, units=TimeUnits.Years)
        self.assertTrue(p1 != p2)

        # test greater than operator
        p1 = Period(length=1, units=TimeUnits.Days)
        p2 = Period(length=2, units=TimeUnits.Days)
        self.assertEqual(p1 < p2, not p1 > p2)
Ejemplo n.º 9
0
    def testBasicArithmetic(self):
        # test bad normalize
        test_period = Period(length=1, units=TimeUnits.Years)
        test_period._units = 10
        with self.assertRaises(TypeError):
            test_period.normalize()

        # test plus method
        p1 = Period(length=0, units=TimeUnits.Days)
        p2 = Period(length=10, units=TimeUnits.Months)
        calculated = p1 + p2
        self.assertEqual(p2, calculated, "added value {0} should be equal to {1}".format(calculated, p2))

        p1 = Period(length=2, units=TimeUnits.Years)
        p2 = Period(length=13, units=TimeUnits.Months)
        calculated = p1 + p2
        expected = Period(length=37, units=TimeUnits.Months)
        self.assertEqual(expected, calculated, "added value {0} should be equal to {1}".format(calculated, expected))

        p2 = Period(length=2, units=TimeUnits.Weeks)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2 = Period(length=2, units=TimeUnits.BDays)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2 = Period(length=2, units=TimeUnits.Days)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2._units = 10
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p1 = Period(length=13, units=TimeUnits.Months)
        p2 = Period(length=2, units=TimeUnits.Years)
        calculated = p1 + p2
        expected = Period(length=37, units=TimeUnits.Months)
        self.assertEqual(expected, calculated, "added value {0} should be equal to {1}".format(calculated, expected))

        p2 = Period(length=2, units=TimeUnits.Weeks)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2 = Period(length=2, units=TimeUnits.BDays)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2 = Period(length=2, units=TimeUnits.Days)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2._units = 10
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p1 = Period(length=2, units=TimeUnits.Weeks)
        p2 = Period(length=7, units=TimeUnits.Days)
        calculated = p1 + p2
        expected = Period(length=21, units=TimeUnits.Days)
        self.assertEqual(expected, calculated, "added value {0} should be equal to {1}".format(calculated, expected))

        p2 = Period(length=2, units=TimeUnits.Months)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2 = Period(length=2, units=TimeUnits.BDays)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2 = Period(length=2, units=TimeUnits.Years)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2._units = 10
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p1 = Period(length=7, units=TimeUnits.Days)
        p2 = Period(length=2, units=TimeUnits.Weeks)
        calculated = p1 + p2
        expected = Period(length=21, units=TimeUnits.Days)
        self.assertEqual(expected, calculated, "added value {0} should be equal to {1}".format(calculated, expected))

        p2 = Period(length=2, units=TimeUnits.Months)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2 = Period(length=2, units=TimeUnits.BDays)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2 = Period(length=2, units=TimeUnits.Years)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2._units = 10
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p1 = Period(length=7, units=TimeUnits.BDays)

        p2 = Period(length=2, units=TimeUnits.Months)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2 = Period(length=2, units=TimeUnits.Days)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2 = Period(length=2, units=TimeUnits.Weeks)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2 = Period(length=2, units=TimeUnits.Years)
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2._units = 10
        with self.assertRaises(ValueError):
            _ = p1 + p2

        p2 = Period(length=2, units=TimeUnits.BDays)
        self.assertEqual(p1 + p2, Period('9B'))

        # test negative operator
        p1 = Period(length=-13, units=TimeUnits.Weeks)
        p2 = -p1
        self.assertEqual(p2, Period(length=13, units=TimeUnits.Weeks))

        # test less operator
        p1 = Period(length=0, units=TimeUnits.Days)
        p2 = Period(length=-3, units=TimeUnits.BDays)
        self.assertTrue(p2 < p1)

        # test sub operator
        p1 = Period(length=0, units=TimeUnits.Days)
        p2 = Period(length=-3, units=TimeUnits.BDays)
        self.assertEqual(p1 - p2, Period('3b'))

        # test string representation
        p1 = Period(length=12, units=TimeUnits.Months)
        self.assertEqual("1Y", p1.__str__())
Ejemplo n.º 10
0
    def __init__(self,
                 effectiveDate,
                 terminationDate,
                 tenor,
                 calendar,
                 convention=BizDayConventions.Following,
                 terminationConvention=BizDayConventions.Following,
                 dateGenerationRule=DateGeneration.Forward,
                 endOfMonth=False,
                 firstDate=None,
                 nextToLastDate=None,
                 evaluationDate=None):

        # Initialize private data
        self._effectiveDate = effectiveDate
        self._terminationDate = terminationDate
        self._tenor = tenor
        self._cal = calendar
        self._convention = convention
        self._terminationConvention = terminationConvention
        self._rule = dateGenerationRule
        self._dates = []
        self._isRegular = []

        if tenor < Period("1M"):
            self._endOfMonth = False
        else:
            self._endOfMonth = endOfMonth

        if firstDate is None or firstDate == effectiveDate:
            self._firstDate = None
        else:
            self._firstDate = firstDate

        if nextToLastDate is None or nextToLastDate == terminationDate:
            self._nextToLastDate = None
        else:
            self._nextToLastDate = nextToLastDate

        # in many cases (e.g. non-expired bonds) the effective date is not
        # really necessary. In these cases a decent placeholder is enough
        if effectiveDate is None and firstDate is None and dateGenerationRule == DateGeneration.Backward:
            evalDate = evaluationDate
            py_assert(evalDate < terminationDate, ValueError,
                      "null effective date")
            if nextToLastDate is not None:
                y = int((nextToLastDate - evalDate) / 366) + 1
                effectiveDate = nextToLastDate - Period(length=y,
                                                        units=TimeUnits.Years)
            else:
                y = int((terminationDate - evalDate) / 366) + 1
                effectiveDate = terminationDate - Period(length=y,
                                                         units=TimeUnits.Years)
        else:
            py_assert(effectiveDate is not None, ValueError,
                      "null effective date")

        py_assert(
            effectiveDate < terminationDate, ValueError,
            "effective date ({0}) "
            "later than or equal to termination date ({1}".format(
                effectiveDate, terminationDate))

        if tenor.length == 0:
            self._rule = DateGeneration.Zero
        else:
            py_assert(
                tenor.length > 0, ValueError,
                "non positive tenor ({0:d}) not allowed".format(tenor.length))

        if self._firstDate is not None:
            if self._rule == DateGeneration.Backward or self._rule == DateGeneration.Forward:
                py_assert(
                    effectiveDate < self._firstDate < terminationDate,
                    ValueError,
                    "first date ({0}) out of effective-termination date range [{1}, {2})"
                    .format(self._firstDate, effectiveDate, terminationDate))
                # we should ensure that the above condition is still
                # verified after adjustment
            elif self._rule == DateGeneration.Zero:
                raise ValueError(
                    "first date incompatible with {0:d} date generation rule".
                    format(self._rule))
            else:
                raise ValueError("unknown rule ({0:d})".format(self._rule))

        if self._nextToLastDate is not None:
            if self._rule == DateGeneration.Backward or self._rule == DateGeneration.Forward:
                py_assert(
                    effectiveDate < self._nextToLastDate < terminationDate,
                    ValueError,
                    "next to last date ({0}) out of effective-termination date range [{1}, {2})"
                    .format(self._nextToLastDate, effectiveDate,
                            terminationDate))
                # we should ensure that the above condition is still
                # verified after adjustment
            elif self._rule == DateGeneration.Zero:
                raise ValueError(
                    "next to last date incompatible with {0:d} date generation rule"
                    .format(self._rule))
            else:
                raise ValueError("unknown rule ({0:d})".format(self._rule))

        # calendar needed for endOfMonth adjustment
        nullCalendar = Calendar("Null")
        periods = 1

        if self._rule == DateGeneration.Zero:
            self._tenor = Period(length=0, units=TimeUnits.Years)
            self._dates.extend([effectiveDate, terminationDate])
            self._isRegular.append(True)
        elif self._rule == DateGeneration.Backward:
            self._dates.append(terminationDate)
            seed = terminationDate
            if self._nextToLastDate is not None:
                self._dates.insert(0, self._nextToLastDate)
                temp = nullCalendar.advanceDate(
                    seed,
                    Period(length=-periods * self._tenor.length,
                           units=self._tenor.units), convention,
                    self._endOfMonth)
                if temp != self._nextToLastDate:
                    self._isRegular.insert(0, False)
                else:
                    self._isRegular.insert(0, True)
                seed = self._nextToLastDate

            exitDate = effectiveDate
            if self._firstDate is not None:
                exitDate = self._firstDate

            while True:
                temp = nullCalendar.advanceDate(
                    seed,
                    Period(length=-periods * self._tenor.length,
                           units=self._tenor.units), convention,
                    self._endOfMonth)
                if temp < exitDate:
                    if self._firstDate is not None and self._cal.adjustDate(
                            self._dates[0],
                            convention) != self._cal.adjustDate(
                                self._firstDate, convention):
                        self._dates.insert(0, self._firstDate)
                        self._isRegular.insert(0, False)
                    break
                else:
                    # skip dates that would result in duplicates
                    # after adjustment
                    if self._cal.adjustDate(
                            self._dates[0],
                            convention) != self._cal.adjustDate(
                                temp, convention):
                        self._dates.insert(0, temp)
                        self._isRegular.insert(0, True)
                    periods += 1

            if self._cal.adjustDate(self._dates[0],
                                    convention) != self._cal.adjustDate(
                                        effectiveDate, convention):
                self._dates.insert(0, effectiveDate)
                self._isRegular.insert(0, False)

        elif self._rule == DateGeneration.Forward:
            self._dates.append(effectiveDate)

            seed = self._dates[-1]

            if self._firstDate is not None:
                self._dates.append(self._firstDate)
                temp = nullCalendar.advanceDate(
                    seed,
                    Period(length=periods * self._tenor.length,
                           units=self._tenor.units), convention,
                    self._endOfMonth)
                if temp != self._firstDate:
                    self._isRegular.append(False)
                else:
                    self._isRegular.append(True)
                seed = self._firstDate

            exitDate = terminationDate
            if self._nextToLastDate is not None:
                exitDate = self._nextToLastDate

            while True:
                temp = nullCalendar.advanceDate(
                    seed,
                    Period(length=periods * self._tenor.length,
                           units=self._tenor.units), convention,
                    self._endOfMonth)
                if temp > exitDate:
                    if self._nextToLastDate is not None and self._cal.adjustDate(
                            self._dates[-1],
                            convention) != self._cal.adjustDate(
                                self._nextToLastDate, convention):
                        self._dates.append(self._nextToLastDate)
                        self._isRegular.append(False)
                    break
                else:
                    # skip dates that would result in duplicates
                    # after adjustment
                    if self._cal.adjustDate(
                            self._dates[-1],
                            convention) != self._cal.adjustDate(
                                temp, convention):
                        self._dates.append(temp)
                        self._isRegular.append(True)
                    periods += 1

            if self._cal.adjustDate(
                    self._dates[-1],
                    terminationConvention) != self._cal.adjustDate(
                        terminationDate, terminationConvention):
                self._dates.append(terminationDate)
                self._isRegular.append(False)
        else:
            raise ValueError("unknown rule ({0:d})".format(self._rule))

        # adjustments
        if self._endOfMonth and self._cal.isEndOfMonth(seed):
            # adjust to end of month
            if convention == BizDayConventions.Unadjusted:
                for i in range(len(self._dates) - 1):
                    self._dates[i] = Date.endOfMonth(self._dates[i])
            else:
                for i in range(len(self._dates) - 1):
                    self._dates[i] = self._cal.endOfMonth(self._dates[i])

            if terminationConvention != BizDayConventions.Unadjusted:
                self._dates[0] = self._cal.endOfMonth(self._dates[0])
                self._dates[-1] = self._cal.endOfMonth(self._dates[-1])
            else:
                if self._rule == DateGeneration.Backward:
                    self._dates[-1] = Date.endOfMonth(self._dates[-1])
                else:
                    self._dates[0] = Date.endOfMonth(self._dates[0])
        else:
            for i in range(len(self._dates) - 1):
                self._dates[i] = self._cal.adjustDate(self._dates[i],
                                                      convention)

            if terminationConvention != BizDayConventions.Unadjusted:
                self._dates[-1] = self._cal.adjustDate(self._dates[-1],
                                                       terminationConvention)

        # Final safety checks to remove extra next-to-last date, if
        # necessary.  It can happen to be equal or later than the end
        # date due to EOM adjustments (see the Schedule test suite
        # for an example).

        dateLen = len(self._dates)

        if dateLen >= 2 and self._dates[dateLen - 2] >= self._dates[-1]:
            self._isRegular[dateLen - 2] = (self._dates[dateLen -
                                                        2] == self._dates[-1])
            self._dates[dateLen - 2] = self._dates[-1]
            self._dates.pop()
            self._isRegular.pop()

        if len(self._dates) >= 2 and self._dates[1] <= self._dates[0]:
            self._isRegular[1] = (self._dates[1] == self._dates[0])
            self._dates[1] = self._dates[0]
            self._dates = self._dates[1:]
            self._isRegular = self._isRegular[1:]

        py_assert(
            len(self._dates) >= 1, ValueError,
            "degenerate single date ({0}) schedule\n"
            "seed date: {1}\n"
            "exit date: {2}\n"
            "effective date: {3}\n"
            "first date: {4}\n"
            "next to last date: {5}\n"
            "termination date: {6}\n"
            "generation rule: {7}\n"
            "end of month: {8}\n".format(self._dates[0], seed, exitDate,
                                         effectiveDate, firstDate,
                                         nextToLastDate, terminationDate,
                                         self._rule, self._endOfMonth))