Example #1
0
 def _act_360_fraction(self, date):
     '''Implement daycount method Act/360
     '''
     date = BankDate(date)
     if date and date > self._valuation_date:
         return self._valuation_date.nbr_of_days(date) / to_decimal(360)
     else:
         return to_decimal(0)
Example #2
0
 def _360_360_fraction(self, date):
     '''Implement daycount method 360/360
     '''
     day1 = BankDate(date)
     day2 = self._valuation_date
     if day1 and day1 > day2:
         number_of_days = 360 * (day1.year - day2.year) \
             + 30 * (day1.month - day2.month) \
             + (day1.day - day2.day)
         number_of_days = number_of_days % 360
         return to_decimal(number_of_days) / to_decimal(360)
     else:
         return to_decimal(0)
Example #3
0
    def modified_convexity(self, spread):
        '''
        :param spread: A rate based generel spread. Default is 0.0 ie no spread
        :type spread: A float between 0 and 1
        :return: modified_convexity for the DateFlow and time valuation
            parameters given at instantiation

        *Formula for macauley_convexity:*

        .. math::
             macauley \\textunderscore convexity &= \\frac {1}
             {NPV \\left( spread \\right)} \\cdot \\frac
             {\\partial ^{2} NPV \\left( spread \\right)}
             {\\partial spread ^{2}}\\\\
                  &= \\frac {1}{NPV \\left( spread \\right)}\\cdot npv\\_d2

        .. note::
            Actually when no discountcurve is used the spread can be used to
            implement the discountcurve with constant discountfactor for each
            future period of fixed length.
        '''
        if self.__nonzero__():
            spread = to_decimal(spread)
            npv = self.npv_value(spread)
            if spread and npv:
                return self.npv_d2(spread) / npv
Example #4
0
 def _act_act_isda_fraction(self, date):
     '''Implement daycount method Act/Act ISDA
     '''
     date = BankDate(date)
     if date and date > self._valuation_date:
         date_year = date.year
         days_in_year = to_decimal(366 if isleap(date.year) else 365)
         days_in_valuation_year = to_decimal(
             366 if isleap(self._valuation_date.year) else 365)
         if self._valuation_date.year == date.year:
             return self._valuation_date.nbr_of_days(date) \
                     / days_in_valuation_year
         else:
             mid_day = BankDate('%s-01-01' % date_year)
             return self._valuation_date.nbr_of_days(mid_day) \
             / days_in_valuation_year \
             + mid_day.nbr_of_days(date) / days_in_year
     else:
         return to_decimal(0)
Example #5
0
 def npv_spread(self, npv_0, precision=1e-16, max_iteration=30):
     '''
     :param npv_0: The present value of the cashflow
     :type  npv_0: Float or decimal
     :param max_iteration: The precision/tolerance for the result.
         Default is 1e-16
     :type max_iteration: Float or decimal
     :param max_iter: The maximal number of iterations. Default is 30
     :type max_iter: A positive integer
     :return: The par rate of the discounted cashflow
     '''
     npv_0 = to_decimal(npv_0)
     if npv_0:  # TODO: Valuate for a solution
         spread_func = Solver(self.npv_value, self.npv_d1, precision,
                              max_iteration)
         return spread_func(npv_0)
Example #6
0
    def npv_d2(self, spread):
        '''
        :param spread: A rate based generel spread.
        :type spread: A float between 0 and 1
        :return: Second order derivative for the DateFlow and time valuation
            parameters given at instantiation

        *Formula for npv_d2:*

        .. math::
             npv \\textunderscore d2 = \\frac{\\partial ^{2} NPV
             \\left( spread \\right)}{\\partial spread ^{2}}
        '''
        spread = to_decimal(spread)
        discounts = -self.future_times() * (-self.future_times() - 1) \
                        * (1 + spread) ** (-self.future_times() - 2)
        # discounted_values is called as a function to get vector
        # multiplication
        return self.discounted_values()(discounts)
Example #7
0
    def npv_value(self, spread):
        '''
        :param spread: A rate based generel spread.
        :type spread: A float between 0 and 1
        :param used_discountcurve: Used  discountcurve. Default is None
            ie. no discounting
        :type used_discountcurve: A discountcurve or None
        :return: npv_value for the DateFlow and time valuation parameters given
            at instantiation

        *Short hand notation for npv_value in the documentation:*

        .. math::
             NPV ( spread ) = npv \\textunderscore value ( spread )

        .. note::
            Actually when no discountcurve is used the spread can be used to
            implement the discountcurve with constant discountfactor for each
            future period of fixed length.
        '''
        # discounted_values is called as a function to get vector
        # multiplication
        spread = to_decimal(spread)
        return self.discounted_values()((1 + spread)**-self.future_times())
Example #8
0
class ClassicRiskMeasures:

    __metaclass__ = ABCMeta

    basispoint = to_decimal('0.0001')

    @abstractmethod
    def npv_value(self, spread):
        '''npv_value has to be defined before using ClassicRiskMeasures
        '''
        raise NotImplementedError

    @abstractmethod
    def npv_d1(self, spread):
        '''npv_d1 has to be defined before using ClassicRiskMeasures
        '''
        raise NotImplementedError

    @abstractmethod
    def npv_d2(self, spread):
        '''npv_d2 has to be defined before using ClassicRiskMeasures
        '''
        raise NotImplementedError

    @vector_function(1, True)
    def modified_duration(self, spread):
        '''
        :param spread: A rate based generel spread.
        :type spread: A float between 0 and 1
        :return: modified_duration for the DateFlow and time valuation
                    parameters given at instantiation

        *Formula for modified_duration:*

        .. math::
             modified \\textunderscore duration &= \\frac {1}
             {NPV \\left( spread \\right)} \\cdot
             \\frac {\\partial NPV \\left( spread \\right)}{\\partial spread}\\\\
                  &= \\frac{1}{NPV \\left( spread \\right)} \\cdot
                  npv \\textunderscore d1

        .. note::
            Actually when no discountcurve is used the spread can be used to
            implement the discountcurve with constant discountfactor for each
            future period of fixed length.
        '''
        if self.__nonzero__():
            npv = self.npv_value(spread)
            if spread and npv:
                return -self.npv_d1(spread) / npv

    @vector_function(1, True)
    def macauley_duration(self, spread):
        '''
        :param spread: A rate based generel spread. Default is 0.0 ie no spread
        :type spread: A float between 0 and 1
        :return: macauley_duration for the DateFlow and time valuation
                    parameters given at instantiation

        *Formula for macauley_duration:*

        .. math::
             macauley \\textunderscore duration &= \\frac{1}
             {NPV \\left( spread \\right) \\cdot \\left( 1 + spread \\right)}
             \\cdot \\frac {\\partial NPV \\left( spread \\right)}
             {\\partial spread}\\\\
                  &= \\frac {1}{NPV \\left( spread \\right) \\cdot
                  \\left( 1 + spread \\right)} \\cdot npv \\textunderscore d1

        .. note::
            Actually when no discountcurve is used the spread can be used to
            implement the discountcurve with constant discountfactor for each
            future period of fixed length.

        '''
        if self.__nonzero__():
            npv = self.npv_value(spread)
            if spread and npv:
                return -self.npv_d1(spread) / npv * (1 + spread)

    @vector_function(1, True)
    def modified_convexity(self, spread):
        '''
        :param spread: A rate based generel spread. Default is 0.0 ie no spread
        :type spread: A float between 0 and 1
        :return: modified_convexity for the DateFlow and time valuation
            parameters given at instantiation

        *Formula for macauley_convexity:*

        .. math::
             macauley \\textunderscore convexity &= \\frac {1}
             {NPV \\left( spread \\right)} \\cdot \\frac
             {\\partial ^{2} NPV \\left( spread \\right)}
             {\\partial spread ^{2}}\\\\
                  &= \\frac {1}{NPV \\left( spread \\right)}\\cdot npv\\_d2

        .. note::
            Actually when no discountcurve is used the spread can be used to
            implement the discountcurve with constant discountfactor for each
            future period of fixed length.
        '''
        if self.__nonzero__():
            spread = to_decimal(spread)
            npv = self.npv_value(spread)
            if spread and npv:
                return self.npv_d2(spread) / npv

    @vector_function(1, True)
    def macauley_convexity(self, spread):
        '''
        :param spread: A rate based generel spread.
        :type spread: A float between 0 and 1
        :return: macauley_convexity for the DateFlow and time valuation
            parameters given at instantiation

        *Formula for macauley_convexity:*

        .. math::
             macauley \\textunderscore convexity &= \\frac {1}
             {NPV \\left( spread \\right) \\cdot \\left( 1 + spread \\right)^{2}}
             \\cdot \\frac {\\partial ^{2} NPV \\left( spread \\right)}
             {\\partial spread ^{2}}\\\\
                &= \\frac {1}{NPV \\left( spread \\right) \\cdot
                \\left( 1 + spread \\right) ^{2}} \\cdot npv \\textunderscore d2

        .. note::
            Actually when no discountcurve is used the spread can be used to
            implement the discountcurve with constant discountfactor for each
            future period of fixed length.
        '''
        if self.__nonzero__():
            npv = self.npv_value(spread)
            if spread and npv:
                return self.npv_d2(spread) / npv * (1 + spread)**2

    @vector_function(1, True)
    def pv01(self, spread):
        '''
        :param spread: A rate based generel spread.
        :type spread: A float between 0 and 1
        :return: pv01 for the DateFlow and time valuation parameters given at
            instantiation

        *Formula for pv01:*

        .. math::
             pv01 &= \\frac {\\partial NPV \\left( spread \\right)}
             {\\partial spread}\\cdot0.0001\\\\
                &= npv \\textunderscore d1 \\left( spread \\right) \\cdot 0.0001

        This definition has the advantage that it can handle DateFlows with NPV
        near zero.

        .. note::
            Actually when no discountcurve is used the spread can be used to
            implement the discountcurve with constant discountfactor for each
            future period of fixed length.
        '''
        if self.__nonzero__():
            if spread:
                return -ClassicRiskMeasures.basispoint * self.npv_d1(spread)

    @vector_function(1, True)
    def pvbp(self, spread):
        '''
        :param spread: A rate based generel spread.
        :type spread: A float between 0 and 1
        :return: pvbp for the DateFlow and time valuation parameters given at
            instantiation

        *Formula for pvbp:*

        .. math::
             pvbp = NPV \\left( spread \\right)
             - NPV \\left( spread + 0.0001 \\right)

        This definition has the advantage that it can handle DateFlows with NPV
        near zero.

        .. note::
            Actually when no discountcurve is used the spread can be used to
            implement the discountcurve with constant discountfactor for each
            future period of fixed length.
        '''
        if self.__nonzero__():
            if spread:
                return self.npv_value(spread) \
                    - self.npv_value(spread + ClassicRiskMeasures.basispoint)