From 888e38f4f9761178a21b0787ffb4d5b22d595fac Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Thu, 20 Apr 2017 17:51:26 -0400 Subject: [PATCH 01/27] created income_statement_projection_input --- bpfin/financials/income_statement_proj_input.py | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 bpfin/financials/income_statement_proj_input.py diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py new file mode 100644 index 0000000..4470bb4 --- /dev/null +++ b/bpfin/financials/income_statement_proj_input.py @@ -0,0 +1,9 @@ +from bpfin.financials import financial_lib as fl + + +def income_statement_proj_input(): + '''project income statement for UI input. inputs are whatever bill and financial statements are available + + + ''' + pass -- GitLab From ef577d26df2f1b965d8aecdb43f85db3397d6949 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Thu, 20 Apr 2017 18:30:05 -0400 Subject: [PATCH 02/27] create date function : form_bill_year and its test file --- .../financials/income_statement_proj_input.py | 30 +++++++++++++++++++ bpfin/tests/test_utilbills/test_bill_lib.py | 9 ++++++ bpfin/tests/testdata/sample_data.py | 2 +- bpfin/utilbills/bill_lib.py | 21 +++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py index 4470bb4..f7cd659 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_proj_input.py @@ -1,9 +1,39 @@ from bpfin.financials import financial_lib as fl +from bpfin.tests.testdata import sample_data as db +import bpfin.utilbills.bill_lib as bl def income_statement_proj_input(): '''project income statement for UI input. inputs are whatever bill and financial statements are available + Args: ''' pass + +# organize bill_overview +# income statements should be availabe for at least 1 year. If comes with 1+ years, suppose to be continued. + + +def organize_bill_overview(bill_overview, analysis_date): + '''take bill_overview as inputs, fill in the blank annual bill with average numbers + + Args: + bill_overview (dictionary): bill_overview from UI, with blank cells, for 4 utility_types + analysis_date (dictionary): proforma's starting date and the years of proforma + Returns: + bill_overview_organized (dictionary): same structure with bill_overview + + Description: + analysis_date: {'proforma_start': datetime.date, 'proforma': int} + ''' + proforma_terms = bl.form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration'])[1] + + + + + +bill_overview = db.bill_overview + + + diff --git a/bpfin/tests/test_utilbills/test_bill_lib.py b/bpfin/tests/test_utilbills/test_bill_lib.py index 321befb..4e90233 100644 --- a/bpfin/tests/test_utilbills/test_bill_lib.py +++ b/bpfin/tests/test_utilbills/test_bill_lib.py @@ -1,4 +1,5 @@ from bpfin.utilbills.bill_lib import add_list, annualizing_projection +from bpfin.utilbills import bill_lib as bl from datetime import date, datetime @@ -21,3 +22,11 @@ def test_annualizing_projection(): result = annualizing_projection(input_dates, input_values) assert output_dictionary == result + + +def test_form_bill_year(): + start_date = datetime(2012, 2, 14) + year_term = 5 + output_list = [2012, 2013, 2014, 2015, 2016] + result_list = bl.fomr_bill_year(start_date, year_term) + assert output_list == result_list diff --git a/bpfin/tests/testdata/sample_data.py b/bpfin/tests/testdata/sample_data.py index 92f6081..a1ca174 100644 --- a/bpfin/tests/testdata/sample_data.py +++ b/bpfin/tests/testdata/sample_data.py @@ -837,7 +837,7 @@ prior_proj_rough_price = [ 42131.00318614885, 40054.83089682108, 40079.848368848034, 40883.798098440246, 40432.470041231565, 40779.34931771414, 41139.21219179594, 40321.43463472525, 43237.085994998866, 48437.35375945405, 51641.29962190506, 48278.23252154697] -annual_bill_electricity ={ +annual_bill_electricity = { 2012: 32220.590596217822, 2013: 32782.518348206999, 2014: 33293.100530249467, 2015: 33546.761580451312, 2016: 33844.501703633454, 2017: 34523.27291517199, 2018: 35384.966283060414, 2019: 36251.490761516034, 2020: 37100.197369238413, 2021: 37887.082013632862, 2022: 38603.765037606507, 2023: 39307.925216552088, diff --git a/bpfin/utilbills/bill_lib.py b/bpfin/utilbills/bill_lib.py index 3f2536a..039cc13 100644 --- a/bpfin/utilbills/bill_lib.py +++ b/bpfin/utilbills/bill_lib.py @@ -50,6 +50,27 @@ def form_bill_calendar(date_start, year_term): return [bdstart, bdend] +def fomr_bill_year(date_start, year_term): + """Return single list value of years, for length of year_term + + Args: + date_start (datetime): date xx/yy/abcd + year_term (int): number of years + Returns: + list: years + + Description: date_start = 2012,4,5; year_term = 25, output = [2012,...,2036] + """ + bill_year = [date_start.year] + i = 1 + while i < year_term: + bill_year.append(bill_year[-1] + 1) + i = i + 1 + if i == 9999: + break + return bill_year + + def form_date_calendar(date_start, date_end): """Return list of all calendar dates. -- GitLab From 90efb3c59e2c3a0c1884242e286237b45bef514d Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Thu, 20 Apr 2017 18:48:27 -0400 Subject: [PATCH 03/27] improve test file for test_form_bill_year improve organize_bill_overview func with proforma_year calculation --- bpfin/financials/income_statement_proj_input.py | 10 +++++----- bpfin/tests/test_utilbills/test_bill_lib.py | 2 +- bpfin/utilbills/bill_lib.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py index f7cd659..bf3549e 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_proj_input.py @@ -25,15 +25,15 @@ def organize_bill_overview(bill_overview, analysis_date): bill_overview_organized (dictionary): same structure with bill_overview Description: - analysis_date: {'proforma_start': datetime.date, 'proforma': int} + analysis_date: {'proforma_start': datetime.date, 'proforma_duration': int} ''' - proforma_terms = bl.form_bill_calendar(analysis_date['proforma_start'], analysis_date['proforma_duration'])[1] + proforma_year = bl.form_bill_year(analysis_date['proforma_start'], analysis_date['proforma_duration']) + # print(proforma_year) + return None +organize_bill_overview(db.bill_overview, db.analysis_date) -bill_overview = db.bill_overview - - diff --git a/bpfin/tests/test_utilbills/test_bill_lib.py b/bpfin/tests/test_utilbills/test_bill_lib.py index 4e90233..4eb3034 100644 --- a/bpfin/tests/test_utilbills/test_bill_lib.py +++ b/bpfin/tests/test_utilbills/test_bill_lib.py @@ -28,5 +28,5 @@ def test_form_bill_year(): start_date = datetime(2012, 2, 14) year_term = 5 output_list = [2012, 2013, 2014, 2015, 2016] - result_list = bl.fomr_bill_year(start_date, year_term) + result_list = bl.form_bill_year(start_date, year_term) assert output_list == result_list diff --git a/bpfin/utilbills/bill_lib.py b/bpfin/utilbills/bill_lib.py index 039cc13..af85d6f 100644 --- a/bpfin/utilbills/bill_lib.py +++ b/bpfin/utilbills/bill_lib.py @@ -50,7 +50,7 @@ def form_bill_calendar(date_start, year_term): return [bdstart, bdend] -def fomr_bill_year(date_start, year_term): +def form_bill_year(date_start, year_term): """Return single list value of years, for length of year_term Args: -- GitLab From f2cec581e42bf99c942b73e9098a8c6e3da4fd87 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Thu, 20 Apr 2017 21:29:53 -0400 Subject: [PATCH 04/27] Create form_raw_income_statement, not finished Create organize_bill_overview for annual bill overview --- bpfin/financials/financial_lib.py | 86 +++++++++++++++---- .../financials/income_statement_proj_input.py | 30 ++----- 2 files changed, 75 insertions(+), 41 deletions(-) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index 3b213e2..7b3a9d5 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -1,6 +1,8 @@ # import datetime # import calendar # from bpfin.lib import other as lib +import bpfin.utilbills.bill_lib as bl +from bpfin.tests.testdata import sample_data as db # import pprint @@ -46,20 +48,69 @@ def income_statement_single_year(income_input, bill_overview): 'revenue': revenue, 'utility_expense': utility_expense, 'energy_opex': energy_opex, - 'electricity_opex': electricity_opex, - 'gas_opex': gas_opex, - 'oil_opex': oil_opex, + 'electricity_opex': electricity_opex, + 'gas_opex': gas_opex, + 'oil_opex': oil_opex, 'water_opex': water_opex, 'other_utility': other_utility, - 'non_utility_expense': non_utility_expense, + 'non_utility_expense': non_utility_expense, 'net_non_energy_opex': net_non_energy_opex, 'total_opex': total_opex, - 'noi': noi} + 'noi': noi + } # print(income_statement) return income_statement +def organize_bill_overview(bill_overview, analysis_date): + '''take bill_overview as inputs, fill in the blank annual bill with average numbers + + Args: + bill_overview (dictionary): bill_overview from UI, with blank cells, for 4 utility_types + analysis_date (dictionary): proforma's starting date and the years of proforma + Returns: + dictionary: bill_overview_organized,same structure with bill_overview + + Description: + analysis_date: {'proforma_start': datetime.date, 'proforma_duration': int} + ''' + proforma_year = bl.form_bill_year(analysis_date['proforma_start'], + analysis_date['proforma_duration']) + # print(proforma_year) + bill_dict = {} + bill_dict[1] = bill_overview['electricity'] # electricity_bill + bill_dict[2] = bill_overview['gas'] # gas_bill + bill_dict[3] = bill_overview['oil'] # oil_bill + bill_dict[4] = bill_overview['water'] # water_bill + + for year in proforma_year: + for i in range(4): + if year in bill_dict[i + 1]: + pass + else: + bill_dict[i + 1][year] = 0 + return bill_dict + + +# income statements, should be in {2014:{'year':2014, 'revenue': 100000...},2015:{},2016:{}} +def form_raw_income_statement(raw_income_input, bill_overview, analysis_date): + bill_overview_organized = organize_bill_overview(bill_overview, analysis_date) + for year in sorted(raw_income_input): + print(year) + # print(bill_overview_organized) + + return None + + + +raw_income_input = { + 2014: {'revenue': 90000, 'utility_expense': 55000, 'non_utility_expense': 3500}, + 2015: {'revenue': 95000, 'utility_expense': 55000, 'non_utility_expense': 3000}, + 2016: {'revenue': 100000, 'utility_expense': 60000, 'non_utility_expense': 3000}} + + + # income_input_2016 = { # 'year': 2016, # 'revenue': 100000, @@ -67,18 +118,19 @@ def income_statement_single_year(income_input, bill_overview): # 'non_utility_expense': 3000 # } -# electricity_bill = { -# 2012: 32220.590596217822, 2013: 32782.518348206999, 2014: 33293.100530249467, 2015: 33546.761580451312, -# 2016: 33844.501703633454, 2017: 34523.27291517199, 2018: 35384.966283060414, 2019: 36251.490761516034, -# 2020: 37100.197369238413, 2021: 37887.082013632862, 2022: 38603.765037606507, 2023: 39307.925216552088, -# 2024: 40028.077679374117, 2025: 40772.42926238777, 2026: 41575.666985412594, 2027: 42439.918590730398, -# 2028: 43325.235463581725, 2029: 44211.298795796341, 2030: 45097.667796776521, 2031: 45986.665329650692, -# 2032: 46886.305428683903, 2033: 47806.578908870637, 2034: 48751.551094031129, 2035: 49722.255450564422, -# 2036: 50718.832984188753} -# oil_bill = {2015: 1010, 2016: 1210, 2017: 1510} -# gas_bill = {2015: 1020, 2016: 1220, 2017: 1520} -# water_bill = {2015: 0, 2016: 0, 2017: 0} +electricity_bill = { + 2012: 32220.590596217822, 2013: 32782.518348206999, 2014: 33293.100530249467, 2015: 33546.761580451312, + 2016: 33844.501703633454, 2017: 34523.27291517199, 2018: 35384.966283060414, 2019: 36251.490761516034, + 2020: 37100.197369238413, 2021: 37887.082013632862, 2022: 38603.765037606507, 2023: 39307.925216552088, + 2024: 40028.077679374117, 2025: 40772.42926238777, 2026: 41575.666985412594, 2027: 42439.918590730398, + 2028: 43325.235463581725, 2029: 44211.298795796341, 2030: 45097.667796776521, 2031: 45986.665329650692, + 2032: 46886.305428683903, 2033: 47806.578908870637, 2034: 48751.551094031129, 2035: 49722.255450564422, + 2036: 50718.832984188753} +oil_bill = {2015: 1010, 2016: 1210, 2017: 1510} +gas_bill = {2015: 1020, 2016: 1220, 2017: 1520} +water_bill = {2015: 0, 2016: 0, 2017: 0} -# bill_overview = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} +bill_overview = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} # income_statement_single_year(income_input_2016, bill_overview) +form_raw_income_statement(raw_income_input, bill_overview, db.analysis_date) diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py index bf3549e..e2a845a 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_proj_input.py @@ -3,37 +3,19 @@ from bpfin.tests.testdata import sample_data as db import bpfin.utilbills.bill_lib as bl -def income_statement_proj_input(): +def income_statement_proj_input(raw_income_statement, bill_overview, analysis_date, growth_rate_flag): '''project income statement for UI input. inputs are whatever bill and financial statements are available - Args: - - - ''' - pass - -# organize bill_overview -# income statements should be availabe for at least 1 year. If comes with 1+ years, suppose to be continued. - - -def organize_bill_overview(bill_overview, analysis_date): - '''take bill_overview as inputs, fill in the blank annual bill with average numbers - Args: bill_overview (dictionary): bill_overview from UI, with blank cells, for 4 utility_types analysis_date (dictionary): proforma's starting date and the years of proforma Returns: - bill_overview_organized (dictionary): same structure with bill_overview - - Description: - analysis_date: {'proforma_start': datetime.date, 'proforma_duration': int} + dictionary: ''' proforma_year = bl.form_bill_year(analysis_date['proforma_start'], analysis_date['proforma_duration']) - # print(proforma_year) - + form_raw_income_statement() return None -organize_bill_overview(db.bill_overview, db.analysis_date) - - - +# organize bill_overview +# income statements should be availabe for at least 1 year. If comes with 1+ years, suppose to be continued. +income_statement_proj_input(db.bill_overview, db.analysis_date) -- GitLab From db7a122b800efb9c760684c70830e63da7f11e54 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Thu, 20 Apr 2017 23:02:25 -0400 Subject: [PATCH 05/27] Improve form_raw_income_statement --- bpfin/financials/financial_lib.py | 23 ++++++++++++++----- .../test_financials/test_financial_lib.py | 2 +- bpfin/tests/testdata/sample_data.py | 2 +- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index 7b3a9d5..5cb5daa 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -7,7 +7,7 @@ from bpfin.tests.testdata import sample_data as db # calculate single year income statement given inputs from UI -def income_statement_single_year(income_input, bill_overview): +def income_statement_single_year(year, income_input, bill_overview): '''calculate income statement for 1 year, with inputs from UI and energy bill overview Args: @@ -17,11 +17,11 @@ def income_statement_single_year(income_input, bill_overview): dictionary: income statement with standarized items Description Sample: - income_input = {'year': 2016, 'revenue': 100000, 'utility_expense': 60000,'non_utility_expense': 3000} + income_input = {revenue': 100000, 'utility_expense': 60000,'non_utility_expense': 3000} bill_overview = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} ''' - year = income_input['year'] + # year = income_input['year'] revenue = income_input['revenue'] utility_expense = income_input['utility_expense'] non_utility_expense = income_input['non_utility_expense'] @@ -89,15 +89,26 @@ def organize_bill_overview(bill_overview, analysis_date): if year in bill_dict[i + 1]: pass else: - bill_dict[i + 1][year] = 0 - return bill_dict + bill_dict[i + 1][year] = 0 # !!!!!! average, not 0!!!!! + bill_overview_organized = { + 'electricity': bill_dict[1], + 'gas': bill_dict[2], + 'oil': bill_dict[3], + 'water': bill_dict[4] + } + return bill_overview_organized # income statements, should be in {2014:{'year':2014, 'revenue': 100000...},2015:{},2016:{}} def form_raw_income_statement(raw_income_input, bill_overview, analysis_date): bill_overview_organized = organize_bill_overview(bill_overview, analysis_date) + print(bill_overview_organized) + income_statement_full = {} for year in sorted(raw_income_input): - print(year) + income_statement_full[year] = income_statement_single_year(year, + raw_income_input[year], + bill_overview_organized) + print(income_statement_full[year]) # print(bill_overview_organized) return None diff --git a/bpfin/tests/test_financials/test_financial_lib.py b/bpfin/tests/test_financials/test_financial_lib.py index 6bf20bd..ef71ec8 100644 --- a/bpfin/tests/test_financials/test_financial_lib.py +++ b/bpfin/tests/test_financials/test_financial_lib.py @@ -7,5 +7,5 @@ def test_income_statement_single_year(): income_input = db.income_input_2016 bill_overview = db.bill_overview output_dict = db.income_statement_2016 - result_dict = fl.income_statement_single_year(income_input, bill_overview) + result_dict = fl.income_statement_single_year(2016, income_input, bill_overview) assert output_dict == result_dict diff --git a/bpfin/tests/testdata/sample_data.py b/bpfin/tests/testdata/sample_data.py index a1ca174..86aa4e9 100644 --- a/bpfin/tests/testdata/sample_data.py +++ b/bpfin/tests/testdata/sample_data.py @@ -855,7 +855,7 @@ bill_overview = { 'water': annual_bill_water} income_input_2016 = { - 'year': 2016, + # 'year': 2016, 'revenue': 100000, 'utility_expense': 60000, 'non_utility_expense': 3000} -- GitLab From 05176685ab23a27b49214272929d5d465aad6c36 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 21 Apr 2017 00:02:47 -0400 Subject: [PATCH 06/27] Improved financial_lib organize_bill_overview, not finished yet. Rename init file --- bpfin/financials/financial_lib.py | 25 +++++++++++++------ .../testdata/{__inti__.py => __init__.py} | 0 2 files changed, 17 insertions(+), 8 deletions(-) rename bpfin/tests/testdata/{__inti__.py => __init__.py} (100%) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index 5cb5daa..154e4a9 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -63,7 +63,7 @@ def income_statement_single_year(year, income_input, bill_overview): return income_statement -def organize_bill_overview(bill_overview, analysis_date): +def organize_bill_overview(bill_overview, analysis_date): # !! also need input_flag '''take bill_overview as inputs, fill in the blank annual bill with average numbers Args: @@ -83,18 +83,23 @@ def organize_bill_overview(bill_overview, analysis_date): bill_dict[2] = bill_overview['gas'] # gas_bill bill_dict[3] = bill_overview['oil'] # oil_bill bill_dict[4] = bill_overview['water'] # water_bill + average_bill_dict = {} + + for i in range(4): + if bill_dict[i + 1][1] is False: + average_bill_dict[i + 1] = 0 # !!! build average calculation for year in proforma_year: for i in range(4): - if year in bill_dict[i + 1]: + if year in bill_dict[i + 1][0]: pass else: - bill_dict[i + 1][year] = 0 # !!!!!! average, not 0!!!!! + bill_dict[i + 1][0][year] = average_bill_dict[i + 1] bill_overview_organized = { - 'electricity': bill_dict[1], - 'gas': bill_dict[2], - 'oil': bill_dict[3], - 'water': bill_dict[4] + 'electricity': bill_dict[1][0], + 'gas': bill_dict[2][0], + 'oil': bill_dict[3][0], + 'water': bill_dict[4][0] } return bill_overview_organized @@ -141,7 +146,11 @@ oil_bill = {2015: 1010, 2016: 1210, 2017: 1510} gas_bill = {2015: 1020, 2016: 1220, 2017: 1520} water_bill = {2015: 0, 2016: 0, 2017: 0} -bill_overview = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} +bill_overview = { + 'electricity': [electricity_bill, True], + 'oil': [oil_bill, False], + 'gas': [gas_bill, False], + 'water': [water_bill, False]} # income_statement_single_year(income_input_2016, bill_overview) form_raw_income_statement(raw_income_input, bill_overview, db.analysis_date) diff --git a/bpfin/tests/testdata/__inti__.py b/bpfin/tests/testdata/__init__.py similarity index 100% rename from bpfin/tests/testdata/__inti__.py rename to bpfin/tests/testdata/__init__.py -- GitLab From b71db9f86eef6fb58fdec2bece8f13d48bac3552 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 21 Apr 2017 11:08:07 -0400 Subject: [PATCH 07/27] Create organize_bill_overview, income_statement_single_year, faw_income_statement Create test files and sample data --- bpfin/financials/financial_lib.py | 165 ++++++++++++------ .../test_financials/test_financial_lib.py | 26 ++- bpfin/tests/testdata/sample_data.py | 155 +++++++++++----- 3 files changed, 251 insertions(+), 95 deletions(-) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index 154e4a9..8180d4f 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -6,11 +6,11 @@ from bpfin.tests.testdata import sample_data as db # import pprint -# calculate single year income statement given inputs from UI def income_statement_single_year(year, income_input, bill_overview): - '''calculate income statement for 1 year, with inputs from UI and energy bill overview + '''calculate income statement for one single year, with inputs from UI and energy bill overview Args: + year (int): the year of this income statement income_input (dictionary): 4 elements of inputs bill_overview (dictionary): contains annual energy charge for 4 utility types Returns: @@ -20,8 +20,6 @@ def income_statement_single_year(year, income_input, bill_overview): income_input = {revenue': 100000, 'utility_expense': 60000,'non_utility_expense': 3000} bill_overview = {'electricity': electricity_bill, 'oil': oil_bill, 'gas': gas_bill, 'water': water_bill} ''' - - # year = income_input['year'] revenue = income_input['revenue'] utility_expense = income_input['utility_expense'] non_utility_expense = income_input['non_utility_expense'] @@ -58,12 +56,10 @@ def income_statement_single_year(year, income_input, bill_overview): 'total_opex': total_opex, 'noi': noi } - - # print(income_statement) return income_statement -def organize_bill_overview(bill_overview, analysis_date): # !! also need input_flag +def organize_bill_overview(bill_overview, analysis_date): '''take bill_overview as inputs, fill in the blank annual bill with average numbers Args: @@ -77,7 +73,6 @@ def organize_bill_overview(bill_overview, analysis_date): # !! also need input ''' proforma_year = bl.form_bill_year(analysis_date['proforma_start'], analysis_date['proforma_duration']) - # print(proforma_year) bill_dict = {} bill_dict[1] = bill_overview['electricity'] # electricity_bill bill_dict[2] = bill_overview['gas'] # gas_bill @@ -87,7 +82,9 @@ def organize_bill_overview(bill_overview, analysis_date): # !! also need input for i in range(4): if bill_dict[i + 1][1] is False: - average_bill_dict[i + 1] = 0 # !!! build average calculation + average_bill_dict[i + 1] = float( + sum(bill_dict[i + 1][0][year] for year in bill_dict[i + 1][ + 0])) / len(bill_dict[i + 1][0]) for year in proforma_year: for i in range(4): @@ -100,57 +97,121 @@ def organize_bill_overview(bill_overview, analysis_date): # !! also need input 'gas': bill_dict[2][0], 'oil': bill_dict[3][0], 'water': bill_dict[4][0] - } + } return bill_overview_organized # income statements, should be in {2014:{'year':2014, 'revenue': 100000...},2015:{},2016:{}} -def form_raw_income_statement(raw_income_input, bill_overview, analysis_date): - bill_overview_organized = organize_bill_overview(bill_overview, analysis_date) - print(bill_overview_organized) +def form_raw_income_statement(raw_income_input, bill_overview_organized, analysis_date): + ''' form income statement table with raw inputs from UI, and organized bill_overview. NO projection + Args: + raw_income_input (dictionary): dictionary of dictionary. raw inputs for income statement for available years + bill_over_view_organized (dictionary): dict of dict, 4 utility types, with blank charge filled with average + analysis_date (dictionary): proforma's starting date and the years of proforma + Returns: + Dictionary: dict of dict, full income statement for available years + + Description: + raw_income_input = {2014: {'revenue': 90000, 'utility_expense': 55000, 'non_utility_expense': 3500}, 2015:{},} + bill_overview_organized = {'electricity':{2012: 100, 2013: 120, ...}, 'gas':{2012:100,2013:130...},...} + Output = {2014: {'year': 2014, 'revenue': ...}, 2015:{...}, 2016:{...}} + ''' income_statement_full = {} for year in sorted(raw_income_input): - income_statement_full[year] = income_statement_single_year(year, - raw_income_input[year], - bill_overview_organized) - print(income_statement_full[year]) - # print(bill_overview_organized) - - return None - - - -raw_income_input = { - 2014: {'revenue': 90000, 'utility_expense': 55000, 'non_utility_expense': 3500}, - 2015: {'revenue': 95000, 'utility_expense': 55000, 'non_utility_expense': 3000}, - 2016: {'revenue': 100000, 'utility_expense': 60000, 'non_utility_expense': 3000}} - - + income_statement_full[year] = income_statement_single_year( + year, raw_income_input[year], bill_overview_organized) + print(income_statement_full) + return income_statement_full + + +# raw_income_input = { +# 2014: { +# 'revenue': 90000, +# 'utility_expense': 55000, +# 'non_utility_expense': 3500 +# }, +# 2015: { +# 'revenue': 95000, +# 'utility_expense': 55000, +# 'non_utility_expense': 3000 +# }, +# 2016: { +# 'revenue': 100000, +# 'utility_expense': 60000, +# 'non_utility_expense': 3000 +# } +# } -# income_input_2016 = { -# 'year': 2016, -# 'revenue': 100000, -# 'utility_expense': 60000, -# 'non_utility_expense': 3000 +# electricity_bill = { +# 2012: 32220.590596217822, +# 2013: 32782.518348206999, +# 2014: 33293.100530249467, +# 2015: 33546.761580451312, +# 2016: 33844.501703633454, +# 2017: 34523.27291517199, +# 2018: 35384.966283060414, +# 2019: 36251.490761516034, +# 2020: 37100.197369238413, +# 2021: 37887.082013632862, +# 2022: 38603.765037606507, +# 2023: 39307.925216552088, +# 2024: 40028.077679374117, +# 2025: 40772.42926238777, +# 2026: 41575.666985412594, +# 2027: 42439.918590730398, +# 2028: 43325.235463581725, +# 2029: 44211.298795796341, +# 2030: 45097.667796776521, +# 2031: 45986.665329650692, +# 2032: 46886.305428683903, +# 2033: 47806.578908870637, +# 2034: 48751.551094031129, +# 2035: 49722.255450564422, +# 2036: 50718.832984188753 +# } +# oil_bill = {2015: 1010, 2016: 1210, 2017: 1510} +# gas_bill = {2015: 1020, 2016: 1220, 2017: 1520} +# water_bill = {2015: 0, 2016: 0, 2017: 0} + +# bill_overview = { +# 'electricity': [electricity_bill, True], +# 'oil': [oil_bill, False], +# 'gas': [gas_bill, False], +# 'water': [water_bill, False] # } -electricity_bill = { - 2012: 32220.590596217822, 2013: 32782.518348206999, 2014: 33293.100530249467, 2015: 33546.761580451312, - 2016: 33844.501703633454, 2017: 34523.27291517199, 2018: 35384.966283060414, 2019: 36251.490761516034, - 2020: 37100.197369238413, 2021: 37887.082013632862, 2022: 38603.765037606507, 2023: 39307.925216552088, - 2024: 40028.077679374117, 2025: 40772.42926238777, 2026: 41575.666985412594, 2027: 42439.918590730398, - 2028: 43325.235463581725, 2029: 44211.298795796341, 2030: 45097.667796776521, 2031: 45986.665329650692, - 2032: 46886.305428683903, 2033: 47806.578908870637, 2034: 48751.551094031129, 2035: 49722.255450564422, - 2036: 50718.832984188753} -oil_bill = {2015: 1010, 2016: 1210, 2017: 1510} -gas_bill = {2015: 1020, 2016: 1220, 2017: 1520} -water_bill = {2015: 0, 2016: 0, 2017: 0} - -bill_overview = { - 'electricity': [electricity_bill, True], - 'oil': [oil_bill, False], - 'gas': [gas_bill, False], - 'water': [water_bill, False]} +# bill_overview_organized = { +# 'electricity': { +# 2012: 32220.590596217822, 2013: 32782.518348207, 2014: 33293.10053024947, +# 2015: 33546.76158045131, 2016: 33844.501703633454, 2017: 34523.27291517199, +# 2018: 35384.966283060414, 2019: 36251.490761516034, 2020: 37100.19736923841, +# 2021: 37887.08201363286, 2022: 38603.76503760651, 2023: 39307.92521655209, +# 2024: 40028.07767937412, 2025: 40772.42926238777, 2026: 41575.666985412594, +# 2027: 42439.9185907304, 2028: 43325.235463581725, 2029: 44211.29879579634, +# 2030: 45097.66779677652, 2031: 45986.66532965069, 2032: 46886.3054286839, +# 2033: 47806.57890887064, 2034: 48751.55109403113, 2035: 49722.25545056442, +# 2036: 50718.83298418875}, +# 'gas': {2015: 1020, 2016: 1220, 2017: 1520, 2012: 1253.3333333333333, +# 2013: 1253.3333333333333, 2014: 1253.3333333333333, 2018: 1253.3333333333333, +# 2019: 1253.3333333333333, 2020: 1253.3333333333333, 2021: 1253.3333333333333, +# 2022: 1253.3333333333333, 2023: 1253.3333333333333, 2024: 1253.3333333333333, +# 2025: 1253.3333333333333, 2026: 1253.3333333333333, 2027: 1253.3333333333333, +# 2028: 1253.3333333333333, 2029: 1253.3333333333333, 2030: 1253.3333333333333, +# 2031: 1253.3333333333333, 2032: 1253.3333333333333, 2033: 1253.3333333333333, +# 2034: 1253.3333333333333, 2035: 1253.3333333333333, 2036: 1253.3333333333333}, +# 'oil': {2015: 1010, 2016: 1210, 2017: 1510, 2012: 1243.3333333333333, +# 2013: 1243.3333333333333, 2014: 1243.3333333333333, 2018: 1243.3333333333333, +# 2019: 1243.3333333333333, 2020: 1243.3333333333333, 2021: 1243.3333333333333, +# 2022: 1243.3333333333333, 2023: 1243.3333333333333, 2024: 1243.3333333333333, +# 2025: 1243.3333333333333, 2026: 1243.3333333333333, 2027: 1243.3333333333333, +# 2028: 1243.3333333333333, 2029: 1243.3333333333333, 2030: 1243.3333333333333, +# 2031: 1243.3333333333333, 2032: 1243.3333333333333, 2033: 1243.3333333333333, +# 2034: 1243.3333333333333, 2035: 1243.3333333333333, 2036: 1243.3333333333333}, +# 'water': {2015: 0, 2016: 0, 2017: 0, 2012: 0.0, 2013: 0.0, 2014: 0.0, 2018: 0.0, +# 2019: 0.0, 2020: 0.0, 2021: 0.0, 2022: 0.0, 2023: 0.0, 2024: 0.0, +# 2025: 0.0, 2026: 0.0, 2027: 0.0, 2028: 0.0, 2029: 0.0, 2030: 0.0, +# 2031: 0.0, 2032: 0.0, 2033: 0.0, 2034: 0.0, 2035: 0.0, 2036: 0.0} +# } # income_statement_single_year(income_input_2016, bill_overview) -form_raw_income_statement(raw_income_input, bill_overview, db.analysis_date) +form_raw_income_statement(db.raw_income_input, db.bill_overview_organized, db.analysis_date) diff --git a/bpfin/tests/test_financials/test_financial_lib.py b/bpfin/tests/test_financials/test_financial_lib.py index ef71ec8..120ce06 100644 --- a/bpfin/tests/test_financials/test_financial_lib.py +++ b/bpfin/tests/test_financials/test_financial_lib.py @@ -3,9 +3,29 @@ from bpfin.financials import financial_lib as fl from bpfin.tests.testdata import sample_data as db +def test_organize_bill_overview(): + input_bill_overview = db.bill_overview + input_analysis_date = db.analysis_date + output_dict = db.bill_overview_organized + result_dict = fl.organize_bill_overview(input_bill_overview, input_analysis_date) + assert output_dict == result_dict + + def test_income_statement_single_year(): - income_input = db.income_input_2016 - bill_overview = db.bill_overview + input_income = db.income_input_2016 + input_bill_overview_organized = db.bill_overview_organized output_dict = db.income_statement_2016 - result_dict = fl.income_statement_single_year(2016, income_input, bill_overview) + result_dict = fl.income_statement_single_year(2016, input_income, input_bill_overview_organized) + assert output_dict == result_dict + + +def test_form_raw_income_statement(): + input_raw_income_input = db.raw_income_input + input_bill_overview_organized = db.bill_overview_organized + input_analysis_date = db.analysis_date + output_dict = db.income_statement_full + result_dict = fl.form_raw_income_statement( + input_raw_income_input, + input_bill_overview_organized, + input_analysis_date) assert output_dict == result_dict diff --git a/bpfin/tests/testdata/sample_data.py b/bpfin/tests/testdata/sample_data.py index 86aa4e9..a486778 100644 --- a/bpfin/tests/testdata/sample_data.py +++ b/bpfin/tests/testdata/sample_data.py @@ -40,7 +40,6 @@ raw_bill['usage'] = [ 0.092170964664193167, 0.094173672324921492, 0.095187070309577237, 0.097177529967719486, 0.095676831493476874, 0.091583582602530869, 0.089122740090923164, 0.091516956021057888] - monthly_normalized_bill = { 'monthly_usage': [ 0.092656544646156233, 0.081407077375199768, 0.096259845999318444, 0.095904698506193486, @@ -55,11 +54,123 @@ monthly_normalized_bill = { 26817.901843564676, 27005.501339712977, 27201.030152373722, 26618.451410257541, 28498.41164180508, 31875.872144254135, 33930.968787907128, 31671.445647289031]} -# pro-forma projection +# pro-forma projection time base analysis_date = { 'proforma_start': datetime.date(2012, 1, 15), 'proforma_duration': 25} +# prior_projection results are at lower place in this file, due to its super long length + +# organize annual bill overview from UI +annual_bill_electricity = { + 2012: 32220.590596217822, 2013: 32782.518348206999, 2014: 33293.100530249467, 2015: 33546.761580451312, + 2016: 33844.501703633454, 2017: 34523.27291517199, 2018: 35384.966283060414, 2019: 36251.490761516034, + 2020: 37100.197369238413, 2021: 37887.082013632862, 2022: 38603.765037606507, 2023: 39307.925216552088, + 2024: 40028.077679374117, 2025: 40772.42926238777, 2026: 41575.666985412594, 2027: 42439.918590730398, + 2028: 43325.235463581725, 2029: 44211.298795796341, 2030: 45097.667796776521, 2031: 45986.665329650692, + 2032: 46886.305428683903, 2033: 47806.578908870637, 2034: 48751.551094031129, 2035: 49722.255450564422, + 2036: 50718.832984188753} +annual_bill_gas = {2015: 1020, 2016: 1220, 2017: 1520} +annual_bill_oil = {2015: 1010, 2016: 1210, 2017: 1510} +annual_bill_water = {2015: 0, 2016: 0, 2017: 0} + +bill_overview = { + 'electricity': [annual_bill_electricity, True], + 'gas': [annual_bill_gas, False], + 'oil': [annual_bill_oil, False], + 'water': [annual_bill_water, False] +} + +bill_overview_organized = { + 'electricity': { + 2012: 32220.590596217822, 2013: 32782.518348207, 2014: 33293.10053024947, + 2015: 33546.76158045131, 2016: 33844.501703633454, 2017: 34523.27291517199, + 2018: 35384.966283060414, 2019: 36251.490761516034, 2020: 37100.19736923841, + 2021: 37887.08201363286, 2022: 38603.76503760651, 2023: 39307.92521655209, + 2024: 40028.07767937412, 2025: 40772.42926238777, 2026: 41575.666985412594, + 2027: 42439.9185907304, 2028: 43325.235463581725, 2029: 44211.29879579634, + 2030: 45097.66779677652, 2031: 45986.66532965069, 2032: 46886.3054286839, + 2033: 47806.57890887064, 2034: 48751.55109403113, 2035: 49722.25545056442, + 2036: 50718.83298418875}, + 'gas': {2015: 1020, 2016: 1220, 2017: 1520, 2012: 1253.3333333333333, + 2013: 1253.3333333333333, 2014: 1253.3333333333333, 2018: 1253.3333333333333, + 2019: 1253.3333333333333, 2020: 1253.3333333333333, 2021: 1253.3333333333333, + 2022: 1253.3333333333333, 2023: 1253.3333333333333, 2024: 1253.3333333333333, + 2025: 1253.3333333333333, 2026: 1253.3333333333333, 2027: 1253.3333333333333, + 2028: 1253.3333333333333, 2029: 1253.3333333333333, 2030: 1253.3333333333333, + 2031: 1253.3333333333333, 2032: 1253.3333333333333, 2033: 1253.3333333333333, + 2034: 1253.3333333333333, 2035: 1253.3333333333333, 2036: 1253.3333333333333}, + 'oil': {2015: 1010, 2016: 1210, 2017: 1510, 2012: 1243.3333333333333, + 2013: 1243.3333333333333, 2014: 1243.3333333333333, 2018: 1243.3333333333333, + 2019: 1243.3333333333333, 2020: 1243.3333333333333, 2021: 1243.3333333333333, + 2022: 1243.3333333333333, 2023: 1243.3333333333333, 2024: 1243.3333333333333, + 2025: 1243.3333333333333, 2026: 1243.3333333333333, 2027: 1243.3333333333333, + 2028: 1243.3333333333333, 2029: 1243.3333333333333, 2030: 1243.3333333333333, + 2031: 1243.3333333333333, 2032: 1243.3333333333333, 2033: 1243.3333333333333, + 2034: 1243.3333333333333, 2035: 1243.3333333333333, 2036: 1243.3333333333333}, + 'water': {2015: 0, 2016: 0, 2017: 0, 2012: 0.0, 2013: 0.0, 2014: 0.0, 2018: 0.0, + 2019: 0.0, 2020: 0.0, 2021: 0.0, 2022: 0.0, 2023: 0.0, 2024: 0.0, + 2025: 0.0, 2026: 0.0, 2027: 0.0, 2028: 0.0, 2029: 0.0, 2030: 0.0, + 2031: 0.0, 2032: 0.0, 2033: 0.0, 2034: 0.0, 2035: 0.0, 2036: 0.0} +} + +# income statement test +income_input_2016 = { + 'revenue': 100000, + 'utility_expense': 60000, + 'non_utility_expense': 3000} + +income_statement_2016 = { + 'year': 2016, + 'revenue': 100000, + 'utility_expense': 60000, + 'energy_opex': 36274.501703633454, + 'electricity_opex': 33844.501703633454, + 'gas_opex': 1220, + 'oil_opex': 1210, + 'water_opex': 0, + 'other_utility': 23725.498296366546, + 'non_utility_expense': 3000, + 'net_non_energy_opex': 26725.498296366546, + 'total_opex': 63000.0, + 'noi': 37000.0} + +raw_income_input = { + 2014: { + 'revenue': 90000, + 'utility_expense': 55000, + 'non_utility_expense': 3500 + }, + 2015: { + 'revenue': 95000, + 'utility_expense': 55000, + 'non_utility_expense': 3000 + }, + 2016: { + 'revenue': 100000, + 'utility_expense': 60000, + 'non_utility_expense': 3000 + } +} + +income_statement_full = { + 2014: { + 'year': 2014, 'revenue': 90000, 'utility_expense': 55000, 'energy_opex': 35789.76719691614, + 'electricity_opex': 33293.10053024947, 'gas_opex': 1253.3333333333333, 'oil_opex': 1243.3333333333333, 'water_opex': 0.0, + 'other_utility': 19210.23280308386, 'non_utility_expense': 3500, 'net_non_energy_opex': 22710.23280308386, 'total_opex': 58500.0, 'noi': 31500.0}, + 2015: { + 'year': 2015, 'revenue': 95000, 'utility_expense': 55000, 'energy_opex': 35576.76158045131, + 'electricity_opex': 33546.76158045131, 'gas_opex': 1020, 'oil_opex': 1010, 'water_opex': 0, + 'other_utility': 19423.23841954869, 'non_utility_expense': 3000, 'net_non_energy_opex': 22423.23841954869, 'total_opex': 58000.0, 'noi': 37000.0}, + 2016: { + 'year': 2016, 'revenue': 100000, 'utility_expense': 60000, 'energy_opex': 36274.501703633454, + 'electricity_opex': 33844.501703633454, 'gas_opex': 1220, 'oil_opex': 1210, 'water_opex': 0, + 'other_utility': 23725.498296366546, 'non_utility_expense': 3000, 'net_non_energy_opex': 26725.498296366546, 'total_opex': 63000.0, 'noi': 37000.0} +} +# pro-forma date and bill projection - +# proforma_date_from, proforma_date_to +# prior_rough, post_rough +# piror_regress, post_regress proforma_date_from = [ datetime.date(2012, 1, 1), datetime.date(2012, 2, 1), @@ -837,45 +948,9 @@ prior_proj_rough_price = [ 42131.00318614885, 40054.83089682108, 40079.848368848034, 40883.798098440246, 40432.470041231565, 40779.34931771414, 41139.21219179594, 40321.43463472525, 43237.085994998866, 48437.35375945405, 51641.29962190506, 48278.23252154697] -annual_bill_electricity = { - 2012: 32220.590596217822, 2013: 32782.518348206999, 2014: 33293.100530249467, 2015: 33546.761580451312, - 2016: 33844.501703633454, 2017: 34523.27291517199, 2018: 35384.966283060414, 2019: 36251.490761516034, - 2020: 37100.197369238413, 2021: 37887.082013632862, 2022: 38603.765037606507, 2023: 39307.925216552088, - 2024: 40028.077679374117, 2025: 40772.42926238777, 2026: 41575.666985412594, 2027: 42439.918590730398, - 2028: 43325.235463581725, 2029: 44211.298795796341, 2030: 45097.667796776521, 2031: 45986.665329650692, - 2032: 46886.305428683903, 2033: 47806.578908870637, 2034: 48751.551094031129, 2035: 49722.255450564422, - 2036: 50718.832984188753} -annual_bill_gas = {2015: 1020, 2016: 1220, 2017: 1520} -annual_bill_oil = {2015: 1010, 2016: 1210, 2017: 1510} -annual_bill_water = {2015: 0, 2016: 0, 2017: 0} -bill_overview = { - 'electricity': annual_bill_electricity, - 'gas': annual_bill_gas, - 'oil': annual_bill_oil, - 'water': annual_bill_water} - -income_input_2016 = { - # 'year': 2016, - 'revenue': 100000, - 'utility_expense': 60000, - 'non_utility_expense': 3000} - -income_statement_2016 = { - 'year': 2016, - 'revenue': 100000, - 'utility_expense': 60000, - 'energy_opex': 36274.501703633454, - 'electricity_opex': 33844.501703633454, - 'gas_opex': 1220, - 'oil_opex': 1210, - 'water_opex': 0, - 'other_utility': 23725.498296366546, - 'non_utility_expense': 3000, - 'net_non_energy_opex': 26725.498296366546, - 'total_opex': 63000.0, - 'noi': 37000.0} - +# global variables - +# inflation coefficient dictionary. this is NOT inflation rate inflation_coeff_dict = { datetime.date(1981, 1, 31): 0.3381208260704529, datetime.date(1981, 2, 28): 0.3410451203881943, -- GitLab From 047435a25f8a1c0d45e0fe6f6047d19dbebcc535 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 21 Apr 2017 11:16:41 -0400 Subject: [PATCH 08/27] Remove form_inflated_items func from lib_other --- bpfin/lib/other.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bpfin/lib/other.py b/bpfin/lib/other.py index 63cdf26..c82caf8 100644 --- a/bpfin/lib/other.py +++ b/bpfin/lib/other.py @@ -476,13 +476,13 @@ def month_shift(month): # return new_dict #return (2016,2,29 : 99.86%; present_date: 100%) # form inflated items, based on a 12 month list, present time is the last month of 12 months list -def form_inflated_item(base_list,target_terms,inflation_coeff_dict,present_date): - pre_year_date=datetime.date(present_date.year-1,present_date.month+1,cal_last_day(present_date.year-1,present_date.month+1)) - base_terms=form_date_calendar(pre_year_date,present_date)[1] - for term in base_terms: - base_list[term.month-1]=base_list[term.month-1]/inflation_coeff_dict[term] - new_dict=dict(zip([],[])) - for term in target_terms: - new_dict[term]=base_list[term.month-1]*inflation_coeff_dict[term] - return [new_dict[term] for term in sorted(new_dict)] +# def form_inflated_item(base_list,target_terms,inflation_coeff_dict,present_date): +# pre_year_date=datetime.date(present_date.year-1,present_date.month+1,cal_last_day(present_date.year-1,present_date.month+1)) +# base_terms=form_date_calendar(pre_year_date,present_date)[1] +# for term in base_terms: +# base_list[term.month-1]=base_list[term.month-1]/inflation_coeff_dict[term] +# new_dict=dict(zip([],[])) +# for term in target_terms: +# new_dict[term]=base_list[term.month-1]*inflation_coeff_dict[term] +# return [new_dict[term] for term in sorted(new_dict)] -- GitLab From 7518225e2a4d8235cc5615734d6afecb323b8261 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 21 Apr 2017 11:56:06 -0400 Subject: [PATCH 09/27] Improve income_statement_proj_input. Commit to start test on sample_data --- bpfin/financials/financial_lib.py | 1 - bpfin/financials/income_statement_proj_input.py | 9 +++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index 8180d4f..84ce191 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -101,7 +101,6 @@ def organize_bill_overview(bill_overview, analysis_date): return bill_overview_organized -# income statements, should be in {2014:{'year':2014, 'revenue': 100000...},2015:{},2016:{}} def form_raw_income_statement(raw_income_input, bill_overview_organized, analysis_date): ''' form income statement table with raw inputs from UI, and organized bill_overview. NO projection Args: diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py index e2a845a..701556f 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_proj_input.py @@ -3,19 +3,20 @@ from bpfin.tests.testdata import sample_data as db import bpfin.utilbills.bill_lib as bl -def income_statement_proj_input(raw_income_statement, bill_overview, analysis_date, growth_rate_flag): +def income_statement_proj_hist(income_statement_full, bill_overview_organized, analysis_date, growth_rate_flag): '''project income statement for UI input. inputs are whatever bill and financial statements are available Args: - bill_overview (dictionary): bill_overview from UI, with blank cells, for 4 utility_types + income_statement_full (dictionary) + bill_overview_organized (dictionary): bill_overview from UI, with blank cells, for 4 utility_types analysis_date (dictionary): proforma's starting date and the years of proforma + growth_rate_flag (float) Returns: dictionary: ''' proforma_year = bl.form_bill_year(analysis_date['proforma_start'], analysis_date['proforma_duration']) - form_raw_income_statement() + return None -# organize bill_overview # income statements should be availabe for at least 1 year. If comes with 1+ years, suppose to be continued. income_statement_proj_input(db.bill_overview, db.analysis_date) -- GitLab From cebb3b12e0ad78e585926559efd4389b27408a45 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 21 Apr 2017 14:17:18 -0400 Subject: [PATCH 10/27] Improved oil price test Income Statement_proj_input is not finished yet --- .../financials/income_statement_proj_input.py | 3 +-- bpfin/tests/test_utilbills/test_bill_lib.py | 8 ++++++++ .../test_month_normalize_rough.py | 7 +++++++ bpfin/tests/testdata/sample_data.py | 19 +++++++++++++++++++ bpfin/utilbills/bill_lib.py | 1 + 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py index 701556f..b5b8fa0 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_proj_input.py @@ -18,5 +18,4 @@ def income_statement_proj_hist(income_statement_full, bill_overview_organized, a return None # income statements should be availabe for at least 1 year. If comes with 1+ years, suppose to be continued. - -income_statement_proj_input(db.bill_overview, db.analysis_date) +# income_statement_proj_input(db.bill_overview, db.analysis_date) diff --git a/bpfin/tests/test_utilbills/test_bill_lib.py b/bpfin/tests/test_utilbills/test_bill_lib.py index 4eb3034..c6f1410 100644 --- a/bpfin/tests/test_utilbills/test_bill_lib.py +++ b/bpfin/tests/test_utilbills/test_bill_lib.py @@ -30,3 +30,11 @@ def test_form_bill_year(): output_list = [2012, 2013, 2014, 2015, 2016] result_list = bl.form_bill_year(start_date, year_term) assert output_list == result_list + + +def test_cal_oil_price(): + input_oiluse = [1, 2, 3, 4, 5, 6] + input_oilcharge = [12, 10, 8, 6, 4, 2] + output_list = [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0] + result_list = bl.cal_oil_price(input_oilcharge, input_oiluse) + assert output_list == result_list diff --git a/bpfin/tests/test_utilbills/test_month_normalize_rough.py b/bpfin/tests/test_utilbills/test_month_normalize_rough.py index 29f21d5..04a6cbc 100644 --- a/bpfin/tests/test_utilbills/test_month_normalize_rough.py +++ b/bpfin/tests/test_utilbills/test_month_normalize_rough.py @@ -10,3 +10,10 @@ def test_month_normalization_rough(): result_dict = bill_month_normalize_rough(input_dict) assert result_dict == output_dict + + +def test_month_normalization_rough_oil(): + input_dict = db.raw_bill_oil + output_dict = db.monthly_normalized_bill_oil + result_dict = bill_month_normalize_rough(input_dict) + assert result_dict == output_dict diff --git a/bpfin/tests/testdata/sample_data.py b/bpfin/tests/testdata/sample_data.py index a486778..1cd184c 100644 --- a/bpfin/tests/testdata/sample_data.py +++ b/bpfin/tests/testdata/sample_data.py @@ -54,6 +54,25 @@ monthly_normalized_bill = { 26817.901843564676, 27005.501339712977, 27201.030152373722, 26618.451410257541, 28498.41164180508, 31875.872144254135, 33930.968787907128, 31671.445647289031]} +raw_bill_oil = {} +raw_bill_oil['utility_type'] = 'oil' +raw_bill_oil['date_from'] = raw_bill['date_from'] +raw_bill_oil['date_to'] = raw_bill['date_to'] +raw_bill_oil['charge'] = raw_bill['charge'] +raw_bill_oil['usage'] = raw_bill['usage'] +monthly_normalized_bill_oil = { + 'monthly_usage': [ + 0.092656544646156233, 0.081407077375199768, 0.096259845999318444, 0.095904698506193486, + 0.09970580811571926, 0.10713597790787066, 0.12362302566814179, 0.10416990876794137, + 0.090033196083726619, 0.099460650112727964, 0.093068756936307756, 0.094710339831841669], + 'monthly_charge': [ + 2641.5304891952883, 2320.8212408964555, 2744.2564263914742, 2734.1315837823149, + 2842.4968046599106, 3054.3223170489046, 3524.3489028868621, 2969.7631302574569, + 2566.7418680794467, 2835.5076346876781, 2653.282182900407, 2700.0818049417217], + 'monthly_price': [ + 28508.83873646447, 28508.83873646447, 28508.83873646447, 28508.83873646447, + 28508.83873646447, 28508.83873646447, 28508.83873646447, 28508.83873646447, + 28508.83873646447, 28508.83873646447, 28508.83873646447, 28508.83873646447]} # pro-forma projection time base analysis_date = { 'proforma_start': datetime.date(2012, 1, 15), diff --git a/bpfin/utilbills/bill_lib.py b/bpfin/utilbills/bill_lib.py index af85d6f..150993e 100644 --- a/bpfin/utilbills/bill_lib.py +++ b/bpfin/utilbills/bill_lib.py @@ -1,6 +1,7 @@ import statsmodels.api as sm import datetime import calendar +import pandas as pd def add_list(obj_list, number): -- GitLab From e7b5b8a4428ca5729051b8872e3a53b1149a17d4 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 21 Apr 2017 16:01:18 -0400 Subject: [PATCH 11/27] Fix test_bill_lib, form_inflated_items, by adding copy func, so the original list won't be modified in memory during test all units --- bpfin/utilbills/bill_lib.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bpfin/utilbills/bill_lib.py b/bpfin/utilbills/bill_lib.py index 150993e..9411a12 100644 --- a/bpfin/utilbills/bill_lib.py +++ b/bpfin/utilbills/bill_lib.py @@ -2,6 +2,7 @@ import statsmodels.api as sm import datetime import calendar import pandas as pd +import copy def add_list(obj_list, number): @@ -201,11 +202,12 @@ def form_inflated_item(base_list, target_terms, inflation_coeff_dict, present_da present_date.month + 1, cal_last_day(present_date.year - 1, present_date.month + 1)) base_terms = form_date_calendar(pre_year_date, present_date)[1] + base_list_copy = copy.deepcopy(base_list) for term in base_terms: - base_list[term.month - 1] = base_list[term.month-1] / inflation_coeff_dict[term] + base_list_copy[term.month - 1] = base_list_copy[term.month-1] / inflation_coeff_dict[term] new_dict = dict(zip([], [])) for term in target_terms: - new_dict[term] = base_list[term.month - 1] * inflation_coeff_dict[term] + new_dict[term] = base_list_copy[term.month - 1] * inflation_coeff_dict[term] return [new_dict[term] for term in sorted(new_dict)] -- GitLab From 8d2cdfe1aaa7305b5ad5d142748d43ed269b8fd6 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Fri, 21 Apr 2017 16:21:05 -0400 Subject: [PATCH 12/27] Clean up sample data and test file, minor formatting --- bpfin/tests/test_utilbills/test_bill_lib.py | 1 - bpfin/tests/testdata/sample_data.py | 12 ++++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/bpfin/tests/test_utilbills/test_bill_lib.py b/bpfin/tests/test_utilbills/test_bill_lib.py index 96256c8..c6f1410 100644 --- a/bpfin/tests/test_utilbills/test_bill_lib.py +++ b/bpfin/tests/test_utilbills/test_bill_lib.py @@ -24,7 +24,6 @@ def test_annualizing_projection(): assert output_dictionary == result -<<<<<<< HEAD def test_form_bill_year(): start_date = datetime(2012, 2, 14) year_term = 5 diff --git a/bpfin/tests/testdata/sample_data.py b/bpfin/tests/testdata/sample_data.py index f9581a8..8dc0523 100644 --- a/bpfin/tests/testdata/sample_data.py +++ b/bpfin/tests/testdata/sample_data.py @@ -176,16 +176,20 @@ raw_income_input = { income_statement_full = { 2014: { 'year': 2014, 'revenue': 90000, 'utility_expense': 55000, 'energy_opex': 35789.76719691614, - 'electricity_opex': 33293.10053024947, 'gas_opex': 1253.3333333333333, 'oil_opex': 1243.3333333333333, 'water_opex': 0.0, - 'other_utility': 19210.23280308386, 'non_utility_expense': 3500, 'net_non_energy_opex': 22710.23280308386, 'total_opex': 58500.0, 'noi': 31500.0}, + 'electricity_opex': 33293.10053024947, 'gas_opex': 1253.3333333333333, + 'oil_opex': 1243.3333333333333, 'water_opex': 0.0, + 'other_utility': 19210.23280308386, 'non_utility_expense': 3500, 'net_non_energy_opex': 22710.23280308386, + 'total_opex': 58500.0, 'noi': 31500.0}, 2015: { 'year': 2015, 'revenue': 95000, 'utility_expense': 55000, 'energy_opex': 35576.76158045131, 'electricity_opex': 33546.76158045131, 'gas_opex': 1020, 'oil_opex': 1010, 'water_opex': 0, - 'other_utility': 19423.23841954869, 'non_utility_expense': 3000, 'net_non_energy_opex': 22423.23841954869, 'total_opex': 58000.0, 'noi': 37000.0}, + 'other_utility': 19423.23841954869, 'non_utility_expense': 3000, 'net_non_energy_opex': 22423.23841954869, + 'total_opex': 58000.0, 'noi': 37000.0}, 2016: { 'year': 2016, 'revenue': 100000, 'utility_expense': 60000, 'energy_opex': 36274.501703633454, 'electricity_opex': 33844.501703633454, 'gas_opex': 1220, 'oil_opex': 1210, 'water_opex': 0, - 'other_utility': 23725.498296366546, 'non_utility_expense': 3000, 'net_non_energy_opex': 26725.498296366546, 'total_opex': 63000.0, 'noi': 37000.0} + 'other_utility': 23725.498296366546, 'non_utility_expense': 3000, 'net_non_energy_opex': 26725.498296366546, + 'total_opex': 63000.0, 'noi': 37000.0} } # liability, mortgage and other debt data -- GitLab From a88a31a25baaff468710f111eff357c7545a4062 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Sat, 22 Apr 2017 00:07:28 -0400 Subject: [PATCH 13/27] Create Income Statement Class to estimate next year financial. Create income statement functions --- bpfin/financials/financial_lib.py | 28 ++++++- .../financials/income_statement_proj_input.py | 74 +++++++++++++++++-- bpfin/lib/other.py | 16 +++- .../test_income_statement_proj_input.py | 15 ++++ 4 files changed, 121 insertions(+), 12 deletions(-) create mode 100644 bpfin/tests/test_financials/test_income_statement_proj_input.py diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index 84ce191..514fa5c 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -119,7 +119,6 @@ def form_raw_income_statement(raw_income_input, bill_overview_organized, analysi for year in sorted(raw_income_input): income_statement_full[year] = income_statement_single_year( year, raw_income_input[year], bill_overview_organized) - print(income_statement_full) return income_statement_full @@ -213,4 +212,29 @@ def form_raw_income_statement(raw_income_input, bill_overview_organized, analysi # } # income_statement_single_year(income_input_2016, bill_overview) -form_raw_income_statement(db.raw_income_input, db.bill_overview_organized, db.analysis_date) +# form_raw_income_statement(db.raw_income_input, db.bill_overview_organized, db.analysis_date) + +class Income_Statement(): + def __init__(self): + self.year + self.revenue + self.utility_expense + self.non_utility_expense + self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex + self.energy_opex + self.other_utility + self.net_non_energy_opex + self.total_opex + self.noi + + def assign_next(self, other_utility_percent, non_utility_expense_percent): + self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex + self.other_utility = self.revenue * other_utility_percent + self.non_utility_expense = self.revenue * self.non_utility_expense_percent + self.utility_expense = self.energy_opex + self.other_utility + self.net_non_energy_opex = self.other_utility + self.non_utility_expense + self.total_opex = self.energy_opex + self.net_non_energy_opex + self.noi = self.revenue - self.total_opex diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py index b5b8fa0..672cd95 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_proj_input.py @@ -1,10 +1,42 @@ -from bpfin.financials import financial_lib as fl -from bpfin.tests.testdata import sample_data as db +import bpfin.financials.financial_lib as fl +import bpfin.tests.testdata.sample_data as db import bpfin.utilbills.bill_lib as bl +from bpfin.lib import other as lib -def income_statement_proj_hist(income_statement_full, bill_overview_organized, analysis_date, growth_rate_flag): - '''project income statement for UI input. inputs are whatever bill and financial statements are available +def income_statement_character(income_statement_full): + '''Determine annual growth rate, other_utility_percentage, non_utility_expense_percentage + Args: + income_statement_full (dictionary): full income statement, with all items filled, for available years + Return: + dictionary: three characters for future projection + + Description: + income_statement_full = {2014:{'revenue': 100000, ... ,'noi':37000}, 2015:{}, 2016:{}} + output = {'cagr': 2.45, 'other_utility_percentage': 20.4%, 'non_utility_expense_percentage': 43.5%} + ''' + start_year = sorted(income_statement_full)[0] + end_year = sorted(income_statement_full)[-1] + cagr = lib.cal_cagr( + income_statement_full[start_year]['revenue'], + income_statement_full[end_year]['revenue'], + end_year - start_year) + revenue_sum = 0 + other_utility_sum = 0 + non_utility_expense_sum = 0 + for year in sorted(income_statement_full): + revenue_sum += income_statement_full[year]['revenue'] + other_utility_sum += income_statement_full[year]['other_utility'] + non_utility_expense_sum += income_statement_full[year]['non_utility_expense'] + result_dict = { + 'cagr': cagr, + 'other_utility_percent': other_utility_sum/revenue_sum, + 'non_utility_expense_percent': non_utility_expense_sum/revenue_sum} + return result_dict + + +def income_statement_proj_input(income_statement_full, bill_overview_organized, analysis_date, growth_rate_flag): + '''Project income statement for UI input. inputs are whatever bill and financial statements are available Args: income_statement_full (dictionary) bill_overview_organized (dictionary): bill_overview from UI, with blank cells, for 4 utility_types @@ -13,9 +45,39 @@ def income_statement_proj_hist(income_statement_full, bill_overview_organized, a Returns: dictionary: ''' - proforma_year = bl.form_bill_year(analysis_date['proforma_start'], analysis_date['proforma_duration']) + # proforma_year = bl.form_bill_year(analysis_date['proforma_start'], analysis_date['proforma_duration']) + characters = income_statement_character(income_statement_full) + cagr = characters['cagr'] + other_utility_percent = characters['other_utility_percent'] + non_utility_expense_percent = characters['non_utility_expense_percent'] + growth_rate = cagr # !!!! need logic for growth_rate_flag + end_year = sorted(income_statement_full)[-1] + # print(end_year) + income_statement_next = fl.Income_Statement + income_statement_next.year = end_year + 1 + income_statement_next.revenue = income_statement_full[end_year]['revenue'] * (1 + growth_rate) + income_statement_next.electricity_opex = bill_overview_organized['electricity'][end_year + 1] + income_statement_next.gas_opex = bill_overview_organized['gas'][end_year + 1] + income_statement_next.oil_opex = bill_overview_organized['oil'][end_year + 1] + income_statement_next.water_opex = bill_overview_organized['water'][end_year + 1] + income_statement_next.assign_next(other_utility_percent, non_utility_expense_percent) + print(income_statement_next.noi) return None +# # for year in range(self.IS_end + 1, scenario.loan_end_year + 1): +# # self.year.append(year) +# # year_terms = form_year_terms(year) +# # self.revenue[year] = self.revenue[year - 1] * (1 + scenario.CAGR_revenue) +# # self.energy_opex[year] = (sum(align2term(cash_flow.terms, cash_flow.post_total, year_terms))) +# # self.other_utility[year] = self.revenue[year] * self.other_utility_perct +# # self.non_utility_expense[year] = self.revenue[year] * self.non_utility_expense_perct +# # self.utility_expense[year] = self.energy_opex[year] + self.other_utility[year] +# # self.net_non_energy_opex[year] = self.other_utility[year] + self.non_utility_expense[year] +# # self.total_opex[year] = self.energy_opex[year] + self.net_non_energy_opex[year] +# # self.noi[year] = self.revenue[year] - self.total_opex[year] + + # income statements should be availabe for at least 1 year. If comes with 1+ years, suppose to be continued. -# income_statement_proj_input(db.bill_overview, db.analysis_date) +# income_statement_character(db.income_statement_full) +income_statement_proj_input(db.income_statement_full, db.bill_overview_organized, db.analysis_date, 0.01) diff --git a/bpfin/lib/other.py b/bpfin/lib/other.py index c82caf8..846a522 100644 --- a/bpfin/lib/other.py +++ b/bpfin/lib/other.py @@ -316,12 +316,20 @@ def average(list1): return sum(list1) / len(list1) -def cal_CAGR(start_value, end_value, n): +def cal_cagr(start_value, end_value, n): + ''' Calculate compound anual growth rate + Args: + start_value (float): first year value + nd_value (float): last year value + n (int): first year - last year + Return: + float: anual growth rate + ''' if start_value != 0: - CAGR = (end_value / start_value) ** (1 / n) - 1 + cagr = (end_value / start_value) ** (1 / n) - 1 else: - CAGR = 0 - return CAGR + cagr = 0 + return cagr # build the matrix to reflect #of days in each month diff --git a/bpfin/tests/test_financials/test_income_statement_proj_input.py b/bpfin/tests/test_financials/test_income_statement_proj_input.py new file mode 100644 index 0000000..7320949 --- /dev/null +++ b/bpfin/tests/test_financials/test_income_statement_proj_input.py @@ -0,0 +1,15 @@ +# import datetime +from bpfin.financials import financial_lib as fl +from bpfin.tests.testdata import sample_data as db +from bpfin.financials.income_statement_proj_input import income_statement_character +# from bpfin.financials.income_statement_proj_input import income_statement_proj_input + + +def test_income_statement_character(): + input_income_statement_full = db.income_statement_full + output_dict = { + 'cagr': 0.05409255338945984, + 'other_utility_percent': 0.21880340182104946, + 'non_utility_expense_percent': 0.03333333333333333} + result_dict = income_statement_character(input_income_statement_full) + assert output_dict == result_dict -- GitLab From 8ccbf85d9e461905b51c12425600dd36e9929421 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Sat, 22 Apr 2017 12:06:39 -0400 Subject: [PATCH 14/27] Create income_statement_proj_input, and its test file, sample_data Still need to work on growth_rate_flag --- bpfin/financials/financial_lib.py | 50 +++++++++++++------ .../financials/income_statement_proj_input.py | 15 +++--- .../test_financials/test_financial_lib.py | 14 ++++++ bpfin/tests/testdata/sample_data.py | 7 +++ 4 files changed, 63 insertions(+), 23 deletions(-) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index 514fa5c..7724bb4 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -216,25 +216,47 @@ def form_raw_income_statement(raw_income_input, bill_overview_organized, analysi class Income_Statement(): def __init__(self): - self.year - self.revenue - self.utility_expense - self.non_utility_expense - self.electricity_opex - self.gas_opex - self.oil_opex - self.water_opex - self.energy_opex - self.other_utility - self.net_non_energy_opex - self.total_opex - self.noi + self.year = None + self.revenue = None + self.utility_expense = None + self.non_utility_expense = None + self.electricity_opex = None + self.gas_opex = None + self.oil_opex = None + self.water_opex = None + self.energy_opex = None + self.other_utility = None + self.net_non_energy_opex = None + self.total_opex = None + self.noi = None def assign_next(self, other_utility_percent, non_utility_expense_percent): + # print('\n other_utility_percent',other_utility_percent) + # print('\n non_utility_expense_percent',non_utility_expense_percent) self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex + # print('\n',self.energy_opex) + # print('\n revenue', self.revenue) self.other_utility = self.revenue * other_utility_percent - self.non_utility_expense = self.revenue * self.non_utility_expense_percent + self.non_utility_expense = self.revenue * non_utility_expense_percent self.utility_expense = self.energy_opex + self.other_utility self.net_non_energy_opex = self.other_utility + self.non_utility_expense self.total_opex = self.energy_opex + self.net_non_energy_opex self.noi = self.revenue - self.total_opex + + +def convert_income_statement_class(income_statement_class): + income_statement_dict = { + 'year': income_statement_class.year, + 'revenue': income_statement_class.revenue, + 'utility_expense': income_statement_class.utility_expense, + 'energy_opex': income_statement_class.energy_opex, + 'electricity_opex': income_statement_class.electricity_opex, + 'gas_opex': income_statement_class.gas_opex, + 'oil_opex': income_statement_class.oil_opex, + 'water_opex': income_statement_class.water_opex, + 'other_utility': income_statement_class.other_utility, + 'non_utility_expense': income_statement_class.non_utility_expense, + 'net_non_energy_opex': income_statement_class.net_non_energy_opex, + 'total_opex': income_statement_class.total_opex, + 'noi': income_statement_class.noi} + return income_statement_dict diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py index 672cd95..c4b973f 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_proj_input.py @@ -35,7 +35,7 @@ def income_statement_character(income_statement_full): return result_dict -def income_statement_proj_input(income_statement_full, bill_overview_organized, analysis_date, growth_rate_flag): +def income_statement_proj_input(income_statement_full, bill_overview_organized, growth_rate_flag): '''Project income statement for UI input. inputs are whatever bill and financial statements are available Args: income_statement_full (dictionary) @@ -52,8 +52,7 @@ def income_statement_proj_input(income_statement_full, bill_overview_organized, non_utility_expense_percent = characters['non_utility_expense_percent'] growth_rate = cagr # !!!! need logic for growth_rate_flag end_year = sorted(income_statement_full)[-1] - # print(end_year) - income_statement_next = fl.Income_Statement + income_statement_next = fl.Income_Statement() income_statement_next.year = end_year + 1 income_statement_next.revenue = income_statement_full[end_year]['revenue'] * (1 + growth_rate) income_statement_next.electricity_opex = bill_overview_organized['electricity'][end_year + 1] @@ -61,9 +60,8 @@ def income_statement_proj_input(income_statement_full, bill_overview_organized, income_statement_next.oil_opex = bill_overview_organized['oil'][end_year + 1] income_statement_next.water_opex = bill_overview_organized['water'][end_year + 1] income_statement_next.assign_next(other_utility_percent, non_utility_expense_percent) - - print(income_statement_next.noi) - return None + result_dict = fl.convert_income_statement_class(income_statement_next) + return result_dict # # for year in range(self.IS_end + 1, scenario.loan_end_year + 1): # # self.year.append(year) @@ -78,6 +76,5 @@ def income_statement_proj_input(income_statement_full, bill_overview_organized, # # self.noi[year] = self.revenue[year] - self.total_opex[year] -# income statements should be availabe for at least 1 year. If comes with 1+ years, suppose to be continued. -# income_statement_character(db.income_statement_full) -income_statement_proj_input(db.income_statement_full, db.bill_overview_organized, db.analysis_date, 0.01) +# income statements should be availabe for at least 1 year. If comes with >1 years, suppose to be continued. +income_statement_proj_input(db.income_statement_full, db.bill_overview_organized, 0.01) diff --git a/bpfin/tests/test_financials/test_financial_lib.py b/bpfin/tests/test_financials/test_financial_lib.py index 120ce06..b6dcc52 100644 --- a/bpfin/tests/test_financials/test_financial_lib.py +++ b/bpfin/tests/test_financials/test_financial_lib.py @@ -1,6 +1,7 @@ import datetime from bpfin.financials import financial_lib as fl from bpfin.tests.testdata import sample_data as db +from bpfin.financials.income_statement_proj_input import income_statement_proj_input def test_organize_bill_overview(): @@ -29,3 +30,16 @@ def test_form_raw_income_statement(): input_bill_overview_organized, input_analysis_date) assert output_dict == result_dict + + +def test_income_statement_proj_input(): + input_income_statement_full = db.income_statement_full + input_bill_overview_organized = db.bill_overview_organized + # input_analysis_date = db.analysis_date + input_growth_rate_flag = 0.01 + output_dict = db.income_input_next + result_dict = income_statement_proj_input( + input_income_statement_full, + input_bill_overview_organized, + input_growth_rate_flag) + assert output_dict == result_dict diff --git a/bpfin/tests/testdata/sample_data.py b/bpfin/tests/testdata/sample_data.py index 8dc0523..da8e91b 100644 --- a/bpfin/tests/testdata/sample_data.py +++ b/bpfin/tests/testdata/sample_data.py @@ -192,6 +192,13 @@ income_statement_full = { 'total_opex': 63000.0, 'noi': 37000.0} } +income_input_next = { + 'year': 2017, 'revenue': 105409.25533894598, 'utility_expense': 60617.176566756985, 'energy_opex': 37553.27291517199, + 'electricity_opex': 34523.27291517199, 'gas_opex': 1520, 'oil_opex': 1510, 'water_opex': 0, + 'other_utility': 23063.903651585, 'non_utility_expense': 3513.6418446315324, 'net_non_energy_opex': 26577.54549621653, + 'total_opex': 64130.81841138852, 'noi': 41278.43692755746} + + # liability, mortgage and other debt data liability_dictionary = { 'debt1': (150, 'NYSERDA', 10, datetime.date(2012, 12, 31)), -- GitLab From d04f7e343b29376c76b246e95cc35e0f49ed8aac Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Sat, 22 Apr 2017 12:09:12 -0400 Subject: [PATCH 15/27] Clean comments minorly --- bpfin/financials/income_statement_proj_input.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py index c4b973f..6d73233 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_proj_input.py @@ -63,18 +63,5 @@ def income_statement_proj_input(income_statement_full, bill_overview_organized, result_dict = fl.convert_income_statement_class(income_statement_next) return result_dict -# # for year in range(self.IS_end + 1, scenario.loan_end_year + 1): -# # self.year.append(year) -# # year_terms = form_year_terms(year) -# # self.revenue[year] = self.revenue[year - 1] * (1 + scenario.CAGR_revenue) -# # self.energy_opex[year] = (sum(align2term(cash_flow.terms, cash_flow.post_total, year_terms))) -# # self.other_utility[year] = self.revenue[year] * self.other_utility_perct -# # self.non_utility_expense[year] = self.revenue[year] * self.non_utility_expense_perct -# # self.utility_expense[year] = self.energy_opex[year] + self.other_utility[year] -# # self.net_non_energy_opex[year] = self.other_utility[year] + self.non_utility_expense[year] -# # self.total_opex[year] = self.energy_opex[year] + self.net_non_energy_opex[year] -# # self.noi[year] = self.revenue[year] - self.total_opex[year] - - # income statements should be availabe for at least 1 year. If comes with >1 years, suppose to be continued. -income_statement_proj_input(db.income_statement_full, db.bill_overview_organized, 0.01) +# income_statement_proj_input(db.income_statement_full, db.bill_overview_organized, 0.01) -- GitLab From 3bf09b447844a3255f264dd1225ecf4d65dd81da Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Sun, 23 Apr 2017 00:23:24 -0400 Subject: [PATCH 16/27] Try to create income_statement_next_year func in income_statement_proj_input. Maybe should move to IS class. Save before bed --- bpfin/financials/financial_lib.py | 4 +- .../financials/income_statement_proj_input.py | 58 ++++++++++++++----- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index 7724bb4..8081230 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -230,7 +230,7 @@ class Income_Statement(): self.total_opex = None self.noi = None - def assign_next(self, other_utility_percent, non_utility_expense_percent): + def assign_next_year(self, other_utility_percent, non_utility_expense_percent): # print('\n other_utility_percent',other_utility_percent) # print('\n non_utility_expense_percent',non_utility_expense_percent) self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex @@ -243,6 +243,8 @@ class Income_Statement(): self.total_opex = self.energy_opex + self.net_non_energy_opex self.noi = self.revenue - self.total_opex + def assign_next(self, ) + def convert_income_statement_class(income_statement_class): income_statement_dict = { diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py index 6d73233..62b0583 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_proj_input.py @@ -17,6 +17,7 @@ def income_statement_character(income_statement_full): ''' start_year = sorted(income_statement_full)[0] end_year = sorted(income_statement_full)[-1] + # if start_year == None: return None cagr = lib.cal_cagr( income_statement_full[start_year]['revenue'], income_statement_full[end_year]['revenue'], @@ -24,44 +25,69 @@ def income_statement_character(income_statement_full): revenue_sum = 0 other_utility_sum = 0 non_utility_expense_sum = 0 + revenue_average = 0 for year in sorted(income_statement_full): revenue_sum += income_statement_full[year]['revenue'] other_utility_sum += income_statement_full[year]['other_utility'] non_utility_expense_sum += income_statement_full[year]['non_utility_expense'] + revenue_average = revenue_sum / (end_year - start_year + 1) result_dict = { 'cagr': cagr, 'other_utility_percent': other_utility_sum/revenue_sum, - 'non_utility_expense_percent': non_utility_expense_sum/revenue_sum} + 'non_utility_expense_percent': non_utility_expense_sum/revenue_sum, + 'revenue_average': revenue_average + } return result_dict -def income_statement_proj_input(income_statement_full, bill_overview_organized, growth_rate_flag): +def income_statement_next(income_statement_hist, bill_overview_organized, growth_rate_flag): '''Project income statement for UI input. inputs are whatever bill and financial statements are available Args: - income_statement_full (dictionary) + income_statement_hist (dictionary): historical income statement, with all items filled, for available years bill_overview_organized (dictionary): bill_overview from UI, with blank cells, for 4 utility_types analysis_date (dictionary): proforma's starting date and the years of proforma growth_rate_flag (float) Returns: dictionary: ''' - # proforma_year = bl.form_bill_year(analysis_date['proforma_start'], analysis_date['proforma_duration']) - characters = income_statement_character(income_statement_full) + characters = income_statement_character(income_statement_hist) cagr = characters['cagr'] other_utility_percent = characters['other_utility_percent'] non_utility_expense_percent = characters['non_utility_expense_percent'] + revenue_average = characters['revenue_average'] growth_rate = cagr # !!!! need logic for growth_rate_flag - end_year = sorted(income_statement_full)[-1] - income_statement_next = fl.Income_Statement() - income_statement_next.year = end_year + 1 - income_statement_next.revenue = income_statement_full[end_year]['revenue'] * (1 + growth_rate) - income_statement_next.electricity_opex = bill_overview_organized['electricity'][end_year + 1] - income_statement_next.gas_opex = bill_overview_organized['gas'][end_year + 1] - income_statement_next.oil_opex = bill_overview_organized['oil'][end_year + 1] - income_statement_next.water_opex = bill_overview_organized['water'][end_year + 1] - income_statement_next.assign_next(other_utility_percent, non_utility_expense_percent) - result_dict = fl.convert_income_statement_class(income_statement_next) - return result_dict + + + + +# def income_statement_proj_input(income_statement_full, bill_overview_organized, growth_rate_flag): +# '''Project income statement for UI input. inputs are whatever bill and financial statements are available +# Args: +# income_statement_full (dictionary) +# bill_overview_organized (dictionary): bill_overview from UI, with blank cells, for 4 utility_types +# analysis_date (dictionary): proforma's starting date and the years of proforma +# growth_rate_flag (float) +# Returns: +# dictionary: +# ''' +# # proforma_year = bl.form_bill_year(analysis_date['proforma_start'], analysis_date['proforma_duration']) +# characters = income_statement_character(income_statement_full) +# cagr = characters['cagr'] +# other_utility_percent = characters['other_utility_percent'] +# non_utility_expense_percent = characters['non_utility_expense_percent'] +# growth_rate = cagr # !!!! need logic for growth_rate_flag +# end_year = sorted(income_statement_full)[-1] +# income_statement_next = fl.Income_Statement() +# income_statement_next.year = end_year + 1 +# income_statement_next.revenue = income_statement_full[end_year]['revenue'] * (1 + growth_rate) +# income_statement_next.electricity_opex = bill_overview_organized['electricity'][end_year + 1] +# income_statement_next.gas_opex = bill_overview_organized['gas'][end_year + 1] +# income_statement_next.oil_opex = bill_overview_organized['oil'][end_year + 1] +# income_statement_next.water_opex = bill_overview_organized['water'][end_year + 1] +# income_statement_next.assign_next_year(other_utility_percent, non_utility_expense_percent) +# result_dict = fl.convert_income_statement_class(income_statement_next) +# return result_dict # income statements should be availabe for at least 1 year. If comes with >1 years, suppose to be continued. # income_statement_proj_input(db.income_statement_full, db.bill_overview_organized, 0.01) + -- GitLab From 7b6da7d547c842f185d7d955055f5c6e1d12f36c Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Sun, 23 Apr 2017 12:23:58 -0400 Subject: [PATCH 17/27] Tem Save --- bpfin/financials/financial_lib.py | 14 +++++++++++++- bpfin/financials/income_statement_proj_input.py | 14 +++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index 8081230..9b7aac7 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -243,7 +243,19 @@ class Income_Statement(): self.total_opex = self.energy_opex + self.net_non_energy_opex self.noi = self.revenue - self.total_opex - def assign_next(self, ) + def assign_next(self, income_statement_characters, bill_overview_organized): + other_utility_percent = income_statement_characters[''] + # print('\n other_utility_percent',other_utility_percent) + # print('\n non_utility_expense_percent',non_utility_expense_percent) + self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex + # print('\n',self.energy_opex) + # print('\n revenue', self.revenue) + self.other_utility = self.revenue * other_utility_percent + self.non_utility_expense = self.revenue * non_utility_expense_percent + self.utility_expense = self.energy_opex + self.other_utility + self.net_non_energy_opex = self.other_utility + self.non_utility_expense + self.total_opex = self.energy_opex + self.net_non_energy_opex + self.noi = self.revenue - self.total_opex def convert_income_statement_class(income_statement_class): diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py index 62b0583..1570383 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_proj_input.py @@ -50,13 +50,17 @@ def income_statement_next(income_statement_hist, bill_overview_organized, growth Returns: dictionary: ''' - characters = income_statement_character(income_statement_hist) - cagr = characters['cagr'] - other_utility_percent = characters['other_utility_percent'] - non_utility_expense_percent = characters['non_utility_expense_percent'] - revenue_average = characters['revenue_average'] + income_statement_characters = income_statement_character(income_statement_hist) + # cagr = characters['cagr'] + # other_utility_percent = characters['other_utility_percent'] + # non_utility_expense_percent = characters['non_utility_expense_percent'] + # revenue_average = characters['revenue_average'] + growth_rate = cagr # !!!! need logic for growth_rate_flag + income_statement_next = fl.Income_Statement() + income_statement_next.revenue = income_statement_characters['revenue_average'] + income_statement_next.assign_next(income_statement_characters, bill_overview_organized) -- GitLab From c6addf3a81139ba960f4ade976a1d096b99e0bc5 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Mon, 24 Apr 2017 10:58:11 -0400 Subject: [PATCH 18/27] Modify income_statement_next func. Not finished yet, but better than previous version. Update financial_lib Income_Statement class method, test files. No need to update sample data --- bpfin/financials/financial_lib.py | 13 ++++++------- bpfin/financials/income_statement_proj_input.py | 14 +++++++++----- bpfin/tests/test_financials/test_financial_lib.py | 8 +++++--- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index 9b7aac7..c89e927 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -244,14 +244,13 @@ class Income_Statement(): self.noi = self.revenue - self.total_opex def assign_next(self, income_statement_characters, bill_overview_organized): - other_utility_percent = income_statement_characters[''] - # print('\n other_utility_percent',other_utility_percent) - # print('\n non_utility_expense_percent',non_utility_expense_percent) + self.electricity_opex = bill_overview_organized['electricity'][self.year] + self.gas_opex = bill_overview_organized['gas'][self.year] + self.oil_opex = bill_overview_organized['oil'][self.year] + self.water_opex = bill_overview_organized['water'][self.year] self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex - # print('\n',self.energy_opex) - # print('\n revenue', self.revenue) - self.other_utility = self.revenue * other_utility_percent - self.non_utility_expense = self.revenue * non_utility_expense_percent + self.other_utility = self.revenue * income_statement_characters['other_utility_percent'] + self.non_utility_expense = self.revenue * income_statement_characters['non_utility_expense_percent'] self.utility_expense = self.energy_opex + self.other_utility self.net_non_energy_opex = self.other_utility + self.non_utility_expense self.total_opex = self.energy_opex + self.net_non_energy_opex diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py index 1570383..8389685 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_proj_input.py @@ -40,7 +40,7 @@ def income_statement_character(income_statement_full): return result_dict -def income_statement_next(income_statement_hist, bill_overview_organized, growth_rate_flag): +def income_statement_next(target_year, income_statement_hist, bill_overview_organized, growth_rate_flag): '''Project income statement for UI input. inputs are whatever bill and financial statements are available Args: income_statement_hist (dictionary): historical income statement, with all items filled, for available years @@ -56,11 +56,15 @@ def income_statement_next(income_statement_hist, bill_overview_organized, growth # non_utility_expense_percent = characters['non_utility_expense_percent'] # revenue_average = characters['revenue_average'] - growth_rate = cagr # !!!! need logic for growth_rate_flag + growth_rate = income_statement_characters['cagr'] # !!!! need logic for growth_rate_flag income_statement_next = fl.Income_Statement() - - income_statement_next.revenue = income_statement_characters['revenue_average'] + income_statement_next.year = target_year + # income_statement_next.revenue = income_statement_characters['revenue_average'] + income_statement_next.revenue = income_statement_hist[2016]['revenue'] * (1 + growth_rate) income_statement_next.assign_next(income_statement_characters, bill_overview_organized) + result_dict = fl.convert_income_statement_class(income_statement_next) + print(result_dict) + return result_dict @@ -94,4 +98,4 @@ def income_statement_next(income_statement_hist, bill_overview_organized, growth # income statements should be availabe for at least 1 year. If comes with >1 years, suppose to be continued. # income_statement_proj_input(db.income_statement_full, db.bill_overview_organized, 0.01) - +income_statement_next(2017, db.income_statement_full, db.bill_overview_organized, 0.01) diff --git a/bpfin/tests/test_financials/test_financial_lib.py b/bpfin/tests/test_financials/test_financial_lib.py index b6dcc52..7a8e829 100644 --- a/bpfin/tests/test_financials/test_financial_lib.py +++ b/bpfin/tests/test_financials/test_financial_lib.py @@ -1,7 +1,7 @@ import datetime from bpfin.financials import financial_lib as fl from bpfin.tests.testdata import sample_data as db -from bpfin.financials.income_statement_proj_input import income_statement_proj_input +from bpfin.financials.income_statement_proj_input import income_statement_next def test_organize_bill_overview(): @@ -32,13 +32,15 @@ def test_form_raw_income_statement(): assert output_dict == result_dict -def test_income_statement_proj_input(): +def test_income_statement_next(): + input_target_year = 2017 input_income_statement_full = db.income_statement_full input_bill_overview_organized = db.bill_overview_organized # input_analysis_date = db.analysis_date input_growth_rate_flag = 0.01 output_dict = db.income_input_next - result_dict = income_statement_proj_input( + result_dict = income_statement_next( + input_target_year, input_income_statement_full, input_bill_overview_organized, input_growth_rate_flag) -- GitLab From dc91fa81118ed5ca4321d42c85a73dc234606798 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Mon, 24 Apr 2017 11:13:43 -0400 Subject: [PATCH 19/27] Rename income_statement_full to IS_hist Modify test files --- .../financials/income_statement_proj_input.py | 24 +++++++++---------- .../test_financials/test_financial_lib.py | 15 +----------- .../test_income_statement_proj_input.py | 24 +++++++++++++++---- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py index 8389685..d459b65 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_proj_input.py @@ -4,32 +4,32 @@ import bpfin.utilbills.bill_lib as bl from bpfin.lib import other as lib -def income_statement_character(income_statement_full): +def income_statement_character(income_statement_hist): '''Determine annual growth rate, other_utility_percentage, non_utility_expense_percentage Args: - income_statement_full (dictionary): full income statement, with all items filled, for available years + income_statement_hist (dictionary): full income statement, with all items filled, for available years Return: dictionary: three characters for future projection Description: - income_statement_full = {2014:{'revenue': 100000, ... ,'noi':37000}, 2015:{}, 2016:{}} + income_statement_hist = {2014:{'revenue': 100000, ... ,'noi':37000}, 2015:{}, 2016:{}} output = {'cagr': 2.45, 'other_utility_percentage': 20.4%, 'non_utility_expense_percentage': 43.5%} ''' - start_year = sorted(income_statement_full)[0] - end_year = sorted(income_statement_full)[-1] + start_year = sorted(income_statement_hist)[0] + end_year = sorted(income_statement_hist)[-1] # if start_year == None: return None cagr = lib.cal_cagr( - income_statement_full[start_year]['revenue'], - income_statement_full[end_year]['revenue'], + income_statement_hist[start_year]['revenue'], + income_statement_hist[end_year]['revenue'], end_year - start_year) revenue_sum = 0 other_utility_sum = 0 non_utility_expense_sum = 0 revenue_average = 0 - for year in sorted(income_statement_full): - revenue_sum += income_statement_full[year]['revenue'] - other_utility_sum += income_statement_full[year]['other_utility'] - non_utility_expense_sum += income_statement_full[year]['non_utility_expense'] + for year in sorted(income_statement_hist): + revenue_sum += income_statement_hist[year]['revenue'] + other_utility_sum += income_statement_hist[year]['other_utility'] + non_utility_expense_sum += income_statement_hist[year]['non_utility_expense'] revenue_average = revenue_sum / (end_year - start_year + 1) result_dict = { 'cagr': cagr, @@ -98,4 +98,4 @@ def income_statement_next(target_year, income_statement_hist, bill_overview_orga # income statements should be availabe for at least 1 year. If comes with >1 years, suppose to be continued. # income_statement_proj_input(db.income_statement_full, db.bill_overview_organized, 0.01) -income_statement_next(2017, db.income_statement_full, db.bill_overview_organized, 0.01) +# income_statement_next(2017, db.income_statement_full, db.bill_overview_organized, 0.01) diff --git a/bpfin/tests/test_financials/test_financial_lib.py b/bpfin/tests/test_financials/test_financial_lib.py index 7a8e829..71c8ba2 100644 --- a/bpfin/tests/test_financials/test_financial_lib.py +++ b/bpfin/tests/test_financials/test_financial_lib.py @@ -1,7 +1,7 @@ import datetime from bpfin.financials import financial_lib as fl from bpfin.tests.testdata import sample_data as db -from bpfin.financials.income_statement_proj_input import income_statement_next + def test_organize_bill_overview(): @@ -32,16 +32,3 @@ def test_form_raw_income_statement(): assert output_dict == result_dict -def test_income_statement_next(): - input_target_year = 2017 - input_income_statement_full = db.income_statement_full - input_bill_overview_organized = db.bill_overview_organized - # input_analysis_date = db.analysis_date - input_growth_rate_flag = 0.01 - output_dict = db.income_input_next - result_dict = income_statement_next( - input_target_year, - input_income_statement_full, - input_bill_overview_organized, - input_growth_rate_flag) - assert output_dict == result_dict diff --git a/bpfin/tests/test_financials/test_income_statement_proj_input.py b/bpfin/tests/test_financials/test_income_statement_proj_input.py index 7320949..5e0c74e 100644 --- a/bpfin/tests/test_financials/test_income_statement_proj_input.py +++ b/bpfin/tests/test_financials/test_income_statement_proj_input.py @@ -2,14 +2,30 @@ from bpfin.financials import financial_lib as fl from bpfin.tests.testdata import sample_data as db from bpfin.financials.income_statement_proj_input import income_statement_character -# from bpfin.financials.income_statement_proj_input import income_statement_proj_input +from bpfin.financials.income_statement_proj_input import income_statement_next def test_income_statement_character(): - input_income_statement_full = db.income_statement_full + input_income_statement_hist = db.income_statement_full output_dict = { 'cagr': 0.05409255338945984, 'other_utility_percent': 0.21880340182104946, - 'non_utility_expense_percent': 0.03333333333333333} - result_dict = income_statement_character(input_income_statement_full) + 'non_utility_expense_percent': 0.03333333333333333, + 'revenue_average': 95000.0} + result_dict = income_statement_character(input_income_statement_hist) + assert output_dict == result_dict + + +def test_income_statement_next(): + input_target_year = 2017 + input_income_statement_hist = db.income_statement_full + input_bill_overview_organized = db.bill_overview_organized + # input_analysis_date = db.analysis_date + input_growth_rate_flag = 0.01 + output_dict = db.income_input_next + result_dict = income_statement_next( + input_target_year, + input_income_statement_hist, + input_bill_overview_organized, + input_growth_rate_flag) assert output_dict == result_dict -- GitLab From f0e83e643d84ae15e6d28e34c4bddfb12f8e3c69 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Mon, 24 Apr 2017 12:10:21 -0400 Subject: [PATCH 20/27] Update IS_character func with start and end years. Add script to judge growth_rate_flag logic --- .../financials/income_statement_proj_input.py | 26 ++++++++++++------- .../test_income_statement_proj_input.py | 4 ++- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py index d459b65..39fdb1a 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_proj_input.py @@ -32,6 +32,8 @@ def income_statement_character(income_statement_hist): non_utility_expense_sum += income_statement_hist[year]['non_utility_expense'] revenue_average = revenue_sum / (end_year - start_year + 1) result_dict = { + 'start_year': start_year, + 'end_year': end_year, 'cagr': cagr, 'other_utility_percent': other_utility_sum/revenue_sum, 'non_utility_expense_percent': non_utility_expense_sum/revenue_sum, @@ -50,18 +52,24 @@ def income_statement_next(target_year, income_statement_hist, bill_overview_orga Returns: dictionary: ''' - income_statement_characters = income_statement_character(income_statement_hist) - # cagr = characters['cagr'] - # other_utility_percent = characters['other_utility_percent'] - # non_utility_expense_percent = characters['non_utility_expense_percent'] - # revenue_average = characters['revenue_average'] + characters = income_statement_character(income_statement_hist) - growth_rate = income_statement_characters['cagr'] # !!!! need logic for growth_rate_flag income_statement_next = fl.Income_Statement() income_statement_next.year = target_year - # income_statement_next.revenue = income_statement_characters['revenue_average'] - income_statement_next.revenue = income_statement_hist[2016]['revenue'] * (1 + growth_rate) - income_statement_next.assign_next(income_statement_characters, bill_overview_organized) + + # if growth_rate_flag == -1: + # income_statement_next.revenue = characters['revenue_average'] + # else: + # if growth_rate_flag == NULL: + # growth_rate = characters['cagr'] + # income_statement_next.revenue = income_statement_hist[characters['end_year']]['revenue'] * (1 + growth_rate) + # else: + # growth_rate = growth_rate_flag # 0.00, 0.01, 0.02 ... + # income_statement_next.revenue = income_statement_hist[characters['end_year']]['revenue'] * (1 + growth_rate) + + growth_rate = characters['cagr'] # !!!! need logic for growth_rate_flag + income_statement_next.revenue = income_statement_hist[characters['end_year']]['revenue'] * (1 + growth_rate) # !!!! need logic for growth_rate_flag + income_statement_next.assign_next(characters, bill_overview_organized) result_dict = fl.convert_income_statement_class(income_statement_next) print(result_dict) return result_dict diff --git a/bpfin/tests/test_financials/test_income_statement_proj_input.py b/bpfin/tests/test_financials/test_income_statement_proj_input.py index 5e0c74e..feada69 100644 --- a/bpfin/tests/test_financials/test_income_statement_proj_input.py +++ b/bpfin/tests/test_financials/test_income_statement_proj_input.py @@ -11,7 +11,9 @@ def test_income_statement_character(): 'cagr': 0.05409255338945984, 'other_utility_percent': 0.21880340182104946, 'non_utility_expense_percent': 0.03333333333333333, - 'revenue_average': 95000.0} + 'revenue_average': 95000.0, + 'start_year': 2014, + 'end_year': 2016} result_dict = income_statement_character(input_income_statement_hist) assert output_dict == result_dict -- GitLab From d68d93708407b6c32051c2746aff8b47d5428306 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Mon, 24 Apr 2017 13:28:35 -0400 Subject: [PATCH 21/27] Improve growth_rate_flag logic. Update test file and sample data --- .../financials/income_statement_proj_input.py | 24 +++++++-------- .../test_income_statement_proj_input.py | 18 ++++++----- bpfin/tests/testdata/sample_data.py | 30 +++++++++++++++++-- 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py index 39fdb1a..95129a2 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_proj_input.py @@ -57,18 +57,18 @@ def income_statement_next(target_year, income_statement_hist, bill_overview_orga income_statement_next = fl.Income_Statement() income_statement_next.year = target_year - # if growth_rate_flag == -1: - # income_statement_next.revenue = characters['revenue_average'] - # else: - # if growth_rate_flag == NULL: - # growth_rate = characters['cagr'] - # income_statement_next.revenue = income_statement_hist[characters['end_year']]['revenue'] * (1 + growth_rate) - # else: - # growth_rate = growth_rate_flag # 0.00, 0.01, 0.02 ... - # income_statement_next.revenue = income_statement_hist[characters['end_year']]['revenue'] * (1 + growth_rate) + if growth_rate_flag == -1.0: + income_statement_next.revenue = characters['revenue_average'] + else: + if growth_rate_flag == -2.0: + growth_rate = characters['cagr'] + income_statement_next.revenue = income_statement_hist[characters['end_year']]['revenue'] * (1 + growth_rate) + else: + growth_rate = growth_rate_flag # 0.00, 0.01, 0.02 ... + income_statement_next.revenue = income_statement_hist[characters['end_year']]['revenue'] * (1 + growth_rate) - growth_rate = characters['cagr'] # !!!! need logic for growth_rate_flag - income_statement_next.revenue = income_statement_hist[characters['end_year']]['revenue'] * (1 + growth_rate) # !!!! need logic for growth_rate_flag + # growth_rate = characters['cagr'] # !!!! need logic for growth_rate_flag + # income_statement_next.revenue = income_statement_hist[characters['end_year']]['revenue'] * (1 + growth_rate) # !!!! need logic for growth_rate_flag income_statement_next.assign_next(characters, bill_overview_organized) result_dict = fl.convert_income_statement_class(income_statement_next) print(result_dict) @@ -106,4 +106,4 @@ def income_statement_next(target_year, income_statement_hist, bill_overview_orga # income statements should be availabe for at least 1 year. If comes with >1 years, suppose to be continued. # income_statement_proj_input(db.income_statement_full, db.bill_overview_organized, 0.01) -# income_statement_next(2017, db.income_statement_full, db.bill_overview_organized, 0.01) +income_statement_next(2017, db.income_statement_full, db.bill_overview_organized, -2.0) diff --git a/bpfin/tests/test_financials/test_income_statement_proj_input.py b/bpfin/tests/test_financials/test_income_statement_proj_input.py index feada69..a9830da 100644 --- a/bpfin/tests/test_financials/test_income_statement_proj_input.py +++ b/bpfin/tests/test_financials/test_income_statement_proj_input.py @@ -23,11 +23,13 @@ def test_income_statement_next(): input_income_statement_hist = db.income_statement_full input_bill_overview_organized = db.bill_overview_organized # input_analysis_date = db.analysis_date - input_growth_rate_flag = 0.01 - output_dict = db.income_input_next - result_dict = income_statement_next( - input_target_year, - input_income_statement_hist, - input_bill_overview_organized, - input_growth_rate_flag) - assert output_dict == result_dict + growth_flag_tuple = {1: 0.01, 2, 0.00, 3: -1.0, 4: -2.0} + for i in range(len(4)): + input_growth_rate_flag = growth_flag_tuple[i + 1] + output_dict = db.income_next[i + 1] + result_dict = income_statement_next( + input_target_year, + input_income_statement_hist, + input_bill_overview_organized, + input_growth_rate_flag) + assert output_dict == result_dict diff --git a/bpfin/tests/testdata/sample_data.py b/bpfin/tests/testdata/sample_data.py index da8e91b..bd9127b 100644 --- a/bpfin/tests/testdata/sample_data.py +++ b/bpfin/tests/testdata/sample_data.py @@ -192,13 +192,39 @@ income_statement_full = { 'total_opex': 63000.0, 'noi': 37000.0} } -income_input_next = { +# income_input_next = { +# 'year': 2017, 'revenue': 105409.25533894598, 'utility_expense': 60617.176566756985, 'energy_opex': 37553.27291517199, +# 'electricity_opex': 34523.27291517199, 'gas_opex': 1520, 'oil_opex': 1510, 'water_opex': 0, +# 'other_utility': 23063.903651585, 'non_utility_expense': 3513.6418446315324, 'net_non_energy_opex': 26577.54549621653, +# 'total_opex': 64130.81841138852, 'noi': 41278.43692755746} + +income_next = {} + +# growth_rate_flag == 0.01 +income_next[1] = { + 'year': 2017, 'revenue': 101000.0, 'utility_expense': 59652.416499097984, 'energy_opex': 37553.27291517199, + 'electricity_opex': 34523.27291517199, 'gas_opex': 1520, 'oil_opex': 1510, 'water_opex': 0, + 'other_utility': 22099.143583925994, 'non_utility_expense': 3366.6666666666665, 'net_non_energy_opex': 25465.81025059266, + 'total_opex': 63019.08316576465, 'noi': 37980.91683423535} +# growth_rate_flag == 0.00 +income_next[2] = { + 'year': 2017, 'revenue': 100000.0, 'utility_expense': 59433.61309727693, 'energy_opex': 37553.27291517199, + 'electricity_opex': 34523.27291517199, 'gas_opex': 1520, 'oil_opex': 1510, 'water_opex': 0, + 'other_utility': 21880.340182104945, 'non_utility_expense': 3333.3333333333335, 'net_non_energy_opex': 25213.673515438277, + 'total_opex': 62766.94643061027, 'noi': 37233.05356938973} +# growth_rate_flag == -1.0 +income_next[3] = { + 'year': 2017, 'revenue': 95000.0, 'utility_expense': 58339.59608817169, 'energy_opex': 37553.27291517199, + 'electricity_opex': 34523.27291517199, 'gas_opex': 1520, 'oil_opex': 1510, 'water_opex': 0, + 'other_utility': 20786.3231729997, 'non_utility_expense': 3166.6666666666665, 'net_non_energy_opex':23952.989839666367, + 'total_opex': 61506.26275483836, 'noi': 33493.73724516164} +# growth_rate_flag == -2.0 +income_next[4] = { 'year': 2017, 'revenue': 105409.25533894598, 'utility_expense': 60617.176566756985, 'energy_opex': 37553.27291517199, 'electricity_opex': 34523.27291517199, 'gas_opex': 1520, 'oil_opex': 1510, 'water_opex': 0, 'other_utility': 23063.903651585, 'non_utility_expense': 3513.6418446315324, 'net_non_energy_opex': 26577.54549621653, 'total_opex': 64130.81841138852, 'noi': 41278.43692755746} - # liability, mortgage and other debt data liability_dictionary = { 'debt1': (150, 'NYSERDA', 10, datetime.date(2012, 12, 31)), -- GitLab From 1dd1bf7f1e88d2d3b5f6366c9999083fc38d47ba Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Mon, 24 Apr 2017 13:33:27 -0400 Subject: [PATCH 22/27] Clean up test files --- .../tests/test_financials/test_income_statement_proj_input.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bpfin/tests/test_financials/test_income_statement_proj_input.py b/bpfin/tests/test_financials/test_income_statement_proj_input.py index a9830da..cdba6fb 100644 --- a/bpfin/tests/test_financials/test_income_statement_proj_input.py +++ b/bpfin/tests/test_financials/test_income_statement_proj_input.py @@ -23,8 +23,8 @@ def test_income_statement_next(): input_income_statement_hist = db.income_statement_full input_bill_overview_organized = db.bill_overview_organized # input_analysis_date = db.analysis_date - growth_flag_tuple = {1: 0.01, 2, 0.00, 3: -1.0, 4: -2.0} - for i in range(len(4)): + growth_flag_tuple = {1: 0.01, 2: 0.00, 3: -1.0, 4: -2.0} + for i in range(4): input_growth_rate_flag = growth_flag_tuple[i + 1] output_dict = db.income_next[i + 1] result_dict = income_statement_next( -- GitLab From 0f3f2b39290d95648b4acc1c67a23f7f8aa2331b Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Mon, 24 Apr 2017 13:36:22 -0400 Subject: [PATCH 23/27] Clean up code minorly --- bpfin/financials/financial_lib.py | 118 ++---------------- .../financials/income_statement_proj_input.py | 4 +- 2 files changed, 14 insertions(+), 108 deletions(-) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index c89e927..3f5ed3e 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -122,98 +122,6 @@ def form_raw_income_statement(raw_income_input, bill_overview_organized, analysi return income_statement_full -# raw_income_input = { -# 2014: { -# 'revenue': 90000, -# 'utility_expense': 55000, -# 'non_utility_expense': 3500 -# }, -# 2015: { -# 'revenue': 95000, -# 'utility_expense': 55000, -# 'non_utility_expense': 3000 -# }, -# 2016: { -# 'revenue': 100000, -# 'utility_expense': 60000, -# 'non_utility_expense': 3000 -# } -# } - -# electricity_bill = { -# 2012: 32220.590596217822, -# 2013: 32782.518348206999, -# 2014: 33293.100530249467, -# 2015: 33546.761580451312, -# 2016: 33844.501703633454, -# 2017: 34523.27291517199, -# 2018: 35384.966283060414, -# 2019: 36251.490761516034, -# 2020: 37100.197369238413, -# 2021: 37887.082013632862, -# 2022: 38603.765037606507, -# 2023: 39307.925216552088, -# 2024: 40028.077679374117, -# 2025: 40772.42926238777, -# 2026: 41575.666985412594, -# 2027: 42439.918590730398, -# 2028: 43325.235463581725, -# 2029: 44211.298795796341, -# 2030: 45097.667796776521, -# 2031: 45986.665329650692, -# 2032: 46886.305428683903, -# 2033: 47806.578908870637, -# 2034: 48751.551094031129, -# 2035: 49722.255450564422, -# 2036: 50718.832984188753 -# } -# oil_bill = {2015: 1010, 2016: 1210, 2017: 1510} -# gas_bill = {2015: 1020, 2016: 1220, 2017: 1520} -# water_bill = {2015: 0, 2016: 0, 2017: 0} - -# bill_overview = { -# 'electricity': [electricity_bill, True], -# 'oil': [oil_bill, False], -# 'gas': [gas_bill, False], -# 'water': [water_bill, False] -# } - -# bill_overview_organized = { -# 'electricity': { -# 2012: 32220.590596217822, 2013: 32782.518348207, 2014: 33293.10053024947, -# 2015: 33546.76158045131, 2016: 33844.501703633454, 2017: 34523.27291517199, -# 2018: 35384.966283060414, 2019: 36251.490761516034, 2020: 37100.19736923841, -# 2021: 37887.08201363286, 2022: 38603.76503760651, 2023: 39307.92521655209, -# 2024: 40028.07767937412, 2025: 40772.42926238777, 2026: 41575.666985412594, -# 2027: 42439.9185907304, 2028: 43325.235463581725, 2029: 44211.29879579634, -# 2030: 45097.66779677652, 2031: 45986.66532965069, 2032: 46886.3054286839, -# 2033: 47806.57890887064, 2034: 48751.55109403113, 2035: 49722.25545056442, -# 2036: 50718.83298418875}, -# 'gas': {2015: 1020, 2016: 1220, 2017: 1520, 2012: 1253.3333333333333, -# 2013: 1253.3333333333333, 2014: 1253.3333333333333, 2018: 1253.3333333333333, -# 2019: 1253.3333333333333, 2020: 1253.3333333333333, 2021: 1253.3333333333333, -# 2022: 1253.3333333333333, 2023: 1253.3333333333333, 2024: 1253.3333333333333, -# 2025: 1253.3333333333333, 2026: 1253.3333333333333, 2027: 1253.3333333333333, -# 2028: 1253.3333333333333, 2029: 1253.3333333333333, 2030: 1253.3333333333333, -# 2031: 1253.3333333333333, 2032: 1253.3333333333333, 2033: 1253.3333333333333, -# 2034: 1253.3333333333333, 2035: 1253.3333333333333, 2036: 1253.3333333333333}, -# 'oil': {2015: 1010, 2016: 1210, 2017: 1510, 2012: 1243.3333333333333, -# 2013: 1243.3333333333333, 2014: 1243.3333333333333, 2018: 1243.3333333333333, -# 2019: 1243.3333333333333, 2020: 1243.3333333333333, 2021: 1243.3333333333333, -# 2022: 1243.3333333333333, 2023: 1243.3333333333333, 2024: 1243.3333333333333, -# 2025: 1243.3333333333333, 2026: 1243.3333333333333, 2027: 1243.3333333333333, -# 2028: 1243.3333333333333, 2029: 1243.3333333333333, 2030: 1243.3333333333333, -# 2031: 1243.3333333333333, 2032: 1243.3333333333333, 2033: 1243.3333333333333, -# 2034: 1243.3333333333333, 2035: 1243.3333333333333, 2036: 1243.3333333333333}, -# 'water': {2015: 0, 2016: 0, 2017: 0, 2012: 0.0, 2013: 0.0, 2014: 0.0, 2018: 0.0, -# 2019: 0.0, 2020: 0.0, 2021: 0.0, 2022: 0.0, 2023: 0.0, 2024: 0.0, -# 2025: 0.0, 2026: 0.0, 2027: 0.0, 2028: 0.0, 2029: 0.0, 2030: 0.0, -# 2031: 0.0, 2032: 0.0, 2033: 0.0, 2034: 0.0, 2035: 0.0, 2036: 0.0} -# } - -# income_statement_single_year(income_input_2016, bill_overview) -# form_raw_income_statement(db.raw_income_input, db.bill_overview_organized, db.analysis_date) - class Income_Statement(): def __init__(self): self.year = None @@ -230,19 +138,6 @@ class Income_Statement(): self.total_opex = None self.noi = None - def assign_next_year(self, other_utility_percent, non_utility_expense_percent): - # print('\n other_utility_percent',other_utility_percent) - # print('\n non_utility_expense_percent',non_utility_expense_percent) - self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex - # print('\n',self.energy_opex) - # print('\n revenue', self.revenue) - self.other_utility = self.revenue * other_utility_percent - self.non_utility_expense = self.revenue * non_utility_expense_percent - self.utility_expense = self.energy_opex + self.other_utility - self.net_non_energy_opex = self.other_utility + self.non_utility_expense - self.total_opex = self.energy_opex + self.net_non_energy_opex - self.noi = self.revenue - self.total_opex - def assign_next(self, income_statement_characters, bill_overview_organized): self.electricity_opex = bill_overview_organized['electricity'][self.year] self.gas_opex = bill_overview_organized['gas'][self.year] @@ -256,6 +151,19 @@ class Income_Statement(): self.total_opex = self.energy_opex + self.net_non_energy_opex self.noi = self.revenue - self.total_opex + # def assign_next_year(self, other_utility_percent, non_utility_expense_percent): + # # print('\n other_utility_percent',other_utility_percent) + # # print('\n non_utility_expense_percent',non_utility_expense_percent) + # self.energy_opex = self.electricity_opex + self.gas_opex + self.oil_opex + self.water_opex + # # print('\n',self.energy_opex) + # # print('\n revenue', self.revenue) + # self.other_utility = self.revenue * other_utility_percent + # self.non_utility_expense = self.revenue * non_utility_expense_percent + # self.utility_expense = self.energy_opex + self.other_utility + # self.net_non_energy_opex = self.other_utility + self.non_utility_expense + # self.total_opex = self.energy_opex + self.net_non_energy_opex + # self.noi = self.revenue - self.total_opex + def convert_income_statement_class(income_statement_class): income_statement_dict = { diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_proj_input.py index 95129a2..6d7bdd2 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_proj_input.py @@ -67,8 +67,6 @@ def income_statement_next(target_year, income_statement_hist, bill_overview_orga growth_rate = growth_rate_flag # 0.00, 0.01, 0.02 ... income_statement_next.revenue = income_statement_hist[characters['end_year']]['revenue'] * (1 + growth_rate) - # growth_rate = characters['cagr'] # !!!! need logic for growth_rate_flag - # income_statement_next.revenue = income_statement_hist[characters['end_year']]['revenue'] * (1 + growth_rate) # !!!! need logic for growth_rate_flag income_statement_next.assign_next(characters, bill_overview_organized) result_dict = fl.convert_income_statement_class(income_statement_next) print(result_dict) @@ -106,4 +104,4 @@ def income_statement_next(target_year, income_statement_hist, bill_overview_orga # income statements should be availabe for at least 1 year. If comes with >1 years, suppose to be continued. # income_statement_proj_input(db.income_statement_full, db.bill_overview_organized, 0.01) -income_statement_next(2017, db.income_statement_full, db.bill_overview_organized, -2.0) +# income_statement_next(2017, db.income_statement_full, db.bill_overview_organized, -2.0) -- GitLab From c8b3b94b11a999404a038cad6b43631b78e6fe4f Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Mon, 24 Apr 2017 13:53:32 -0400 Subject: [PATCH 24/27] Create income_statement_hist Rename IS_proj_input with IS_next Clean sample data and test files --- bpfin/financials/financial_lib.py | 21 ------- .../financials/income_statement_form_hist.py | 63 +++++++++++++++++++ ...proj_input.py => income_statement_next.py} | 39 +----------- .../test_financials/test_financial_lib.py | 13 +--- .../test_income_statement_form_hist.py | 28 +++++++++ .../test_income_statement_proj_input.py | 17 +---- 6 files changed, 94 insertions(+), 87 deletions(-) create mode 100644 bpfin/financials/income_statement_form_hist.py rename bpfin/financials/{income_statement_proj_input.py => income_statement_next.py} (69%) create mode 100644 bpfin/tests/test_financials/test_income_statement_form_hist.py diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index 3f5ed3e..c1a6cbd 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -101,27 +101,6 @@ def organize_bill_overview(bill_overview, analysis_date): return bill_overview_organized -def form_raw_income_statement(raw_income_input, bill_overview_organized, analysis_date): - ''' form income statement table with raw inputs from UI, and organized bill_overview. NO projection - Args: - raw_income_input (dictionary): dictionary of dictionary. raw inputs for income statement for available years - bill_over_view_organized (dictionary): dict of dict, 4 utility types, with blank charge filled with average - analysis_date (dictionary): proforma's starting date and the years of proforma - Returns: - Dictionary: dict of dict, full income statement for available years - - Description: - raw_income_input = {2014: {'revenue': 90000, 'utility_expense': 55000, 'non_utility_expense': 3500}, 2015:{},} - bill_overview_organized = {'electricity':{2012: 100, 2013: 120, ...}, 'gas':{2012:100,2013:130...},...} - Output = {2014: {'year': 2014, 'revenue': ...}, 2015:{...}, 2016:{...}} - ''' - income_statement_full = {} - for year in sorted(raw_income_input): - income_statement_full[year] = income_statement_single_year( - year, raw_income_input[year], bill_overview_organized) - return income_statement_full - - class Income_Statement(): def __init__(self): self.year = None diff --git a/bpfin/financials/income_statement_form_hist.py b/bpfin/financials/income_statement_form_hist.py new file mode 100644 index 0000000..0bd328e --- /dev/null +++ b/bpfin/financials/income_statement_form_hist.py @@ -0,0 +1,63 @@ +import bpfin.financials.financial_lib as fl +import bpfin.tests.testdata.sample_data as db +import bpfin.utilbills.bill_lib as bl +from bpfin.lib import other as lib + + +def income_statement_character(income_statement_hist): + '''Determine annual growth rate, other_utility_percentage, non_utility_expense_percentage + Args: + income_statement_hist (dictionary): full income statement, with all items filled, for available years + Return: + dictionary: three characters for future projection + + Description: + income_statement_hist = {2014:{'revenue': 100000, ... ,'noi':37000}, 2015:{}, 2016:{}} + output = {'cagr': 2.45, 'other_utility_percentage': 20.4%, 'non_utility_expense_percentage': 43.5%} + ''' + start_year = sorted(income_statement_hist)[0] + end_year = sorted(income_statement_hist)[-1] + # if start_year == None: return None + cagr = lib.cal_cagr( + income_statement_hist[start_year]['revenue'], + income_statement_hist[end_year]['revenue'], + end_year - start_year) + revenue_sum = 0 + other_utility_sum = 0 + non_utility_expense_sum = 0 + revenue_average = 0 + for year in sorted(income_statement_hist): + revenue_sum += income_statement_hist[year]['revenue'] + other_utility_sum += income_statement_hist[year]['other_utility'] + non_utility_expense_sum += income_statement_hist[year]['non_utility_expense'] + revenue_average = revenue_sum / (end_year - start_year + 1) + result_dict = { + 'start_year': start_year, + 'end_year': end_year, + 'cagr': cagr, + 'other_utility_percent': other_utility_sum/revenue_sum, + 'non_utility_expense_percent': non_utility_expense_sum/revenue_sum, + 'revenue_average': revenue_average + } + return result_dict + + +def form_income_statement_hist(raw_income_input, bill_overview_organized, analysis_date): + ''' form income statement table with raw inputs from UI, and organized bill_overview. NO projection + Args: + raw_income_input (dictionary): dictionary of dictionary. raw inputs for income statement for available years + bill_over_view_organized (dictionary): dict of dict, 4 utility types, with blank charge filled with average + analysis_date (dictionary): proforma's starting date and the years of proforma + Returns: + Dictionary: dict of dict, full income statement for available years + + Description: + raw_income_input = {2014: {'revenue': 90000, 'utility_expense': 55000, 'non_utility_expense': 3500}, 2015:{},} + bill_overview_organized = {'electricity':{2012: 100, 2013: 120, ...}, 'gas':{2012:100,2013:130...},...} + Output = {2014: {'year': 2014, 'revenue': ...}, 2015:{...}, 2016:{...}} + ''' + income_statement_full = {} + for year in sorted(raw_income_input): + income_statement_full[year] = fl.income_statement_single_year( + year, raw_income_input[year], bill_overview_organized) + return income_statement_full diff --git a/bpfin/financials/income_statement_proj_input.py b/bpfin/financials/income_statement_next.py similarity index 69% rename from bpfin/financials/income_statement_proj_input.py rename to bpfin/financials/income_statement_next.py index 6d7bdd2..88eeb5b 100644 --- a/bpfin/financials/income_statement_proj_input.py +++ b/bpfin/financials/income_statement_next.py @@ -2,44 +2,7 @@ import bpfin.financials.financial_lib as fl import bpfin.tests.testdata.sample_data as db import bpfin.utilbills.bill_lib as bl from bpfin.lib import other as lib - - -def income_statement_character(income_statement_hist): - '''Determine annual growth rate, other_utility_percentage, non_utility_expense_percentage - Args: - income_statement_hist (dictionary): full income statement, with all items filled, for available years - Return: - dictionary: three characters for future projection - - Description: - income_statement_hist = {2014:{'revenue': 100000, ... ,'noi':37000}, 2015:{}, 2016:{}} - output = {'cagr': 2.45, 'other_utility_percentage': 20.4%, 'non_utility_expense_percentage': 43.5%} - ''' - start_year = sorted(income_statement_hist)[0] - end_year = sorted(income_statement_hist)[-1] - # if start_year == None: return None - cagr = lib.cal_cagr( - income_statement_hist[start_year]['revenue'], - income_statement_hist[end_year]['revenue'], - end_year - start_year) - revenue_sum = 0 - other_utility_sum = 0 - non_utility_expense_sum = 0 - revenue_average = 0 - for year in sorted(income_statement_hist): - revenue_sum += income_statement_hist[year]['revenue'] - other_utility_sum += income_statement_hist[year]['other_utility'] - non_utility_expense_sum += income_statement_hist[year]['non_utility_expense'] - revenue_average = revenue_sum / (end_year - start_year + 1) - result_dict = { - 'start_year': start_year, - 'end_year': end_year, - 'cagr': cagr, - 'other_utility_percent': other_utility_sum/revenue_sum, - 'non_utility_expense_percent': non_utility_expense_sum/revenue_sum, - 'revenue_average': revenue_average - } - return result_dict +from bpfin.financials.income_statement_form_hist import income_statement_character def income_statement_next(target_year, income_statement_hist, bill_overview_organized, growth_rate_flag): diff --git a/bpfin/tests/test_financials/test_financial_lib.py b/bpfin/tests/test_financials/test_financial_lib.py index 71c8ba2..b756a24 100644 --- a/bpfin/tests/test_financials/test_financial_lib.py +++ b/bpfin/tests/test_financials/test_financial_lib.py @@ -1,7 +1,7 @@ import datetime from bpfin.financials import financial_lib as fl from bpfin.tests.testdata import sample_data as db - +from bpfin.financials.income_statement_form_hist import form_income_statement_hist def test_organize_bill_overview(): @@ -20,15 +20,4 @@ def test_income_statement_single_year(): assert output_dict == result_dict -def test_form_raw_income_statement(): - input_raw_income_input = db.raw_income_input - input_bill_overview_organized = db.bill_overview_organized - input_analysis_date = db.analysis_date - output_dict = db.income_statement_full - result_dict = fl.form_raw_income_statement( - input_raw_income_input, - input_bill_overview_organized, - input_analysis_date) - assert output_dict == result_dict - diff --git a/bpfin/tests/test_financials/test_income_statement_form_hist.py b/bpfin/tests/test_financials/test_income_statement_form_hist.py new file mode 100644 index 0000000..9114f18 --- /dev/null +++ b/bpfin/tests/test_financials/test_income_statement_form_hist.py @@ -0,0 +1,28 @@ +from bpfin.tests.testdata import sample_data as db +from bpfin.financials.income_statement_form_hist import income_statement_character +from bpfin.financials.income_statement_form_hist import form_income_statement_hist + + +def test_income_statement_character(): + input_income_statement_hist = db.income_statement_full + output_dict = { + 'cagr': 0.05409255338945984, + 'other_utility_percent': 0.21880340182104946, + 'non_utility_expense_percent': 0.03333333333333333, + 'revenue_average': 95000.0, + 'start_year': 2014, + 'end_year': 2016} + result_dict = income_statement_character(input_income_statement_hist) + assert output_dict == result_dict + + +def test_form_income_statement_hist(): + input_raw_income_input = db.raw_income_input + input_bill_overview_organized = db.bill_overview_organized + input_analysis_date = db.analysis_date + output_dict = db.income_statement_full + result_dict = form_income_statement_hist( + input_raw_income_input, + input_bill_overview_organized, + input_analysis_date) + assert output_dict == result_dict diff --git a/bpfin/tests/test_financials/test_income_statement_proj_input.py b/bpfin/tests/test_financials/test_income_statement_proj_input.py index cdba6fb..3546891 100644 --- a/bpfin/tests/test_financials/test_income_statement_proj_input.py +++ b/bpfin/tests/test_financials/test_income_statement_proj_input.py @@ -1,21 +1,6 @@ -# import datetime from bpfin.financials import financial_lib as fl from bpfin.tests.testdata import sample_data as db -from bpfin.financials.income_statement_proj_input import income_statement_character -from bpfin.financials.income_statement_proj_input import income_statement_next - - -def test_income_statement_character(): - input_income_statement_hist = db.income_statement_full - output_dict = { - 'cagr': 0.05409255338945984, - 'other_utility_percent': 0.21880340182104946, - 'non_utility_expense_percent': 0.03333333333333333, - 'revenue_average': 95000.0, - 'start_year': 2014, - 'end_year': 2016} - result_dict = income_statement_character(input_income_statement_hist) - assert output_dict == result_dict +from bpfin.financials.income_statement_next import income_statement_next def test_income_statement_next(): -- GitLab From 8c703511e0a6c317ada5bfa55eae1f96ba6a0111 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Mon, 24 Apr 2017 14:01:12 -0400 Subject: [PATCH 25/27] Add function description, comments and clean up --- bpfin/financials/financial_lib.py | 4 ++-- bpfin/financials/income_statement_form_hist.py | 6 ++---- bpfin/financials/income_statement_next.py | 8 +++----- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/bpfin/financials/financial_lib.py b/bpfin/financials/financial_lib.py index c1a6cbd..a72c3c1 100644 --- a/bpfin/financials/financial_lib.py +++ b/bpfin/financials/financial_lib.py @@ -12,7 +12,7 @@ def income_statement_single_year(year, income_input, bill_overview): Args: year (int): the year of this income statement income_input (dictionary): 4 elements of inputs - bill_overview (dictionary): contains annual energy charge for 4 utility types + bill_overview (dictionary): bill_overview from UI, with blank cells, for 4 utility_types Returns: dictionary: income statement with standarized items @@ -66,7 +66,7 @@ def organize_bill_overview(bill_overview, analysis_date): bill_overview (dictionary): bill_overview from UI, with blank cells, for 4 utility_types analysis_date (dictionary): proforma's starting date and the years of proforma Returns: - dictionary: bill_overview_organized,same structure with bill_overview + dictionary: bill_overview_organized, annual bills for 4 utility types, with blank cells filled Description: analysis_date: {'proforma_start': datetime.date, 'proforma_duration': int} diff --git a/bpfin/financials/income_statement_form_hist.py b/bpfin/financials/income_statement_form_hist.py index 0bd328e..028a1a1 100644 --- a/bpfin/financials/income_statement_form_hist.py +++ b/bpfin/financials/income_statement_form_hist.py @@ -1,6 +1,4 @@ import bpfin.financials.financial_lib as fl -import bpfin.tests.testdata.sample_data as db -import bpfin.utilbills.bill_lib as bl from bpfin.lib import other as lib @@ -13,7 +11,7 @@ def income_statement_character(income_statement_hist): Description: income_statement_hist = {2014:{'revenue': 100000, ... ,'noi':37000}, 2015:{}, 2016:{}} - output = {'cagr': 2.45, 'other_utility_percentage': 20.4%, 'non_utility_expense_percentage': 43.5%} + output = {'cagr': 2.45, 'other_utility_percentage': 20.4%, 'non_utility_expense_percentage': 43.5%, ..} ''' start_year = sorted(income_statement_hist)[0] end_year = sorted(income_statement_hist)[-1] @@ -46,7 +44,7 @@ def form_income_statement_hist(raw_income_input, bill_overview_organized, analys ''' form income statement table with raw inputs from UI, and organized bill_overview. NO projection Args: raw_income_input (dictionary): dictionary of dictionary. raw inputs for income statement for available years - bill_over_view_organized (dictionary): dict of dict, 4 utility types, with blank charge filled with average + bill_overview_organized (dictionary): dict of dict, 4 utility types, with blank charge filled with average analysis_date (dictionary): proforma's starting date and the years of proforma Returns: Dictionary: dict of dict, full income statement for available years diff --git a/bpfin/financials/income_statement_next.py b/bpfin/financials/income_statement_next.py index 88eeb5b..4279fc9 100644 --- a/bpfin/financials/income_statement_next.py +++ b/bpfin/financials/income_statement_next.py @@ -9,11 +9,11 @@ def income_statement_next(target_year, income_statement_hist, bill_overview_orga '''Project income statement for UI input. inputs are whatever bill and financial statements are available Args: income_statement_hist (dictionary): historical income statement, with all items filled, for available years - bill_overview_organized (dictionary): bill_overview from UI, with blank cells, for 4 utility_types + bill_overview_organized (dictionary): annual bills for 4 utility types, with blank cells filled analysis_date (dictionary): proforma's starting date and the years of proforma - growth_rate_flag (float) + growth_rate_flag (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average Returns: - dictionary: + dictionary: 1 year full income statement, with itmes calculated. ''' characters = income_statement_character(income_statement_hist) @@ -35,8 +35,6 @@ def income_statement_next(target_year, income_statement_hist, bill_overview_orga print(result_dict) return result_dict - - # def income_statement_proj_input(income_statement_full, bill_overview_organized, growth_rate_flag): # '''Project income statement for UI input. inputs are whatever bill and financial statements are available # Args: -- GitLab From c2cf13a8fb096b5c45bbddd600f21b9cfc90603f Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Mon, 24 Apr 2017 14:40:40 -0400 Subject: [PATCH 26/27] Fix income_statement_next, delete its target_year from inputs --- bpfin/financials/income_statement_next.py | 36 +++++++++---------- .../test_income_statement_proj_input.py | 3 -- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/bpfin/financials/income_statement_next.py b/bpfin/financials/income_statement_next.py index 4279fc9..60b42bc 100644 --- a/bpfin/financials/income_statement_next.py +++ b/bpfin/financials/income_statement_next.py @@ -5,7 +5,7 @@ from bpfin.lib import other as lib from bpfin.financials.income_statement_form_hist import income_statement_character -def income_statement_next(target_year, income_statement_hist, bill_overview_organized, growth_rate_flag): +def income_statement_next(income_statement_hist, bill_overview_organized, growth_rate_flag): '''Project income statement for UI input. inputs are whatever bill and financial statements are available Args: income_statement_hist (dictionary): historical income statement, with all items filled, for available years @@ -17,21 +17,21 @@ def income_statement_next(target_year, income_statement_hist, bill_overview_orga ''' characters = income_statement_character(income_statement_hist) - income_statement_next = fl.Income_Statement() - income_statement_next.year = target_year + income_next = fl.Income_Statement() + income_next.year = characters['end_year'] + 1 if growth_rate_flag == -1.0: - income_statement_next.revenue = characters['revenue_average'] + income_next.revenue = characters['revenue_average'] else: if growth_rate_flag == -2.0: growth_rate = characters['cagr'] - income_statement_next.revenue = income_statement_hist[characters['end_year']]['revenue'] * (1 + growth_rate) + income_next.revenue = income_statement_hist[characters['end_year']]['revenue'] * (1 + growth_rate) else: growth_rate = growth_rate_flag # 0.00, 0.01, 0.02 ... - income_statement_next.revenue = income_statement_hist[characters['end_year']]['revenue'] * (1 + growth_rate) + income_next.revenue = income_statement_hist[characters['end_year']]['revenue'] * (1 + growth_rate) - income_statement_next.assign_next(characters, bill_overview_organized) - result_dict = fl.convert_income_statement_class(income_statement_next) + income_next.assign_next(characters, bill_overview_organized) + result_dict = fl.convert_income_statement_class(income_next) print(result_dict) return result_dict @@ -52,17 +52,17 @@ def income_statement_next(target_year, income_statement_hist, bill_overview_orga # non_utility_expense_percent = characters['non_utility_expense_percent'] # growth_rate = cagr # !!!! need logic for growth_rate_flag # end_year = sorted(income_statement_full)[-1] -# income_statement_next = fl.Income_Statement() -# income_statement_next.year = end_year + 1 -# income_statement_next.revenue = income_statement_full[end_year]['revenue'] * (1 + growth_rate) -# income_statement_next.electricity_opex = bill_overview_organized['electricity'][end_year + 1] -# income_statement_next.gas_opex = bill_overview_organized['gas'][end_year + 1] -# income_statement_next.oil_opex = bill_overview_organized['oil'][end_year + 1] -# income_statement_next.water_opex = bill_overview_organized['water'][end_year + 1] -# income_statement_next.assign_next_year(other_utility_percent, non_utility_expense_percent) -# result_dict = fl.convert_income_statement_class(income_statement_next) +# income_next = fl.Income_Statement() +# income_next.year = end_year + 1 +# income_next.revenue = income_statement_full[end_year]['revenue'] * (1 + growth_rate) +# income_next.electricity_opex = bill_overview_organized['electricity'][end_year + 1] +# income_next.gas_opex = bill_overview_organized['gas'][end_year + 1] +# income_next.oil_opex = bill_overview_organized['oil'][end_year + 1] +# income_next.water_opex = bill_overview_organized['water'][end_year + 1] +# income_next.assign_next_year(other_utility_percent, non_utility_expense_percent) +# result_dict = fl.convert_income_statement_class(income_next) # return result_dict # income statements should be availabe for at least 1 year. If comes with >1 years, suppose to be continued. # income_statement_proj_input(db.income_statement_full, db.bill_overview_organized, 0.01) -# income_statement_next(2017, db.income_statement_full, db.bill_overview_organized, -2.0) +# income_next(2017, db.income_statement_full, db.bill_overview_organized, -2.0) diff --git a/bpfin/tests/test_financials/test_income_statement_proj_input.py b/bpfin/tests/test_financials/test_income_statement_proj_input.py index 3546891..d62d326 100644 --- a/bpfin/tests/test_financials/test_income_statement_proj_input.py +++ b/bpfin/tests/test_financials/test_income_statement_proj_input.py @@ -4,16 +4,13 @@ from bpfin.financials.income_statement_next import income_statement_next def test_income_statement_next(): - input_target_year = 2017 input_income_statement_hist = db.income_statement_full input_bill_overview_organized = db.bill_overview_organized - # input_analysis_date = db.analysis_date growth_flag_tuple = {1: 0.01, 2: 0.00, 3: -1.0, 4: -2.0} for i in range(4): input_growth_rate_flag = growth_flag_tuple[i + 1] output_dict = db.income_next[i + 1] result_dict = income_statement_next( - input_target_year, input_income_statement_hist, input_bill_overview_organized, input_growth_rate_flag) -- GitLab From 564fc0beeb3faf8883cae1d82f1a49e9a37edd60 Mon Sep 17 00:00:00 2001 From: chenzheng06 Date: Mon, 24 Apr 2017 15:36:02 -0400 Subject: [PATCH 27/27] Modify sorted(income_statement_hist) --- bpfin/financials/income_statement_form_hist.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bpfin/financials/income_statement_form_hist.py b/bpfin/financials/income_statement_form_hist.py index 028a1a1..019ecc5 100644 --- a/bpfin/financials/income_statement_form_hist.py +++ b/bpfin/financials/income_statement_form_hist.py @@ -13,8 +13,9 @@ def income_statement_character(income_statement_hist): income_statement_hist = {2014:{'revenue': 100000, ... ,'noi':37000}, 2015:{}, 2016:{}} output = {'cagr': 2.45, 'other_utility_percentage': 20.4%, 'non_utility_expense_percentage': 43.5%, ..} ''' - start_year = sorted(income_statement_hist)[0] - end_year = sorted(income_statement_hist)[-1] + sorted_income_hist_year = sorted(income_statement_hist) + start_year = sorted_income_hist_year[0] + end_year = sorted_income_hist_year[-1] # if start_year == None: return None cagr = lib.cal_cagr( income_statement_hist[start_year]['revenue'], @@ -24,18 +25,17 @@ def income_statement_character(income_statement_hist): other_utility_sum = 0 non_utility_expense_sum = 0 revenue_average = 0 - for year in sorted(income_statement_hist): + for year in sorted_income_hist_year: revenue_sum += income_statement_hist[year]['revenue'] other_utility_sum += income_statement_hist[year]['other_utility'] non_utility_expense_sum += income_statement_hist[year]['non_utility_expense'] - revenue_average = revenue_sum / (end_year - start_year + 1) result_dict = { 'start_year': start_year, 'end_year': end_year, 'cagr': cagr, 'other_utility_percent': other_utility_sum/revenue_sum, 'non_utility_expense_percent': non_utility_expense_sum/revenue_sum, - 'revenue_average': revenue_average + 'revenue_average': revenue_sum / (end_year - start_year + 1) } return result_dict -- GitLab