示例#1
0
 def series_generator(rate,
                      nbr_of_payments=1,
                      start_date=BankDate(),
                      step='1y'):
     '''Series'''
     discount = 1 / (1 + rate)
     nominal = 0.0
     nominal_step = 100.0 / abs(nbr_of_payments)
     for payday in daterange_iter(nbr_of_payments, start_date, step, False):
         rate = (nominal + nominal_step) * (1 / discount - 1)
         yield {
             'payday': payday,
             'nominal': nominal,
             'payment': nominal_step + rate,
             'rate': rate
         }
         nominal += nominal_step
     if nbr_of_payments > 0:
         yield {
             'payday': start_date,
             'nominal': nominal,
             'payment': 0.0,
             'rate': 0.0
         }
     else:
         yield {
             'payday': payday - step,
             'nominal': 100.0,
             'payment': 0.0,
             'rate': 0.0
         }
示例#2
0
 def bullit_generator(rate,
                      nbr_of_payments=1,
                      start_date=BankDate(),
                      step='1y'):
     '''A bullit'''
     discount = 1 / (1 + rate)
     payment = 100 / discount
     nominal = 0.0
     rate = payment - 100
     for payday in daterange_iter(nbr_of_payments, start_date, step, False):
         yield {
             'payday': payday,
             'nominal': nominal,
             'payment': payment,
             'rate': rate
         }
         if not nominal:
             nominal, payment = 100.0, rate
     if nbr_of_payments > 0:
         yield {
             'payday': start_date,
             'nominal': nominal,
             'payment': 0.0,
             'rate': 0.0
         }
     else:
         yield {
             'payday': payday - step,
             'nominal': 100.0,
             'payment': 0.0,
             'rate': 0.0
         }
示例#3
0
 def find_nearest_bankdate(self, keyvalue, before=True):
     '''
     :param keyvalue: A date
     :type keyvalue: A bankdate, a string in format yyyy-mm-dd or a date
     :param before: if True return nearest date before keyvalue
                    otherwise the nearest after
     :type before: boolean
     :Return: The nearest date in DateFlow (before if before is True
              otherwise the nearest after) keyvalue.
     '''
     if self.keys() and keyvalue:
         keyvalue = BankDate(keyvalue)
         if keyvalue in self.keys():
             return keyvalue
         else:
             lst = self.keys()
             lst.append(keyvalue)
             lst.sort()
             index = lst.index(keyvalue)
             if 0 < index < len(lst) - 1:
                 if before:
                     return lst[index - 1]
                 else:
                     return lst[index + 1]
             elif index == 0:
                 if before:
                     return
                 else:
                     return lst[1]
             else:
                 if before:
                     return lst[-2]
                 else:
                     return
示例#4
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)
示例#5
0
 def __call__(self, date):
     '''Returns the adjusted input date converted to time according to time
     convertion settings.
     Input is date as BankDate
     '''
     bdate = BankDate(date)
     nbr_years = self._valuation_date.nbr_of_years(bdate)
     newdate = bdate.add_years(-nbr_years)
     return nbr_years + self._daycount_method(newdate)
示例#6
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)
示例#7
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)
示例#8
0
 def annuity_generator(rate,
                       nbr_of_payments=1,
                       start_date=BankDate(),
                       step='1y'):
     '''annuity'''
     discount = 1 / (1 + rate)
     if nbr_of_payments > 0:
         payment = 100 * rate / (1.0 - discount**nbr_of_payments)
     else:
         payment = 100 * (1.0 / discount - 1) \
                     / (1.0 - discount ** -nbr_of_payments)
     accumulated_discount = 1.0
     nominal = 0.0
     for payday in daterange_iter(nbr_of_payments, start_date, step, False):
         accumulated_discount *= discount
         yield {
             'payday': payday,
             'nominal': nominal,
             'payment': payment,
             'rate': payment * (1 - accumulated_discount)
         }
         nominal += payment * accumulated_discount
     if nbr_of_payments > 0:
         yield {
             'payday': start_date,
             'nominal': nominal,
             'payment': 0.0,
             'rate': 0.0
         }
     else:
         yield {
             'payday': payday - step,
             'nominal': 100.0,
             'payment': 0.0,
             'rate': 0.0
         }
示例#9
0
 def __init__(self, daycount_method='act/365', valuation_date=BankDate()):
     self.set_daycount_method(daycount_method)
     self.set_valuation_date(valuation_date)
示例#10
0
 def set_valuation_date(self, valuation_date):
     '''Reset or set valuation day
     '''
     self._valuation_date = BankDate(valuation_date)
示例#11
0
def dateflow_generator(rate,
                       enddate_or_integer=1,
                       start_date=BankDate(),
                       step='1y',
                       cashflowtype='Annuity',
                       profile='payment'):
    '''A generator of standard DateFlows.

    Steps step backwards from end_date. If enddate_or_integer is an integer

    end_date is calculated as start_date + enddate_or_integer * step

    The dateflow_generator is build upon the datarangeiter.

    :param rate: Fixed rate pr period.
    :type rate: float or decimal
    :param enddate_or_integer: Either end_date or number of dates in daterange
    :type enddate_or_integer: A date or integer
    :param start_date: start_date for daterange iterations.
        Default is current date
    :type start_date: A date
    :param step: The time period between 2 adjacent dates
    :type step: A timeperiod
    :param keepstart_date: Should start_date be in daterange or not
    :type keepstart_date: Boolean
    :param cashflowtype: Name of cashflow type. Default is 'annuity'
    :type cashflowtype: ('annuity', 'bullit, 'series')
    :param profile: Name of cashflow profile. Default is 'payment'
    :type profile: ('payment', 'nominal', 'rate')
    :param keepstart_date: Should start_date be in the list. Default is True
    :type keepstart_date: boolean

    Create payments of an annuity with nominal 100, a rate of 10% and 5 yearly
    payments starting from 2009-11-24.

    Default:
        step = '1y',  cashflowtype = 'Annuity', profile = 'payment'

    >>> dateflow_generator(0.1, 5, '2009-11-24')
    Data for the DateFlow:
    * key: 2009-11-24, value: 0.0
    * key: 2010-11-24, value: 26.3797480795
    * key: 2011-11-24, value: 26.3797480795
    * key: 2012-11-24, value: 26.3797480795
    * key: 2013-11-24, value: 26.3797480795
    * key: 2014-11-24, value: 26.3797480795

    DateFlow can also be generated from the future and back:

    >>> dateflow_generator(0.1, -5, '2014-11-24')
    Data for the DateFlow:
    * key: 2009-11-24, value: 0.0
    * key: 2010-11-24, value: 26.3797480795
    * key: 2011-11-24, value: 26.3797480795
    * key: 2012-11-24, value: 26.3797480795
    * key: 2013-11-24, value: 26.3797480795
    * key: 2014-11-24, value: 26.3797480795

    Several DateFlows can be uptained.
    Below are the nominals of an annuity (default):

    >>> dateflow_generator(0.1, 5, '2009-11-24', profile = 'nominal')
    Data for the DateFlow:
    * key: 2009-11-24, value: 100.0
    * key: 2010-11-24, value: 83.6202519205
    * key: 2011-11-24, value: 65.6025290331
    * key: 2012-11-24, value: 45.7830338569
    * key: 2013-11-24, value: 23.9815891632
    * key: 2014-11-24, value: 0.0

    And the rates of of an annuity (default):

    >>> dateflow_generator(0.1, 5, '2009-11-24', profile = 'rate')
    Data for the DateFlow:
    * key: 2009-11-24, value: 0.0
    * key: 2010-11-24, value: 10.0
    * key: 2011-11-24, value: 8.36202519205
    * key: 2012-11-24, value: 6.56025290331
    * key: 2013-11-24, value: 4.57830338569
    * key: 2014-11-24, value: 2.39815891632

    Create the payments of a bullit with nominal 100, a rate of 10% and 5 yearly
    payments starting from 2009-11-24.

    Default:
        step = '1y', profile = 'payment', keepstart_date = False.

    >>> dateflow_generator(0.1, 5, '2009-11-24', cashflowtype= 'bullit')
    Data for the DateFlow:
    * key: 2009-11-24, value: 0.0
    * key: 2010-11-24, value: 10.0
    * key: 2011-11-24, value: 10.0
    * key: 2012-11-24, value: 10.0
    * key: 2013-11-24, value: 10.0
    * key: 2014-11-24, value: 110.0

    Create the payments a series with nominal 100, a rate of 10% and 5 yearly
    payments starting from 2009-11-24.

    Default:
        step = '1y', profile = 'payment', keepstart_date = False.

    >>> dateflow_generator(0.1, 5, BankDate('2009-11-24'), cashflowtype= 'series')
    Data for the DateFlow:
    * key: 2009-11-24, value: 0.0
    * key: 2010-11-24, value: 30.0
    * key: 2011-11-24, value: 28.0
    * key: 2012-11-24, value: 26.0
    * key: 2013-11-24, value: 24.0
    * key: 2014-11-24, value: 22.0

    [Christensen]_ table 2.3 page 30, payments:

    >>> dateflow_generator(0.035, '2004-07-01', '2001-01-01', '6m', 'annuity', 'payment')
    Data for the DateFlow:
    * key: 2001-01-01, value: 0.0
    * key: 2001-07-01, value: 16.3544493783
    * key: 2002-01-01, value: 16.3544493783
    * key: 2002-07-01, value: 16.3544493783
    * key: 2003-01-01, value: 16.3544493783
    * key: 2003-07-01, value: 16.3544493783
    * key: 2004-01-01, value: 16.3544493783
    * key: 2004-07-01, value: 16.3544493783

    [Christensen]_ table 2.3 page 30, rates:

    >>> dateflow_generator(0.035, '2004-07-01', '2001-01-01', '6m', 'annuity', 'rate')
    Data for the DateFlow:
    * key: 2001-01-01, value: 0.0
    * key: 2001-07-01, value: 3.5
    * key: 2002-01-01, value: 3.05009427176
    * key: 2002-07-01, value: 2.58444184303
    * key: 2003-01-01, value: 2.10249157929
    * key: 2003-07-01, value: 1.60367305633
    * key: 2004-01-01, value: 1.08739588506
    * key: 2004-07-01, value: 0.553049012794

    [Christensen]_ table 2.3 page 30, nominals:

    >>> dateflow_generator(0.035, '2004-07-01', '2001-01-01', '6m', 'annuity', 'nominal')
    Data for the DateFlow:
    * key: 2001-01-01, value: 100.0
    * key: 2001-07-01, value: 87.1455506217
    * key: 2002-01-01, value: 73.8411955151
    * key: 2002-07-01, value: 60.0711879798
    * key: 2003-01-01, value: 45.8192301808
    * key: 2003-07-01, value: 31.0684538588
    * key: 2004-01-01, value: 15.8014003655
    * key: 2004-07-01, value: 0.0

    '''
    def annuity_generator(rate,
                          nbr_of_payments=1,
                          start_date=BankDate(),
                          step='1y'):
        '''annuity'''
        discount = 1 / (1 + rate)
        if nbr_of_payments > 0:
            payment = 100 * rate / (1.0 - discount**nbr_of_payments)
        else:
            payment = 100 * (1.0 / discount - 1) \
                        / (1.0 - discount ** -nbr_of_payments)
        accumulated_discount = 1.0
        nominal = 0.0
        for payday in daterange_iter(nbr_of_payments, start_date, step, False):
            accumulated_discount *= discount
            yield {
                'payday': payday,
                'nominal': nominal,
                'payment': payment,
                'rate': payment * (1 - accumulated_discount)
            }
            nominal += payment * accumulated_discount
        if nbr_of_payments > 0:
            yield {
                'payday': start_date,
                'nominal': nominal,
                'payment': 0.0,
                'rate': 0.0
            }
        else:
            yield {
                'payday': payday - step,
                'nominal': 100.0,
                'payment': 0.0,
                'rate': 0.0
            }

    def bullit_generator(rate,
                         nbr_of_payments=1,
                         start_date=BankDate(),
                         step='1y'):
        '''A bullit'''
        discount = 1 / (1 + rate)
        payment = 100 / discount
        nominal = 0.0
        rate = payment - 100
        for payday in daterange_iter(nbr_of_payments, start_date, step, False):
            yield {
                'payday': payday,
                'nominal': nominal,
                'payment': payment,
                'rate': rate
            }
            if not nominal:
                nominal, payment = 100.0, rate
        if nbr_of_payments > 0:
            yield {
                'payday': start_date,
                'nominal': nominal,
                'payment': 0.0,
                'rate': 0.0
            }
        else:
            yield {
                'payday': payday - step,
                'nominal': 100.0,
                'payment': 0.0,
                'rate': 0.0
            }

    def series_generator(rate,
                         nbr_of_payments=1,
                         start_date=BankDate(),
                         step='1y'):
        '''Series'''
        discount = 1 / (1 + rate)
        nominal = 0.0
        nominal_step = 100.0 / abs(nbr_of_payments)
        for payday in daterange_iter(nbr_of_payments, start_date, step, False):
            rate = (nominal + nominal_step) * (1 / discount - 1)
            yield {
                'payday': payday,
                'nominal': nominal,
                'payment': nominal_step + rate,
                'rate': rate
            }
            nominal += nominal_step
        if nbr_of_payments > 0:
            yield {
                'payday': start_date,
                'nominal': nominal,
                'payment': 0.0,
                'rate': 0.0
            }
        else:
            yield {
                'payday': payday - step,
                'nominal': 100.0,
                'payment': 0.0,
                'rate': 0.0
            }

    # Main dateflow_generator
    if not 0 < rate < 1:
        raise DateFlowError, 'Rate (%s) must be a float between 0 and 1' \
            % rate
    cashflowdict = {
        'annuity': annuity_generator,
        'bullit': bullit_generator,
        'series': series_generator
    }
    if cashflowtype.lower() in cashflowdict.keys():
        if isinstance(enddate_or_integer, int):
            nbr_of_payments = enddate_or_integer
        else:
            nbr_of_payments = period_count(enddate_or_integer, start_date,
                                           step)
        generator = cashflowdict[cashflowtype.lower()] \
                    (rate, nbr_of_payments, start_date, step)
    else:
        raise DateFlowError, \
        'Cashflowtype (%s) must be one of %s' \
        % (cashflowtype.lower(), cashflowdict.keys())
    profilelst = ('nominal', 'payment', 'rate')
    if profile.lower() in profilelst:
        return sum(
            DateFlow({row['payday']: row[profile.lower()]})
            for row in generator)
    else:
        raise DateFlowError, \
        'Profile (%s) must be one of %s' % (profile.lower(), profilelst)
示例#12
0
 def __validate_key__(key):
     return BankDate(key)