Skip to content
Snippets Groups Projects
test_data_finance.py 46.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
    
            for year_index in range(investment_period + 1):
                net_cash_flows[year_index] = 0
    
            npv_inv_horizon = npv(
                discount_rates=discount_rates[0:analysis_period_span],
                net_cash_flows=net_cash_flows[0 : analysis_period_span + 1],
            )
    
            assert math.isclose(npv_inv_horizon, 1e6, abs_tol=1e-3)
    
            # *********************************************************************
    
            # net present value for the whole investment
    
            npv_asset_long = npv(
                discount_rates=discount_rates, net_cash_flows=net_cash_flows
            )
    
            assert math.isclose(npv_asset_long, 1e6, abs_tol=1e-3)
    
            # calculate discounted salvage value directly
    
            npv_salvage = present_salvage_value_annuity(
                investment=investment,
                investment_longevity=investment_longevity,
                investment_period=investment_period,
                discount_rate=discount_rate,
                analysis_period_span=analysis_period_span,
            )
    
            assert math.isclose(npv_salvage, npv_asset_long - npv_inv_horizon, abs_tol=1e-3)
    
            # salvage value, as seen from the last period
    
            und_salvage_value = salvage_value_annuity(
                investment=investment,
                discount_rate=discount_rate,
                investment_longevity=investment_longevity,
                investment_period=investment_period,
                analysis_period_span=analysis_period_span,
            )
    
            assert math.isclose(und_salvage_value, 0, abs_tol=1e-3)
    
        # *************************************************************************
        # *************************************************************************
    
        def test_scrap_value_annuity_ending_before_horizon(self):
            # Source:
            # Vejledning i samfundsøkonomiske analyser på energiområdet, juli 2021
            # Energistyrelsen, page 19
    
            investment_period = 0
    
            investment = 1e6  # 1E3 DKK
    
            investment_longevity = 15  # years
    
            analysis_period_span = 20  # years
    
            discount_rate = 0.035
    
            discount_rates = tuple(
                discount_rate for i in range(investment_longevity + investment_period)
            )
    
            # *********************************************************************
    
            # calculate the net present value with the salvage value deducted
    
            # annuity method
    
            annuity = (
                investment
                * discount_rate
                / (1 - (1 + discount_rate) ** (-investment_longevity))
            )
    
            net_cash_flows = list(
                annuity for i in range(investment_longevity + investment_period + 1)
            )
    
            for year_index in range(investment_period + 1):
                net_cash_flows[year_index] = 0
    
            npv_inv_horizon = npv(
                discount_rates=discount_rates[0:analysis_period_span],
                net_cash_flows=net_cash_flows[0 : analysis_period_span + 1],
            )
    
            assert math.isclose(npv_inv_horizon, 1e6, abs_tol=1e-3)
    
            # *********************************************************************
    
            # net present value for the whole investment
    
            npv_asset_long = npv(
                discount_rates=discount_rates, net_cash_flows=net_cash_flows
            )
    
            assert math.isclose(npv_asset_long, 1e6, abs_tol=1e-3)
    
            # calculate discounted salvage value directly
    
            npv_salvage = present_salvage_value_annuity(
                investment=investment,
                investment_longevity=investment_longevity,
                investment_period=investment_period,
                discount_rate=discount_rate,
                analysis_period_span=analysis_period_span,
            )
    
            assert math.isclose(npv_salvage, npv_asset_long - npv_inv_horizon, abs_tol=1e-3)
    
            # salvage value, as seen from the last period
    
            und_salvage_value = salvage_value_annuity(
                investment=investment,
                discount_rate=discount_rate,
                investment_longevity=investment_longevity,
                investment_period=investment_period,
                analysis_period_span=analysis_period_span,
            )
    
            assert math.isclose(und_salvage_value, 0, abs_tol=1e-3)
    
        # *************************************************************************
        # *************************************************************************
    
        def test_scrap_value_commissioning_delay_linear_depreciation(self):
            # **************************************************************************
    
            investment = 10
    
            investment_period = 0
    
            investment_longevity = 4
    
            analysis_period_span = 3
    
            # *********************************************************************
    
            # the investment still produces benefits after the evaluation phase
    
            residual_value = salvage_value_linear_depreciation(
                investment=investment,
                investment_period=investment_period,
                investment_longevity=investment_longevity,
                analysis_period_span=analysis_period_span,
            )
    
            assert residual_value == 2.5
    
            # the investment is delayed
    
            investment_period = 1
    
            residual_value = salvage_value_linear_depreciation(
                investment=investment,
                investment_period=investment_period,
                investment_longevity=investment_longevity,
                analysis_period_span=analysis_period_span,
            )
    
            assert residual_value == 5.0
    
            # the investment is delayed even more
    
            investment_period = 2
    
            residual_value = salvage_value_linear_depreciation(
                investment=investment,
                investment_period=investment_period,
                investment_longevity=investment_longevity,
                analysis_period_span=analysis_period_span,
            )
    
            assert residual_value == 7.5
    
            # the evaluation phase is longer
    
            investment_period = 0
    
            analysis_period_span = 4
    
            residual_value = salvage_value_linear_depreciation(
                investment=investment,
                investment_period=investment_period,
                investment_longevity=investment_longevity,
                analysis_period_span=analysis_period_span,
            )
    
            assert residual_value == 0.0
    
            # trigger ValueError: the investment takes place after the eval. phase
    
            investment_period = analysis_period_span + 1
    
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            try:
                residual_value = salvage_value_linear_depreciation(
                    investment=investment,
                    investment_period=investment_period,
                    investment_longevity=investment_longevity,
                    analysis_period_span=analysis_period_span,
                )
            except ValueError:
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
    
        # *************************************************************************
        # *************************************************************************
    
        def test_npv(self):
            # *********************************************************************
    
            # data
    
            R_t = [
                0,
                21579,
                4002,
                3302,
                2952,
                2952,
                2952,
                2952,
                2952,
                3198,
                0,
                0,
                0,
                16154,
                2952,
                6452,
                -21930,
            ]
    
            n_periods = len(R_t) - 1
    
            R_t2 = [ncf_t * 1.5 for ncf_t in R_t]
    
            i_t = tuple([0.035 for k in range(n_periods)])
    
            i_t2 = tuple([ii_t * 1.5 for ii_t in i_t])
    
            # *********************************************************************
    
            # compute the NPV via the object
    
            my_inv = Investment(i_t, R_t)
    
            assert math.isclose(
                my_inv.net_present_value(), 45287.96018387402, abs_tol=0.001
            )
    
            # compute the NPV via the object using i_t2 and R_t
    
            my_inv.discount_rates = i_t2
            my_npv = my_inv.net_present_value()
    
            assert math.isclose(my_npv, 42923.405014, abs_tol=0.001)
    
            # compute the NPV via the object using i_t2 and R_t2
    
            my_inv.net_cash_flows = R_t2
            my_npv = my_inv.net_present_value()
    
            assert math.isclose(my_npv, 64385.107522, abs_tol=0.001)
    
            # compute the NPV via the _npv method using i_t and R_t2
    
            my_inv.discount_rates = i_t
            my_inv.net_cash_flows = R_t2
            my_npv = my_inv.net_present_value()
    
            assert math.isclose(my_npv, 67931.940276, abs_tol=0.001)
    
            # compute the NPV via the npv method using i_t and R_t
    
            my_npv, my_df = npv(
                discount_rates=i_t, net_cash_flows=R_t, return_discount_factors=True
            )
    
            assert math.isclose(my_npv, 45287.960184, abs_tol=0.001)
    
            # create new object without specifying the net cash flows
    
            my_inv = Investment(discount_rates=i_t)
    
            for ncf_t in my_inv.net_cash_flows:
                assert ncf_t >= 0
    
            my_inv.net_cash_flows = R_t
            my_npv = my_inv.net_present_value()
    
            assert math.isclose(my_npv, 45287.960184, abs_tol=0.001)
    
            # create new object by specifying the discount rate and the analysis period
    
            my_inv = Investment(
                None,
                net_cash_flows=R_t,
                discount_rate=i_t[0],
                analysis_period_span=len(i_t),
            )
    
            my_npv = my_inv.net_present_value()
    
            assert math.isclose(my_npv, 45287.960184, abs_tol=0.001)
    
            # *********************************************************************
    
            # force errors
    
            # *********************************************************************
    
            # TypeError('The discount rates must be provided as a tuple.')
    
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            try:
                my_inv = Investment(list(i_t), R_t)
            except TypeError:
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
    
            # *********************************************************************
    
            # ValueError('The duration of the period under analysis must be positive.')
    
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            try:
                my_inv = Investment(tuple())
            except ValueError:
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
    
            # *********************************************************************
    
            # TypeError('The discount rate must be provided as a float.')
    
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            try:
                my_inv = Investment(None, None, 5, 10)
            except TypeError:
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
    
            # *********************************************************************
    
            # ValueError('The discount rate must be in the open interval between 0 and 1.)
    
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            try:
                my_inv = Investment(None, None, 1.35, 10)
            except ValueError:
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
    
            # *********************************************************************
    
            # TypeError('The duration of the period under consideration must be provided as an integer.')
    
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            try:
                my_inv = Investment(None, None, 0.35, 10.0)
            except TypeError:
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
    
            # *********************************************************************
    
            # ValueError('The duration of the period under analysis must be positive.)
    
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            try:
                my_inv = Investment(None, None, 0.35, 0)
            except ValueError:
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
    
            # *********************************************************************
    
            # TypeError('The net cash flows must be provided as a list.')
    
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            try:
                my_inv = Investment(i_t, tuple(R_t))
            except TypeError:
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
    
            # *********************************************************************
    
            # trigger the error for differently-sized inputs using npv() and not _npv()
    
            number_errors = 0
    
            try:
                my_npv = npv(i_t[0:-1], R_t)
    
            except ValueError:
                number_errors += 1
    
            assert number_errors == 1
    
            # *********************************************************************
    
            # trigger the error for differently-sized inputs using the __init__ method
    
            number_errors = 0
    
            try:
                my_inv = Investment(i_t[0:-1], R_t)
    
            except ValueError:
                number_errors += 1
    
            assert number_errors == 1
    
            # *********************************************************************
    
    
    # ******************************************************************************
    # ******************************************************************************