Exemple #1
0
def timevalue(cflo, marr, base_date=0, utility=None):
    """
    Computes the net value of a cashflow at time `base_date`.

    Args:
        cflo (TimeSeries, list of TimeSeries): cashflow.
        marr (TimeSeries): Minimum atractive interest rate.
        base_date (int, tuple): Time.
        utility (function): utility function

    Returns:
        net value (float, list of floats)

    >>> marr = nominal_rate([12]*5)
    >>> cflo = cashflow([100]*5, spec = (0, -200))
    >>> timevalue(cflo, marr) # doctest: +ELLIPSIS
    103.73...

    >>> timevalue(cflo, marr, 4) # doctest: +ELLIPSIS
    163.22...

    >>> timevalue(cflo, marr, base_date=0, utility=exp_utility_fun(200)) # doctest: +ELLIPSIS
    -84.15...

    >>> timevalue(cflo, marr, base_date=0, utility=log_utility_fun(210)) # doctest: +ELLIPSIS
    369092793...

    >>> timevalue(cflo, marr, base_date=0, utility=sqrt_utility_fun(210)) # doctest: +ELLIPSIS
    2998.12...

    """
    params = vars2list([cflo, marr, base_date])
    cflo = params[0]
    marr = params[1]
    base_date = params[2]
    retval = []
    for xcflo, xmarr, xbase_date in zip(cflo, marr, base_date):
        if not isinstance(xcflo, TimeSeries):
            raise TypeError("`cflo` must be a TimeSeries")
        if not isinstance(xmarr, TimeSeries):
            raise TypeError("`marr` must be a TimeSeries")
        verify_eq_time_range(xcflo, xmarr)
        netval = 0
        factor = to_discount_factor(xmarr, xbase_date)
        for time, _ in enumerate(xcflo):
            if utility is None:
                xcflo_aux = xcflo[time]
            else:
                xcflo_aux = utility(xcflo[time])
            netval += xcflo_aux * factor[time]
        if utility is not None:
            netval = utility(netval, inverse=True)
        retval.append(netval)
    if len(retval) == 1:
        return retval[0]
    return retval
Exemple #2
0
def const2curr(cflo, inflation, base_date=0):
    """Converts a cashflow of constant dollars to current dollars
    of the time `base_date`.

    Args:
        cflo (TimeSeries): A cashflow.
        inflation (TimeSeries): Inflation rate.
        base_date (int, tuple): base time.

    Returns:
        A cashflow in current money (TimeSeries)

    >>> const2curr(cflo=cashflow(const_value=[100] * 5),
    ... inflation=nominal_rate(const_value=[10, 10, 20, 20, 20])) # doctest: +NORMALIZE_WHITESPACE
    Time Series:
    Start = (0,)
    End = (4,)
    pyr = 1
    Data = (0,)   100.00
           (1,)   110.00
           (2,)   132.00
           (3,)   158.40
           (4,)   190.08


    """
    params = vars2list([cflo, inflation, base_date])
    cflo = params[0]
    inflation = params[1]
    base_date = params[2]
    retval = []
    for xcflo, xinflation, xbase_date in zip(cflo, inflation, base_date):
        if not isinstance(xcflo, TimeSeries):
            raise TypeError("cflo must be a TimeSeries object")
        if not isinstance(xinflation, TimeSeries):
            raise TypeError("inflation must be a TimeSeries object")
        verify_eq_time_range(xcflo, xinflation)
        factor = to_compound_factor(xinflation, xbase_date)
        result = xcflo.copy()
        for time, _ in enumerate(result):
            result[time] *= factor[time]
        retval.append(result)
    if len(retval) == 1:
        return retval[0]
    return retval
Exemple #3
0
def curr2const(cflo, inflation, base_date=0):
    """Converts a cashflow of current dollars to constant dollars of
    the time `t0`.

    Args:
        cflo (list, Cashflow): A cashflow.
        inflation_rate (float, Rate): Inflation rate.
        t0 (int): base time.

    Returns:
        A cashflow in constant dollars

    >>> curr2const(cflo=cashflow(const_value=[100] * 5),
    ... inflation=nominal_rate(const_value=[10, 10, 20, 20, 20])) # doctest: +NORMALIZE_WHITESPACE
    Time Series:
    Start = (0,)
    End = (4,)
    pyr = 1
    Data = (0,)   100.00
           (1,)    90.91
           (2,)    75.76
           (3,)    63.13
           (4,)    52.61

    """
    params = vars2list([cflo, inflation, base_date])
    cflo = params[0]
    inflation = params[1]
    base_date = params[2]
    retval = []
    for xcflo, xinflation, xbase_date in zip(cflo, inflation, base_date):
        if not isinstance(xcflo, TimeSeries):
            raise TypeError("cflo must be a TimeSeries object")
        if not isinstance(xinflation, TimeSeries):
            raise TypeError("inflation must be a TimeSeries object")
        verify_eq_time_range(xcflo, xinflation)
        factor = to_discount_factor(xinflation, xbase_date)
        result = xcflo.copy()
        for time, _ in enumerate(result):
            result[time] *= factor[time]
        retval.append(result)
    if len(retval) == 1:
        return retval[0]
    return retval
Exemple #4
0
def currency_conversion(cflo, exchange_rate=1, devaluation=None, base_date=0):
    """Converts a cashflow of dollars to another currency.

    Args:
        cflo (TimeSeries): A cashflow.
        exchange_rate (float): Exchange rate at time `base_date`.
        devaluaton (TimeSeries): Devaluation rate.
        base_date (int): Time.

    Returns:
        A cashflow in other currency.




    """
    params = vars2list([cflo, exchange_rate, devaluation, base_date])
    cflo = params[0]
    exchange_rate = params[1]
    devaluation = params[2]
    base_date = params[3]
    retval = []
    for xcflo, xexchange_rate, xdevaluation, xbase_date in zip(
            cflo, exchange_rate, devaluation, base_date):
        if not isinstance(xcflo, TimeSeries):
            raise TypeError("`cashflow` must be a TimeSeries")
        if xdevaluation is None:
            result = xcflo.copy()
            for time, _ in enumerate(result):
                result[time] *= xexchange_rate
        else:
            if not isinstance(xdevaluation, TimeSeries):
                raise TypeError("`devaluation` must be a TimeSeries")
            verify_eq_time_range(xcflo, xdevaluation)
            factor = to_compound_factor(xdevaluation, xbase_date)
            result = xcflo.copy()
            for time, _ in enumerate(result):
                result[time] *= xexchange_rate * factor[time]
        retval.append(result)
    if len(retval) == 1:
        return retval[0]
    return retval
Exemple #5
0
def after_tax_cashflow(cflo, tax_rate):
    """Computes the after cashflow for a tax rate. Taxes are not computed
    for negative values in the cashflow.

    Args:
        cflo (TimeSeries): generic cashflow.
        tax_rate (TimeSeries): income tax rate.

    Returns:
        TimeSeries objects with taxed values


    >>> cflo = cashflow(const_value=[100] * 5, spec=(0, -100))
    >>> tax_rate = nominal_rate(const_value=[10] * 5)
    >>> after_tax_cashflow(cflo=cflo, tax_rate=tax_rate) # doctest: +NORMALIZE_WHITESPACE
    Time Series:
    Start = (0,)
    End = (4,)
    pyr = 1
    Data = (0,)           0.00
           (1,)-(4,) [4] 10.00

    """
    params = vars2list([cflo, tax_rate])
    cflo = params[0]
    tax_rate = params[1]
    retval = []
    for xcflo, xtax_rate in zip(cflo, tax_rate):
        if not isinstance(xcflo, TimeSeries):
            raise TypeError("cashflow must be a TimeSeries")
        verify_eq_time_range(xcflo, xtax_rate)
        result = xcflo.copy()
        for time, _ in enumerate(xcflo):
            if result[time] > 0:
                result[time] *= xtax_rate[time] / 100
            else:
                result[time] = 0
        retval.append(result)
    if len(retval) == 1:
        return retval[0]
    return retval
def depreciation_sl(costs, life, salvalue=None, delay=None, noprint=True):
    """Computes the depreciation of an asset using straight line depreciation
    method.

    Args:
        cost (TimeSeries): the cost per period of the assets.
        life (TimeSeries): number of depreciation periods for the asset.
        salvalue(TimeSeries): salvage value as a percentage of cost.
        noprint (bool): when True, the procedure prints a depreciation table.

    Returns:
        depreciation, accum_depreciation (TimeSeries, TimeSeries).

    """
    verify_eq_time_range(costs, life)
    if salvalue is not None:
        verify_eq_time_range(costs, salvalue)
    else:
        salvalue = [0] * len(costs)
    if delay is not None:
        verify_eq_time_range(costs, delay)
    else:
        delay = [0] * len(costs)

    depr = [0] * len(costs)
    adepr = [0] * len(costs)
    begbook = [0] * len(costs)
    endbook = [0] * len(costs)

    for index, _ in enumerate(costs):
        if costs[index] == 0:
            continue
        if delay[index] == 0:
            ValueError('Depreciation with delay 0')
        xdepr = [(costs[index] *
                  (100 - salvalue[index]) / 100) / life[index]] * life[index]
        for time in range(life[index]):
            if index + time + delay[index] + 1 < len(costs):
                depr[index + time + delay[index] + 1] += xdepr[time]
            else:
                break

    for time, _ in enumerate(depr):
        if time > 0:
            adepr[time] = adepr[time - 1] + depr[time]
        else:
            adepr[time] = depr[time]

    for time, _ in enumerate(depr):
        if time > 0:
            begbook[time] = endbook[time - 1]
        endbook[time] = begbook[time] - depr[time] + costs[time]

    if noprint is True:
        retval = costs.copy()
        for index, _ in enumerate(costs):
            retval[index] = depr[index]
        return retval

    print_depr(depr, adepr, costs, begbook, endbook)
Exemple #7
0
def benefit_cost_ratio(cflo, marr, base_date=0):
    """
    Computes a benefit cost ratio at time `base_date` of a cashflow.

    Args:
        rate (int float, Rate): Minimum atractive interest rate.
        cashflow (cashflow, list): cashflow.
        base_date (int, list): Time.

    Returns:
        (float) net present value.

    """

    params = vars2list([marr, cflo, base_date])
    marr = params[0]
    cflo = params[1]
    base_date = params[2]

    retval = []
    for xmarr, xcflo, xbase_date in zip(marr, cflo, base_date):
        verify_eq_time_range(xcflo, xmarr)
        num = 0
        den = 0
        num = xcflo.copy()
        den = xcflo.copy()
        for time, _ in enumerate(xcflo):
            if xcflo[time] >= 0.0:
                den[time] = 0
            else:
                num[time] = 0
        retval.append(-timevalue(num, xmarr, xbase_date) /
                      timevalue(den, xmarr, xbase_date))

    if len(retval) == 1:
        return retval[0]
    return retval
def depreciation_soyd(costs, life, salvalue=None, delay=None, noprint=True):
    """Computes the depreciation of an asset using the sum-of-year's-digits
    method.

    Args:
        cost (TimeSeries): the cost per period of the assets.
        life (TimeSeries): number of depreciation periods for the asset.
        salvalue(TimeSeries): salvage value as a percentage of cost.
        noprint (bool): when True, the procedure prints a depreciation table.

    Returns:
        A tuple (dep, accum) of lists (tuple): depreciation per period and accumulated depreciation per period

    """
    verify_eq_time_range(costs, life)
    if salvalue is not None:
        verify_eq_time_range(costs, salvalue)
    else:
        salvalue = [0] * len(costs)
    if delay is not None:
        verify_eq_time_range(costs, delay)
    else:
        delay = [0] * len(costs)

    depr = [0] * len(costs)
    adepr = [0] * len(costs)
    begbook = [0] * len(costs)
    endbook = [0] * len(costs)

    for index, _ in enumerate(costs):
        sumdig = life[index] * (life[index] + 1) / 2
        xdepr = [(costs[index] * (100 - salvalue[index]) / 100) *
                 (life[index] - time) / sumdig for time in range(life[index])]
        for time in range(life[index]):
            if index + time + delay[index] + 1 < len(costs):
                depr[index + time + delay[index] + 1] += xdepr[time]
            else:
                break

    for time, _ in enumerate(depr):
        if time > 0:
            adepr[time] = adepr[time - 1] + depr[time]
        else:
            adepr[time] = depr[time]

    for time, _ in enumerate(depr):
        if time > 0:
            begbook[time] = endbook[time - 1]
        endbook[time] = begbook[time] - depr[time] + costs[time]

    if noprint is True:
        retval = costs.copy()
        for index, _ in enumerate(costs):
            retval[index] = depr[index]
        return retval

    print_depr(depr, adepr, costs, begbook, endbook)
Exemple #9
0
def fixed_ppal_loan(amount,
                    nrate,
                    grace=0,
                    dispoints=0,
                    orgpoints=0,
                    prepmt=None,
                    balloonpmt=None):
    """Loan with fixed principal payment.

    """
    #pylint: disable-msg=too-many-arguments

    if not isinstance(nrate, TimeSeries):
        TypeError('nrate must be a TimeSeries object.')

    if prepmt is None:
        prepmt = cashflow(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    else:
        verify_eq_time_range(nrate, prepmt)

    if balloonpmt is None:
        balloonpmt = cashflow(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    else:
        verify_eq_time_range(nrate, balloonpmt)

    # present value of the balloon payments
    balloonpv = sum(balloonpmt)

    life = len(nrate) - grace - 1

    begppalbal = TimeSeries(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    intpmt = TimeSeries(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    ppalpmt = TimeSeries(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    totpmt = TimeSeries(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    endppalbal = TimeSeries(start=nrate.start, end=nrate.end, pyr=nrate.pyr)

    pmt = (amount - balloonpv) / life  # periodic ppal payment

    # balance calculation
    for time in range(grace + life + 1):

        if time == 0:
            begppalbal[time] = 0
            endppalbal[time] = amount - prepmt[time]
            totpmt[time] = amount * (dispoints + orgpoints)
            intpmt[time] = amount * dispoints
        else:
            begppalbal[time] = endppalbal[time - 1]
            intpmt[time] = begppalbal[time] * nrate[time] / nrate.pyr / float(
                100)
            if time <= grace:
                ppalpmt[time] = prepmt[time] + balloonpmt[time]
            else:
                ppalpmt[time] = pmt + prepmt[time] + balloonpmt[time]
            totpmt[time] = intpmt[time] + ppalpmt[time]
            endppalbal[time] = begppalbal[time] - ppalpmt[time]

            if endppalbal[time] < 0:
                totpmt[time] = begppalbal[time] + intpmt[time]
                ppalpmt[time] = begppalbal[time]
                endppalbal[time] = begppalbal[time] - ppalpmt[time]
                prepmt[time] = 0
                pmt = 0

    ## resuls
    result = Loan()
    result.life = life
    result.nrate = nrate
    result.grace = grace
    result.amount = amount
    result.begppalbal = begppalbal
    result.totpmt = totpmt
    result.intpmt = intpmt
    result.ppalpmt = ppalpmt
    result.endppalbal = endppalbal

    return result
Exemple #10
0
def buydown_loan(amount,
                 nrate,
                 grace=0,
                 dispoints=0,
                 orgpoints=0,
                 prepmt=None):
    """
    Buydown loan


    """

    if not isinstance(nrate, TimeSeries):
        TypeError('nrate must be a TimeSeries object.')

    if prepmt is None:
        prepmt = cashflow(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    else:
        verify_eq_time_range(nrate, prepmt)

    life = len(nrate) - grace - 1

    begppalbal = TimeSeries(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    intpmt = TimeSeries(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    ppalpmt = TimeSeries(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    totpmt = TimeSeries(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    endppalbal = TimeSeries(start=nrate.start, end=nrate.end, pyr=nrate.pyr)

    if prepmt is None:
        prepmt = cashflow(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    else:
        verify_eq_time_range(nrate, prepmt)

    ##
    ## balance calculation
    ##
    for time in range(grace + life + 1):

        if time == 0:
            #
            begppalbal[time] = amount
            endppalbal[time] = amount
            totpmt[time] = amount * (dispoints + orgpoints)
            intpmt[time] = amount * dispoints
            #
        else:
            #
            # periodic payment per period
            #
            if time <= grace:

                begppalbal[time] = endppalbal[time - 1]
                intpmt[time] = begppalbal[time] * nrate[time] / nrate.pyr / 100
                totpmt[time] = intpmt[time]
                endppalbal[time] = begppalbal[time]

            else:

                pmt = -pvpmt(nrate=nrate[time],
                             nper=grace + life - time + 1,
                             pval=endppalbal[time - 1],
                             pmt=None,
                             pyr=nrate.pyr)

                totpmt[time] = pmt + prepmt[time]

                # balance
                begppalbal[time] = endppalbal[time - 1]
                intpmt[time] = begppalbal[time] * nrate[time] / nrate.pyr / 100
                ppalpmt[time] = totpmt[time] - intpmt[time]
                endppalbal[time] = begppalbal[time] - ppalpmt[time]

    ## resuls
    result = Loan()
    result.nrate = nrate
    result.life = life
    result.grace = grace
    result.amount = amount
    result.begppalbal = begppalbal
    result.totpmt = totpmt
    result.intpmt = intpmt
    result.ppalpmt = ppalpmt
    result.endppalbal = endppalbal

    return result
Exemple #11
0
def fixed_rate_loan(amount,
                    nrate,
                    life,
                    start,
                    pyr=1,
                    grace=0,
                    dispoints=0,
                    orgpoints=0,
                    prepmt=None,
                    balloonpmt=None):
    """Fixed rate loan

    """
    if not isinstance(float(nrate), float):
        TypeError('nrate must be a float.')

    nrate = nominal_rate(const_value=nrate,
                         start=start,
                         nper=life + grace + 1,
                         pyr=pyr)

    if prepmt is None:
        prepmt = cashflow(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    else:
        verify_eq_time_range(nrate, prepmt)

    if balloonpmt is None:
        balloonpmt = cashflow(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    else:
        verify_eq_time_range(nrate, balloonpmt)

    # present value of the balloon payments
    if balloonpmt is not None:
        balloonpv = timevalue(cflo=balloonpmt, marr=nrate, base_date=grace)
    else:
        balloonpv = 0

    pmt = pvpmt(pmt=None,
                pval=-amount + balloonpv,
                nrate=nrate[0],
                nper=len(nrate) - 1,
                pyr=nrate.pyr)
    pmts = cashflow(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    for time in range(1, life + 1):
        pmts[grace + time] = pmt

    # balance
    begppalbal = TimeSeries(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    intpmt = TimeSeries(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    ppalpmt = TimeSeries(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    totpmt = TimeSeries(start=nrate.start, end=nrate.end, pyr=nrate.pyr)
    endppalbal = TimeSeries(start=nrate.start, end=nrate.end, pyr=nrate.pyr)

    # payments per period
    for time, _ in enumerate(totpmt):
        totpmt[time] = pmts[time] + balloonpmt[time] + prepmt[time]

    # balance calculation
    for time in range(grace + life + 1):

        if time == 0:
            begppalbal[0] = amount
            endppalbal[0] = amount
            totpmt[time] = amount * (dispoints + orgpoints)
            intpmt[time] = amount * dispoints
        else:
            begppalbal[time] = endppalbal[time - 1]
            if time <= grace:
                intpmt[time] = begppalbal[time] * nrate[time] / nrate.pyr / 100
                totpmt[time] = intpmt[time]
                endppalbal[time] = begppalbal[time]
            else:
                intpmt[time] = begppalbal[time] * nrate[time] / nrate.pyr / 100
                ppalpmt[time] = totpmt[time] - intpmt[time]
                if ppalpmt[time] < 0:
                    capint = -ppalpmt[time]
                    ppalpmt[time] = 0
                else:
                    capint = 0
                endppalbal[time] = begppalbal[time] - ppalpmt[time] + capint
                if endppalbal[time] < 0:
                    totpmt[time] = begppalbal[time] + intpmt[time]
                    ppalpmt[time] = begppalbal[time]
                    endppalbal[time] = begppalbal[time] - ppalpmt[time]
                    pmts[time] = 0
                    prepmt[time] = 0

    result = Loan()
    result.life = life
    result.nrate = nrate
    result.grace = grace
    result.amount = amount
    result.begppalbal = begppalbal
    result.totpmt = totpmt
    result.intpmt = intpmt
    result.ppalpmt = ppalpmt
    result.endppalbal = endppalbal

    return result
Exemple #12
0
def depreciation_db(costs,
                    life,
                    salvalue=None,
                    factor=1,
                    convert_to_sl=True,
                    delay=None,
                    noprint=True):
    """Computes the depreciation of an asset using the declining balance
    method.

    Args:
        ccost (TimeSeries): the cost per period of the assets.
        life (TimeSeries): number of depreciation periods for the asset.
        salvalue(TimeSeries): salvage value as a percentage of cost.
        factor (float): acelerating factor for depreciation.
        convert_to_sl (bool): converts to straight line method?
        noprint (bool): when True, the procedure prints a depreciation table.

    Returns:
        A tuple (dep, accum) of lists (tuple): depreciation per period and accumulated depreciation per period


    """

    verify_eq_time_range(costs, life)
    if salvalue is not None:
        verify_eq_time_range(costs, salvalue)
    else:
        salvalue = [0] * len(costs)
    if delay is not None:
        verify_eq_time_range(costs, delay)
    else:
        delay = [0] * len(costs)
    if not isinstance(factor, (int, float)):
        raise TypeError('Invalid type for `factor`')
    if not isinstance(convert_to_sl, bool):
        raise TypeError('Invalid type for `convert_to_sl`')

    depr = [0] * len(costs)
    adepr = [0] * len(costs)
    begbook = [0] * len(costs)
    endbook = [0] * len(costs)

    for index, _ in enumerate(costs):

        if costs[index] == 0:
            continue

        xfactor = factor / life[index]

        rem_cost = costs[index]
        xdepr = [0] * life[index]

        sl_depr = (costs[index] - salvalue[index]) / life[index]

        for time in range(life[index]):
            xdepr[time] = rem_cost * xfactor
            if convert_to_sl is True and xdepr[time] < sl_depr:
                xdepr[time] = sl_depr
            rem_cost -= xdepr[time]
            if rem_cost < salvalue[index]:
                rem_cost += xdepr[time]
                xdepr[time] = rem_cost - salvalue[index]
                rem_cost = salvalue[index]

        for time in range(life[index]):
            if index + time + delay[index] + 1 < len(costs):
                depr[index + time + delay[index] + 1] += xdepr[time]
            else:
                break

    for time, _ in enumerate(depr):
        if time > 0:
            adepr[time] = adepr[time - 1] + depr[time]
        else:
            adepr[time] = depr[time]

    for time, _ in enumerate(depr):
        if time > 0:
            begbook[time] = endbook[time - 1]
        endbook[time] = begbook[time] - depr[time] + costs[time]

    if noprint is True:
        retval = costs.copy()
        for index, _ in enumerate(costs):
            retval[index] = depr[index]
        return retval

    print_depr(depr, adepr, costs, begbook, endbook)
Exemple #13
0
def savings(deposits, rate, initbal=0, noprint=True):
    """
    Computes the final balance for a savings account with arbitrary deposits and
    withdrawls and variable interset rate.

    Args:
        deposits (TimeSeries): deposits to the account.
        rate (TimeSeries): interest rate paid by the account.
        initbal (float): initial balance of the account.
        noprint (bool): prints summary report?

    Return:
        interest, end_balance (TimeSeries, TimeSeries)

    """
    verify_eq_time_range(deposits, rate)

    begbal = deposits.copy()
    interest = deposits.copy()
    endbal = deposits.copy()

    for time, _ in enumerate(deposits):
        if time == 0:
            begbal[0] = initbal
            interest[0] = begbal[0] * rate[0] / 100 / rate.pyr
            endbal[0] = begbal[0] + deposits[0] + interest[0]
        else:
            begbal[time] = endbal[time - 1]
            interest[time] = begbal[time] * rate[time] / 100 / rate.pyr
            if deposits[time] < 0 and -deposits[time] > begbal[
                    time] + interest[time]:
                deposits[time] = -(begbal[time] + interest[time])
            endbal[time] = begbal[time] + deposits[time] + interest[time]

    if noprint is True:
        return (interest, endbal)

    len_timeid = len(deposits.end.__repr__())
    len_number = max(len('{:1.2f}'.format(endbal[-1])),
                     len('{:1.2f}'.format(begbal[0])), 9)

    fmt_timeid = '{:<' + '{:d}'.format(len_timeid) + 's}'
    fmt_number = ' {:' + '{:d}'.format(len_number) + '.2f}'
    fmt_header = ' {:>' + '{:d}'.format(len_number) + 's}'

    if deposits.pyr == 1:
        xmajor, = deposits.start
        xminor = 0
    else:
        xmajor, xminor = deposits.start

    txt = []
    header = fmt_timeid.format('t')
    header += fmt_header.format('Beginning')
    header += fmt_header.format('Deposit')
    header += fmt_header.format('Earned')
    header += fmt_header.format('Ending')
    txt.append(header)

    header = fmt_timeid.format('')
    header += fmt_header.format('Balance')
    header += fmt_header.format('')
    header += fmt_header.format('Interest')
    header += fmt_header.format('Balance')
    txt.append(header)

    txt.append('-' * len_timeid + '-----' + '-' * len_number * 4)

    for time, _ in enumerate(deposits):
        if deposits.pyr == 1:
            timeid = (xmajor, )
        else:
            timeid = (xmajor, xminor)
        fmt = fmt_timeid + fmt_number * 4
        txt.append(
            fmt.format(timeid.__repr__(), begbal[time], deposits[time],
                       interest[time], endbal[time]))
        if deposits.pyr == 1:
            xmajor += 1
        else:
            xminor += 1
            if xminor == deposits.pyr:
                xminor = 0
                xmajor += 1

    print('\n'.join(txt))