diff --git a/bpfin/financials/loan_allocation.py b/bpfin/financials/loan_allocation.py index 6e1f36ebe61d8162de2af9b393c321454b1e2855..5962fbb5e092b69cdefe3080aace1b18b46369d2 100644 --- a/bpfin/financials/loan_allocation.py +++ b/bpfin/financials/loan_allocation.py @@ -25,12 +25,14 @@ def loan_allocation( * if loan_first: pretend SF more expensive than loans, payback_n < min(payback_i) * if self-finance first: pretent SF cheaper than loans, payback_n -> infinity 2. x variables constraint - sum(x_i / payback_i) <= saving/dscr - * sum of annual debt service and self-finance payback <= saving/dscr + sum(x_i / payback_i) - (x_n / payback_n) <= saving/dscr + * sum of annual debt service (exclude self-finance payback) <= saving/dscr sum(x_i / payback_i) - (x_n / payback_n) <= noi/dscr * sum of loan debt service <= noi constraint, making project financially feasibile sum(x_i / payback_i) - (x_n / payback_n) <= cash/dscr * sum of loan debt service <= cash constraint, making project financially feasibile + sum(x_i / payback_i) <= saving + * sum of annual debt service + self-finance payback <= saving sum(x_i) >= project_cost * ideally sum(x) == project cost, but it makes no difference because object func chases minimum 3. x variables bounds @@ -86,7 +88,7 @@ def loan_allocation( # # pre-request check: project cost should be lower than total available financing sum_loan_max_amount = sum(list(current_loan.max_amount for current_loan in loan_list)) if (sum_loan_max_amount + downpayment_max) <= cost: - # print('\nalert: not financiable') + # print('\n!alert!: not financiable') return [0] * len(loan_list) # linear programming (LP) @@ -94,7 +96,7 @@ def loan_allocation( # objective function: x1/payback1 + x2/payback2 + x3/payback3 + sf/adjust_payback = minimum c_formula = list(1 / current_loan.payback for current_loan in loan_list) if is_loan_first is True: - c_formula.append(max(c_formula) + 0.1) + c_formula.append(max(c_formula) + 0.1) # make the payback of SF shortest, to minimize SF amount else: c_formula.append(0) @@ -104,20 +106,25 @@ def loan_allocation( a_1 = copy.deepcopy(a_0) a_2 = copy.deepcopy(a_0) a_3 = copy.deepcopy(a_0) - a_1.append(1 / expected_payback * 12 if expected_payback else 0) + a_4 = copy.deepcopy(a_0) + + a_1.append(0) a_2.append(0) a_3.append(0) - a_4 = ([-1] * (len(loan_list) + 1)) # -x1 -x2 -x3 -sf <= -cost + a_4.append(1 / expected_payback * 12 if expected_payback else 0) + a_5 = ([-1] * (len(loan_list) + 1)) # -x1 -x2 -x3 -sf <= -cost A_matrix.append(multiply_list(a_1, (req_dscr['req_saving_dscr'] if first_year_saving is not None else 0))) A_matrix.append(multiply_list(a_2, (req_dscr['req_noi_dscr'] if first_year_noi is not None else 0))) - A_matrix.append(multiply_list(a_2, (req_dscr['req_cash_dscr'] if first_year_cash is not None else 0))) - A_matrix.append(a_4) + A_matrix.append(multiply_list(a_3, (req_dscr['req_cash_dscr'] if first_year_cash is not None else 0))) + A_matrix.append(multiply_list(a_4, (1 if first_year_saving is not None else 0))) + A_matrix.append(a_5) b_list = [] b_list.append(first_year_saving if first_year_saving else 0) b_list.append(first_year_noi if first_year_noi else 0) b_list.append(first_year_cash if first_year_cash else 0) + b_list.append(first_year_saving if first_year_saving else 0) b_list.append(0 - cost) # x variables bounds @@ -141,24 +148,3 @@ def loan_allocation( return list(res.x[loanid] for loanid in range(len(res.x) - 1)), res.x[-1] -# **** ugly test **** -# from bpfin.tests.testdata import feature_data as db -# from bpfin.financials.loan import Loan_List -# from bpfin.lib.other import sumproduct -# # req_dscr = { -# # 'req_noi_dscr': 1.15, -# # 'req_cash_dscr': 1.05, -# # 'req_saving_dscr': 1.10 -# # } - -# # test cases -# print('\n Base Case:') -# print(loan_allocation( -# loan_list=Loan_List(db.raw_loan_input_list).loan_list, -# customer_preference=db.customer_preference, -# cost=db.cost_estimation, -# req_dscr=db.req_dscr, -# first_year_saving=40000, -# first_year_noi=18412, -# first_year_cash=20000, -# )) diff --git a/bpfin/financials/scenario.py b/bpfin/financials/scenario.py index 05ffdc173a7d00a744d75345d7899bc17b81b2fb..613a700aff14f34148dcf664a9bc6ef9140b74d9 100644 --- a/bpfin/financials/scenario.py +++ b/bpfin/financials/scenario.py @@ -30,6 +30,8 @@ class Scenario(): scheduled_loan_list (list): list of Loan objects. Store financing plans for each loan option downpayment(float): self-finance amount calculated by loan_allocation + feasibility(boolean): indicating financial feaibility of the project + """ def __init__(self, analysis_date, commission_date, construction_cost, @@ -87,6 +89,7 @@ class Scenario(): commissioning_date=copy.deepcopy(commission_date)) self.scheduled_loan_list = None self.downpayment = 0 + self.feasibility = False def prelim_analysis(self, prior_month_bill, percent_saving_dict, full_saving_dict, req_dscr, @@ -167,6 +170,16 @@ class Scenario(): self.scheduled_loan_list = scheduled_loan_list self.downpayment = self.loan_list.get_downpayment() + # determine feasibility by summing up financing plan + total_amount = 0 + for current_loan in scheduled_loan_list: + total_amount += current_loan.amount + total_amount += self.downpayment + if total_amount == 0: + self.feasibility = False + else: + self.feasibility = True + def get_post_energy_bill(self): """ Get annual energy bill for pro-forma period, considering commission date. @@ -359,50 +372,10 @@ class Scenario(): """ return (self.saving_overview.get_total_saving_percent(), self.construction_cost) - -# # ***** ugly test that can be a guide for front end dev ***** -# from bpfin.tests.testdata import feature_data as db -# from bpfin.lib.back_end_call import monthly_bill -# from bpfin.financials.liability import final_liability_dict -# from bpfin.financials.balance_sheet_projection import balance_sheet_projection -# from bpfin.financials.financial_income import Income_Statement_Table -# from bpfin.financials.financial_balance import Balance_Sheet_Table - -# growth_toggle = 0.01 -# prior_IS_table = Income_Statement_Table( -# db.raw_income_input, -# db.prior_annual_bill, -# db.analysis_date) -# prior_IS_table.project(growth_toggle, db.prior_annual_bill) -# prior_BS_table = Balance_Sheet_Table(sdb.raw_balance_sheet) -# prior_BS_table.project_balance_sheet( -# db.analysis_date, -# db.liability_dictionary, -# prior_IS_table.get_noi_dict()) - -# scenario = Scenario( -# analysis_date=db.analysis_date, -# commission_date=db.commission_date, -# construction_cost=db.cost_estimation, -# manual_input_dict=db.manual_input_dict, -# prior_annual_bill_table=db.prior_annual_bill, -# prior_income_statement_table=prior_IS_table, -# other_debt_service=db.liability_dictionary, -# growth_rate_flag=growth_toggle, -# prior_balance_sheet_table=prior_BS_table, -# loan_input_list=db.raw_loan_input_list -# ) - -# prior_month_bill = monthly_bill(db.raw_bill_table, db.analysis_date)[2] -# scenario.prelim_analysis( -# prior_month_bill=prior_month_bill, -# percent_saving_dict=db.percent_saving_dict, -# full_saving_dict=db.full_saving_dict, -# growth_rate_flag=growth_toggle, -# req_dscr=db.req_dscr, -# customer_preference=db.customer_preference) - -# print(scenario.get_annual_debt_service()) -# print(scenario.get_graph_dict()) -# print(scenario.get_dscr()) -# print(scenario.get_economics()) + def get_feasibility(self): + """ + Get the feasibility + Return: + Boolean + """ + return self.feasibility diff --git a/bpfin/tests/test_financials/test_loan_allocation.py b/bpfin/tests/test_financials/test_loan_allocation.py index 1e664bf1e7f0a51d6779be1c72fe4c31c03f2139..b1f483570be6c5fe8912759c5eee114150194750 100644 --- a/bpfin/tests/test_financials/test_loan_allocation.py +++ b/bpfin/tests/test_financials/test_loan_allocation.py @@ -3,7 +3,34 @@ from bpfin.financials.loan import Loan_List from bpfin.financials.loan_allocation import loan_allocation -def test_loan_allocation(): +def test_loan_allocation_1(): + loan_input_list = [ + {'institute': 'OneCapital', 'max_amount': 80000, 'interest': 0.0425, 'duration': 130} + ] + + customer_preference = { + 'downpayment_max': 50000.00, + 'expected_payback': 150, # in months, default 120, extreme case 24 + } + req_dscr = { + 'req_saving_dscr': 1.10, + 'req_noi_dscr': 1.05, + 'req_cash_dscr': 1.05, + } + result = (loan_allocation( + loan_list=Loan_List(loan_input_list).loan_list, + customer_preference=customer_preference, + cost=126000, + req_dscr=req_dscr, + first_year_saving=12860.49, + first_year_noi=781410.20, + first_year_cash=500329.18, + )) + + expected_outcome = ([78671.3292130981], 47328.6707869019) + assert result == expected_outcome + +def test_loan_allocation_2(): result = loan_allocation( loan_list=Loan_List(db.raw_loan_input_list).loan_list, customer_preference=db.customer_preference, @@ -13,5 +40,5 @@ def test_loan_allocation(): first_year_noi=18412, first_year_cash=20000) - expected_outcome = ([0.0, 50000.0, 60800.314080022246], 39199.685919977754) + expected_outcome = ([0.0, 50000.0, 63015.637528143176], 36984.362471856824) assert result == expected_outcome diff --git a/bpfin/tests/test_financials/test_scenario.py b/bpfin/tests/test_financials/test_scenario.py index e9cf330417981f7c0b04aa617fcf40204187530c..1c95e57f892a13d00f20516213233fc58bfc62ed 100644 --- a/bpfin/tests/test_financials/test_scenario.py +++ b/bpfin/tests/test_financials/test_scenario.py @@ -1,47 +1,148 @@ from bpfin.financials.scenario import Scenario -from bpfin.tests.testdata import feature_data as db -from bpfin.tests.testdata import sample_data as sd -# from bpfin.lib.back_end_call import monthly_bill +from bpfin.financials.cash_balance import cash_balance +from bpfin.back_end_call.back_end_inputs import form_annual_bill_table from bpfin.financials.liability import final_liability_dict from bpfin.financials.balance_sheet_projection import balance_sheet_projection -from bpfin.financials.cash_balance import cash_balance from bpfin.financials.financial_income import Income_Statement_Table from bpfin.financials.financial_balance import Balance_Sheet_Table +from bpfin.tests.testdata import feature_data as db -growth_toggle = -2.0 +def test_scenario_1(): + growth_rate_flag=-2 + prior_annual_bill_table, manual_input_dict, prior_month_bill, unsued_display_table = form_annual_bill_table( + db.raw_monthly_bill_table, db.raw_annual_bill_table, db.analysis_date) -cash_balance_test = cash_balance(db.analysis_date, db.raw_cash_balance) -liability_test = final_liability_dict(db.analysis_date, db.raw_liability_input) + prior_IS_table = Income_Statement_Table( + db.raw_income_input, + prior_annual_bill_table, + db.analysis_date) -prior_IS_table = Income_Statement_Table(db.raw_income_input, - db.prior_annual_bill, db.analysis_date) -prior_IS_table.project(growth_toggle, db.prior_annual_bill) -prior_BS_table = Balance_Sheet_Table(cash_balance_test, liability_test, - prior_IS_table.get_noi_dict()) -prior_BS_table.project_balance_sheet(db.analysis_date, db.liability_dictionary, - prior_IS_table.get_noi_dict()) + prior_IS_table.project(growth_rate_flag=growth_rate_flag, annual_bill_table=prior_annual_bill_table) + cash_balance_dict = cash_balance(db.analysis_date, db.raw_cash_balance) + liability_dict=final_liability_dict(db.analysis_date,db.raw_liability_input) + prior_BS_table = Balance_Sheet_Table( + cash_balance_dictionary=cash_balance_dict, + other_debt_service_dictionary=liability_dict, + net_income_dictionary=prior_IS_table.get_noi_dict() + ) -def test_scenario_object(): - """TODO: Test must be implemented correctly. Test cases must be added later. - """ + prior_BS_table.project_balance_sheet( + analysis_date=db.analysis_date, + other_debt_service_dictionary=liability_dict, + net_income_dictionary=prior_IS_table.get_noi_dict() + ) - scenario_object_test = Scenario( + scenario = Scenario( analysis_date=db.analysis_date, commission_date=db.commission_date, construction_cost=db.cost_estimation, manual_input_dict=db.manual_input_dict, - prior_annual_bill_table=db.prior_annual_bill, + prior_annual_bill_table=prior_annual_bill_table, prior_income_statement_table=prior_IS_table, other_debt_service=db.liability_dictionary, - growth_rate_flag=growth_toggle, + growth_rate_flag=growth_rate_flag, prior_balance_sheet_table=prior_BS_table, - loan_input_list=db.raw_loan_input_list) + # loan_input_list=db.fail_loan_input_list + loan_input_list=db.raw_loan_input_list, + ) + + scenario.prelim_analysis( + prior_month_bill=prior_month_bill, + # percent_saving_dict=db.fail_saving_dict, + percent_saving_dict=db.percent_saving_dict, + full_saving_dict=db.full_saving_dict, + req_dscr=db.req_dscr, + # customer_preference=db.fail_customer_preference + customer_preference=db.customer_preference, + ) + + result = {} + result['feasibility'] = scenario.get_feasibility() + result['annual_ds'] = scenario.get_annual_debt_service() + result['graph_dict'] = scenario.get_graph_dict() + result['economics'] = scenario.get_economics() + result['financing_plan'] = scenario.get_financing_plan() + + outcome = db.scenario_outcome + + assert result == outcome + + +def test_scenario_fail(): + growth_rate_flag=-2 + prior_annual_bill_table, manual_input_dict, prior_month_bill, unsued_display_table = form_annual_bill_table( + db.raw_monthly_bill_table, db.raw_annual_bill_table, db.analysis_date) + + prior_IS_table = Income_Statement_Table( + db.raw_income_input, + prior_annual_bill_table, + db.analysis_date) + + prior_IS_table.project(growth_rate_flag=growth_rate_flag, annual_bill_table=prior_annual_bill_table) + cash_balance_dict = cash_balance(db.analysis_date, db.raw_cash_balance) + liability_dict=final_liability_dict(db.analysis_date,db.raw_liability_input) + + prior_BS_table = Balance_Sheet_Table( + cash_balance_dictionary=cash_balance_dict, + other_debt_service_dictionary=liability_dict, + net_income_dictionary=prior_IS_table.get_noi_dict() + ) + + prior_BS_table.project_balance_sheet( + analysis_date=db.analysis_date, + other_debt_service_dictionary=liability_dict, + net_income_dictionary=prior_IS_table.get_noi_dict() + ) + + scenario = Scenario( + analysis_date=db.analysis_date, + commission_date=db.commission_date, + construction_cost=db.cost_estimation, + manual_input_dict=db.manual_input_dict, + prior_annual_bill_table=prior_annual_bill_table, + prior_income_statement_table=prior_IS_table, + other_debt_service=db.liability_dictionary, + growth_rate_flag=growth_rate_flag, + prior_balance_sheet_table=prior_BS_table, + loan_input_list=db.fail_loan_input_list + # loan_input_list=db.raw_loan_input_list, + ) + + scenario.prelim_analysis( + prior_month_bill=prior_month_bill, + percent_saving_dict=db.fail_saving_dict, + # percent_saving_dict=db.percent_saving_dict, + full_saving_dict=db.full_saving_dict, + req_dscr=db.req_dscr, + customer_preference=db.fail_customer_preference + # customer_preference=db.customer_preference, + ) + + result = {} + result['feasibility'] = scenario.get_feasibility() + result['annual_ds'] = scenario.get_annual_debt_service() + result['graph_dict'] = scenario.get_graph_dict() + result['economics'] = scenario.get_economics() + result['financing_plan'] = scenario.get_financing_plan() + + outcome = db.fail_scenario_outcome - scenario_object_test.prelim_analysis( - sd.prior_month_bill, db.percent_saving_dict, db.full_saving_dict, - db.req_dscr, db.customer_preference) + assert result == outcome - print(scenario_object_test.get_post_balance_sheet_statement()) - assert 1 == 1 + # import pprint + # pp = pprint.PrettyPrinter(width=360, indent=4, compact=False) + # print('\n') + # print('annual debt service=====') + # pp.pprint(scenario.get_annual_debt_service()) + # print('graph dict=====') + # pp.pprint(scenario.get_graph_dict()) + # print('get dscr=====') + # pp.pprint(scenario.get_dscr()) + # print('project economics=====') + # pp.pprint(scenario.get_economics()) + # print('financing plan=====') + # pp.pprint(scenario.get_financing_plan()) + # print('feasibility =====') + # pp.pprint(scenario.get_feasibility()) diff --git a/bpfin/tests/testdata/feature_data.py b/bpfin/tests/testdata/feature_data.py index e10a745ea5bff6ea0a42c9b9294d7f97412e2fb4..ca63d77a962475d21a78e066f81bb5a6b01033e1 100644 --- a/bpfin/tests/testdata/feature_data.py +++ b/bpfin/tests/testdata/feature_data.py @@ -25,9 +25,9 @@ commission_date = date(2017, 3, 14) # required debt service coverage ratio req_dscr = { + 'req_saving_dscr': 1.10, 'req_noi_dscr': 1.15, 'req_cash_dscr': 1.15, - 'req_saving_dscr': 1.10 } # req_dscr = { @@ -43,8 +43,13 @@ customer_preference = { 'expected_payback': 120, # in months, default 120, extreme case 24 } +fail_customer_preference = { + 'downpayment_max': 99999.00, + 'expected_payback': 240, # in months, default 120, extreme case 24 +} + -percent_saving_fdict = { +percent_saving_dict = { UTILITY_TYPE_LIST[0]: 0.25, UTILITY_TYPE_LIST[1]: 0.10, UTILITY_TYPE_LIST[2]: 0.80, @@ -260,6 +265,13 @@ percent_saving_dict = { UTILITY_TYPE_LIST[3]: 0.0 } +fail_saving_dict = { + UTILITY_TYPE_LIST[0]: 0.25, + UTILITY_TYPE_LIST[1]: 0.10, + UTILITY_TYPE_LIST[2]: 0.80, + UTILITY_TYPE_LIST[3]: 0.00 +} + full_saving_dict = { UTILITY_TYPE_LIST[0]: None, UTILITY_TYPE_LIST[1]: None, @@ -283,9 +295,15 @@ raw_cash_balance = { loan_term_1 = {'institute': 'NYSERDA', 'max_amount': 500000, 'interest': 0.08, 'duration': 120} loan_term_2 = {'institute': 'Joe Fund', 'max_amount': 50000, 'interest': 0.05, 'duration': 108} loan_term_3 = {'institute': 'Tooraj Capital', 'max_amount': 75000, 'interest': 0.07, 'duration': 114} -# loan_term_dict = {1: loan_term_1, 2: loan_term_2, 3: loan_term_3} #should be deleted if whole tests runs good raw_loan_input_list = [loan_term_1, loan_term_2, loan_term_3] # raw_loan_input_list = None + +fail_loan_term_1 = {'institute': 'NYSERDA', 'max_amount': 500000, 'interest': 0.08, 'duration': 12} +fail_loan_term_2 = {'institute': 'Joe Fund', 'max_amount': 50000, 'interest': 0.05, 'duration': 24} +fail_loan_term_3 = {'institute': 'Tooraj Capital', 'max_amount': 75000, 'interest': 0.07, 'duration': 6} +fail_loan_input_list = [fail_loan_term_1, fail_loan_term_2, fail_loan_term_3] +# raw_loan_input_list = None + loan1_end_balance = [ 24863.347680778272, 24725.784346095064, 24587.303922513969, 24447.900296109001, 24307.567312194667, 24166.298775054238, @@ -930,3 +948,164 @@ liability_dictionary = { 2035: 0, 2036: 0, } + +scenario_outcome = { + 'feasibility': True, + 'annual_ds':{ + 2012: 0,2013: 0,2014: 0,2015: 0,2016: 0,2017: 17817.434251054554,2018: 21380.921101265467, + 2019: 21380.921101265467,2020: 21380.921101265467,2021: 21380.921101265467,2022: 21380.921101265467, + 2023: 21380.921101265467,2024: 21380.921101265467,2025: 21380.921101265467,2026: 12012.041393887805, + 2027: 606.6379717767887,2028: 0,2029: 0,2030: 0,2031: 0,2032: 0,2033: 0,2034: 0,2035: 0,2036: 0}, + 'graph_dict':{ + 'energy_expenses': { + 2012: 55002.38772098512,2013: 55616.15410714429,2014: 55660.176408612344, + 2015: 56462.176198804, 2016: 57253.29633563089, 2017: 38245.304003035155, + 2018: 31995.29516294587, + 2019: 32277.866903219165, + 2020: 32553.735565389954, + 2021: 32811.31698250212, + 2022: 33044.85075083363, + 2023: 33273.81714638449, + 2024: 33507.656358322245, + 2025: 33749.416583944476, + 2026: 34009.416899967524, + 2027: 34289.92015109155, + 2028: 34577.76064477535, + 2029: 34865.97301897171, + 2030: 35154.19462615646, + 2031: 35443.28338380835, + 2032: 35735.622462367246, + 2033: 36034.586281311065, + 2034: 36341.547655119575, + 2035: 36656.87910689578, + 2036: 36980.62037310585}, + 'net_savings': { 2014: 0.0, + 2015: 0.0, + 2016: 0.0, + 2017: 1399.2525568434357, + 2018: 5004.7662904717035, + 2019: 5654.4228400261345, + 2020: 6287.789772250726, + 2021: 6880.955294341689, + 2022: 7417.696647191213, + 2023: 7943.461473897962, + 2024: 8480.092734186055, + 2025: 9034.964295942966, + 2026: 18999.704242172826, + 2027: 31048.702318883665, + 2028: 32316.2641932619, + 2029: 32978.169444379586, + 2030: 33640.00693821155, + 2031: 34303.84790318047, + 2032: 34974.94503078355, + 2033: 35661.17092538828, + 2034: 36365.728149686125, + 2035: 37089.50809611738, + 2036: 37832.5959793318}, + 'total_loan': { 2012: 0, + 2013: 0, + 2014: 0, + 2015: 0, + 2016: 0, + 2017: 17817.434251054554, + 2018: 21380.921101265467, + 2019: 21380.921101265467, + 2020: 21380.921101265467, + 2021: 21380.921101265467, + 2022: 21380.921101265467, + 2023: 21380.921101265467, + 2024: 21380.921101265467, + 2025: 21380.921101265467, + 2026: 12012.041393887805, + 2027: 606.6379717767887, + 2028: 0, + 2029: 0, + 2030: 0, + 2031: 0, + 2032: 0, + 2033: 0, + 2034: 0, + 2035: 0, + 2036: 0} + }, + 'economics': { + 'estimated_cost': 150000.0, + 'first_year_saving': 28667.50724801173, + 'min_cash_dscr': 5.611089438289177, + 'min_noi_dscr': 1.7556178946382468, + 'min_saving_dscr': 1.2340762713995275, + 'overall_saving': 0.46592312148565274, + 'simple_payback': 5.2324047117980035,}, + + 'financing_plan': [25000.0, 50000.0, 75000.0, 0.0], +} + + +fail_scenario_outcome = { + 'feasibility': False, + 'annual_ds':{ + 2012: 0, 2013: 0, 2014: 0, 2015: 0, 2016: 0, 2017: 0.0, 2018: 0.0, 2019: 0.0, 2020: 0, + 2021: 0, 2022: 0, 2023: 0, 2024: 0, 2025: 0, 2026: 0, 2027: 0, 2028: 0, 2029: 0, + 2030: 0, 2031: 0, 2032: 0, 2033: 0, 2034: 0, 2035: 0, 2036: 0}, + 'graph_dict':{ + 'energy_expenses': { + 2012: 55002.38772098512,2013: 55616.15410714429,2014: 55660.176408612344, + 2015: 56462.176198804, 2016: 57253.29633563089, 2017: 38245.304003035155, + 2018: 31995.29516294587, + 2019: 32277.866903219165, + 2020: 32553.735565389954, + 2021: 32811.31698250212, + 2022: 33044.85075083363, + 2023: 33273.81714638449, + 2024: 33507.656358322245, + 2025: 33749.416583944476, + 2026: 34009.416899967524, + 2027: 34289.92015109155, + 2028: 34577.76064477535, + 2029: 34865.97301897171, + 2030: 35154.19462615646, + 2031: 35443.28338380835, + 2032: 35735.622462367246, + 2033: 36034.586281311065, + 2034: 36341.547655119575, + 2035: 36656.87910689578, + 2036: 36980.62037310585}, + 'net_savings': { 2014: 0.0, + 2015: 0.0, + 2016: 0.0, + 2017: 19216.68680789799, + 2018: 26385.68739173717, + 2019: 27035.3439412916, + 2020: 27668.710873516193, + 2021: 28261.876395607156, + 2022: 28798.61774845668, + 2023: 29324.38257516343, + 2024: 29861.013835451522, + 2025: 30415.885397208433, + 2026: 31011.74563606063, + 2027: 31655.340290660453, + 2028: 32316.2641932619, + 2029: 32978.169444379586, + 2030: 33640.00693821155, + 2031: 34303.84790318047, + 2032: 34974.94503078355, + 2033: 35661.17092538828, + 2034: 36365.728149686125, + 2035: 37089.50809611738, + 2036: 37832.5959793318}, + 'total_loan': { + 2012: 0, 2013: 0, 2014: 0, 2015: 0, 2016: 0, 2017: 0.0, 2018: 0.0, + 2019: 0.0, 2020: 0, 2021: 0, 2022: 0, 2023: 0, 2024: 0, 2025: 0, + 2026: 0, 2027: 0, 2028: 0, 2029: 0, 2030: 0, 2031: 0, 2032: 0, + 2033: 0, 2034: 0, 2035: 0, 2036: 0,}, + }, + 'economics': { + 'estimated_cost': 150000.0, + 'first_year_saving': 28667.50724801173, + 'min_cash_dscr': 0, + 'min_noi_dscr': 0, + 'min_saving_dscr': 0, + 'overall_saving': 0.46592312148565274, + 'simple_payback': 5.2324047117980035,}, + 'financing_plan': [0, 0, 0, 0], +} diff --git a/setup.py b/setup.py index 2a0050509eb0e21a7c96ccb0136af26828b062d3..aa1b22991be280e892e2d5f8ccbdd4f207bd3376 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ reqs = [str(req.req) for req in install_reqs] setup( name='bpfin', - version='0.2.5', + version='0.2.5-beta', description='Finance models and utilites', author='BlocPower', author_email='admin@blocpower.org',