From 07aad584490504db207be471af4e8b482662e1b9 Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Tue, 25 Apr 2017 23:32:28 -0400 Subject: [PATCH 1/8] Create balance sheet files. --- bpfin/financials/balance_sheet_form_hist.py | 27 ++++++++++++++++++++ bpfin/financials/balance_sheet_next.py | 13 ++++++++++ bpfin/financials/balance_sheet_projection.py | 14 ++++++++++ bpfin/financials/cash_balance.py | 6 +++++ 4 files changed, 60 insertions(+) create mode 100644 bpfin/financials/balance_sheet_form_hist.py create mode 100644 bpfin/financials/balance_sheet_next.py create mode 100644 bpfin/financials/balance_sheet_projection.py diff --git a/bpfin/financials/balance_sheet_form_hist.py b/bpfin/financials/balance_sheet_form_hist.py new file mode 100644 index 0000000..4aa8589 --- /dev/null +++ b/bpfin/financials/balance_sheet_form_hist.py @@ -0,0 +1,27 @@ +def balance_sheet_character(balance_sheet_hist): + """Determine annual growth rate and other percentages + Args: + balance_sheet_hist (dictionary): full balance sheet, with all items for all available years + Return: + dictionary: three characters for future projection + Description: + balance_sheet_hist = {2014:{'asset': 100000, ... ,'liability':37000}, 2015:{}, 2016:{}} + output = {'cagr': 2.45, ...? + """ + + +def form_balance_sheet_hist(raw_balance_sheet_input, + balance_sheet_overview_organized, analysis_date): + """ Form balance sheet table with raw inputs from UI, and organized bill_overview. NO projection + Args: + raw_balance_sheet_input (dictionary): dictionary of dictionaries. raw inputs for balance sheet for available years + balance_sheet_overview_organized (dictionary): dictionary of dictionaries. + analysis_date (dictionary): proforma's starting date and the years of proforma + Returns: + Dictionary: dict of dict, full balance sheet for available years + + Description: + raw_balance_sheet_input = {2014: {'asset': 90000, 'liability': 55000,...}, 2015:{},} + bill_overview_organized = {...} + output = {...} + """ diff --git a/bpfin/financials/balance_sheet_next.py b/bpfin/financials/balance_sheet_next.py new file mode 100644 index 0000000..33179e0 --- /dev/null +++ b/bpfin/financials/balance_sheet_next.py @@ -0,0 +1,13 @@ + + +def balance_sheet_next(cash_balance, liability, net_op_income, growth_rate_flag): + """Project income statement for UI input. inputs are whatever bill and financial statements are available + Args: + cash_balance (dictionary): {year:value}, cash per year + liability (dictionary): {(year,month):value} value can be mortgage, loan debt, etc + net_op_income (dictionary): {year:value}, NOI + growth_rate_flat (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average + analysis_date (dictionary): proforma's starting date and the years of proforma + Returns: + dictionary: 1 year full balance sheet + """ diff --git a/bpfin/financials/balance_sheet_projection.py b/bpfin/financials/balance_sheet_projection.py new file mode 100644 index 0000000..258f715 --- /dev/null +++ b/bpfin/financials/balance_sheet_projection.py @@ -0,0 +1,14 @@ + + +def balance_sheet_projection(cash_balance, liability, net_op_income, + growth_rate_flag, analysis_date): + """Return balance sheet projection. + Args: + cash_balance (dictionary): {year:value}, cash per year + liability (dictionary): {(year,month):value} value can be mortgage, loan debt, etc + net_op_income (dictionary): {year:value}, NOI + growth_rate_flat (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average + analysis_date (dictionary): proforma's starting date and the years of proforma + Returns: + dictionary: {year: balance sheet // cash proforma} + """ diff --git a/bpfin/financials/cash_balance.py b/bpfin/financials/cash_balance.py index f8759ea..a73675d 100644 --- a/bpfin/financials/cash_balance.py +++ b/bpfin/financials/cash_balance.py @@ -1,4 +1,10 @@ def cash_balance(cash_dictionary): + """Returns current cash balance + Args: + cash_dictionary (dictionary): {datetime:(cash value,year)} + Returns: + dictionary: {datetime, cash value} + """ cash_balance_dictionary = {} -- GitLab From 3402e45462b940319902f6d25685327b5c4bcd12 Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Wed, 26 Apr 2017 16:59:47 -0400 Subject: [PATCH 2/8] Balance sheet projection --- bpfin/financials/balance_sheet_projection.py | 16 ++++++++++++---- bpfin/tests/testdata/sample_data.py | 10 ++++++++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/bpfin/financials/balance_sheet_projection.py b/bpfin/financials/balance_sheet_projection.py index 258f715..1ade1b4 100644 --- a/bpfin/financials/balance_sheet_projection.py +++ b/bpfin/financials/balance_sheet_projection.py @@ -1,14 +1,22 @@ +import datetime -def balance_sheet_projection(cash_balance, liability, net_op_income, - growth_rate_flag, analysis_date): +def balance_sheet_projection(cash_balance, liability, + income_statement_projection, growth_rate_flag, + analysis_date): """Return balance sheet projection. Args: cash_balance (dictionary): {year:value}, cash per year - liability (dictionary): {(year,month):value} value can be mortgage, loan debt, etc - net_op_income (dictionary): {year:value}, NOI + liability (dictionary): {(year):value} value can be mortgage, loan debt, etc + income_statement_projection (dictionary): {year:income statement values - take NOI} growth_rate_flat (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average analysis_date (dictionary): proforma's starting date and the years of proforma Returns: dictionary: {year: balance sheet // cash proforma} """ + + analysis_years = [] + for date, length in analysis_date.items(): + analysis_years.append(date.year) + for i in range(1, length): + analysis_years.append(date.year + i) diff --git a/bpfin/tests/testdata/sample_data.py b/bpfin/tests/testdata/sample_data.py index b7a8053..058575e 100644 --- a/bpfin/tests/testdata/sample_data.py +++ b/bpfin/tests/testdata/sample_data.py @@ -488,12 +488,18 @@ income_statement_projection_cagr = { 'year': 2036}} -# liability, mortgage and other debt data +# {debt ID: debt_value, lender, remaining months, start_date} liability_dictionary = { 'debt1': (150, 'NYSERDA', 10, datetime.date(2012, 12, 31)), 'debt2': (100, 'NYCEEC', 20, datetime.date(2012, 8, 31)) } - +# {year: value, is_balancesheet (boolean)} +cash_balance = { + datetime(2014, 11, 1): (500, False), + datetime(2015, 12, 31): (600, True), + datetime(2016, 11, 11): (500, False), + datetime(2016, 10, 10): (400, False) +} # pro-forma date and bill projection - # proforma_date_from, proforma_date_to -- GitLab From 9e63acf0f3e14e8b893dff5c29917e55330aa597 Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Fri, 28 Apr 2017 16:18:36 -0400 Subject: [PATCH 3/8] Balance sheet projection, still working --- bpfin/financials/balance_sheet_form_hist.py | 27 -------------------- bpfin/financials/balance_sheet_next.py | 13 ---------- bpfin/financials/balance_sheet_projection.py | 18 ++++++++++--- bpfin/tests/testdata/sample_data.py | 8 +++--- 4 files changed, 19 insertions(+), 47 deletions(-) delete mode 100644 bpfin/financials/balance_sheet_form_hist.py delete mode 100644 bpfin/financials/balance_sheet_next.py diff --git a/bpfin/financials/balance_sheet_form_hist.py b/bpfin/financials/balance_sheet_form_hist.py deleted file mode 100644 index 4aa8589..0000000 --- a/bpfin/financials/balance_sheet_form_hist.py +++ /dev/null @@ -1,27 +0,0 @@ -def balance_sheet_character(balance_sheet_hist): - """Determine annual growth rate and other percentages - Args: - balance_sheet_hist (dictionary): full balance sheet, with all items for all available years - Return: - dictionary: three characters for future projection - Description: - balance_sheet_hist = {2014:{'asset': 100000, ... ,'liability':37000}, 2015:{}, 2016:{}} - output = {'cagr': 2.45, ...? - """ - - -def form_balance_sheet_hist(raw_balance_sheet_input, - balance_sheet_overview_organized, analysis_date): - """ Form balance sheet table with raw inputs from UI, and organized bill_overview. NO projection - Args: - raw_balance_sheet_input (dictionary): dictionary of dictionaries. raw inputs for balance sheet for available years - balance_sheet_overview_organized (dictionary): dictionary of dictionaries. - analysis_date (dictionary): proforma's starting date and the years of proforma - Returns: - Dictionary: dict of dict, full balance sheet for available years - - Description: - raw_balance_sheet_input = {2014: {'asset': 90000, 'liability': 55000,...}, 2015:{},} - bill_overview_organized = {...} - output = {...} - """ diff --git a/bpfin/financials/balance_sheet_next.py b/bpfin/financials/balance_sheet_next.py deleted file mode 100644 index 33179e0..0000000 --- a/bpfin/financials/balance_sheet_next.py +++ /dev/null @@ -1,13 +0,0 @@ - - -def balance_sheet_next(cash_balance, liability, net_op_income, growth_rate_flag): - """Project income statement for UI input. inputs are whatever bill and financial statements are available - Args: - cash_balance (dictionary): {year:value}, cash per year - liability (dictionary): {(year,month):value} value can be mortgage, loan debt, etc - net_op_income (dictionary): {year:value}, NOI - growth_rate_flat (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average - analysis_date (dictionary): proforma's starting date and the years of proforma - Returns: - dictionary: 1 year full balance sheet - """ diff --git a/bpfin/financials/balance_sheet_projection.py b/bpfin/financials/balance_sheet_projection.py index 1ade1b4..515b8c0 100644 --- a/bpfin/financials/balance_sheet_projection.py +++ b/bpfin/financials/balance_sheet_projection.py @@ -15,8 +15,20 @@ def balance_sheet_projection(cash_balance, liability, dictionary: {year: balance sheet // cash proforma} """ - analysis_years = [] + analysis_years = {} for date, length in analysis_date.items(): - analysis_years.append(date.year) + analysis_years[date.year] = [] for i in range(1, length): - analysis_years.append(date.year + i) + analysis_years[date.year + i] = [] + + for in_year, item in income_statement_projection.items(): + for an_year in analysis_years: + if in_year == an_year: + analysis_years[an_year].append(item['noi']) + + for li_year, liab in liability.items(): + for an_year in analysis_years: + if li_year == an_year: + analysis_years[an_year].append(liab) + + return analysis_years diff --git a/bpfin/tests/testdata/sample_data.py b/bpfin/tests/testdata/sample_data.py index 058575e..6457cc1 100644 --- a/bpfin/tests/testdata/sample_data.py +++ b/bpfin/tests/testdata/sample_data.py @@ -495,10 +495,10 @@ liability_dictionary = { } # {year: value, is_balancesheet (boolean)} cash_balance = { - datetime(2014, 11, 1): (500, False), - datetime(2015, 12, 31): (600, True), - datetime(2016, 11, 11): (500, False), - datetime(2016, 10, 10): (400, False) + datetime.date(2014, 11, 1): (500, False), + datetime.date(2015, 12, 31): (600, True), + datetime.date(2016, 11, 11): (500, False), + datetime.date(2016, 10, 10): (400, False) } # pro-forma date and bill projection - -- GitLab From 212ac65424ecdbc86fcb4f7e8dc74bf71c8db040 Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Fri, 28 Apr 2017 16:23:59 -0400 Subject: [PATCH 4/8] Change in cash every year is returned. --- bpfin/financials/balance_sheet_projection.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/bpfin/financials/balance_sheet_projection.py b/bpfin/financials/balance_sheet_projection.py index 515b8c0..a72bbb1 100644 --- a/bpfin/financials/balance_sheet_projection.py +++ b/bpfin/financials/balance_sheet_projection.py @@ -16,6 +16,7 @@ def balance_sheet_projection(cash_balance, liability, """ analysis_years = {} + for date, length in analysis_date.items(): analysis_years[date.year] = [] for i in range(1, length): @@ -29,6 +30,11 @@ def balance_sheet_projection(cash_balance, liability, for li_year, liab in liability.items(): for an_year in analysis_years: if li_year == an_year: - analysis_years[an_year].append(liab) + analysis_years[an_year].append(-liab) + + yearly_change_in_cash = {} + + for year, cash_change in analysis_years.items(): + yearly_change_in_cash[year] = sum(cash_change) - return analysis_years + return yearly_change_in_cash -- GitLab From 3064381d7400808099082e417bd5be31e2ba47cb Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Mon, 1 May 2017 14:02:06 -0400 Subject: [PATCH 5/8] Balance sheet projection --- bpfin/financials/balance_sheet_projection.py | 49 +++++++++++--------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/bpfin/financials/balance_sheet_projection.py b/bpfin/financials/balance_sheet_projection.py index a72bbb1..f0674ab 100644 --- a/bpfin/financials/balance_sheet_projection.py +++ b/bpfin/financials/balance_sheet_projection.py @@ -17,24 +17,31 @@ def balance_sheet_projection(cash_balance, liability, analysis_years = {} - for date, length in analysis_date.items(): - analysis_years[date.year] = [] - for i in range(1, length): - analysis_years[date.year + i] = [] - - for in_year, item in income_statement_projection.items(): - for an_year in analysis_years: - if in_year == an_year: - analysis_years[an_year].append(item['noi']) - - for li_year, liab in liability.items(): - for an_year in analysis_years: - if li_year == an_year: - analysis_years[an_year].append(-liab) - - yearly_change_in_cash = {} - - for year, cash_change in analysis_years.items(): - yearly_change_in_cash[year] = sum(cash_change) - - return yearly_change_in_cash + for date in analysis_date: + start_year = date.year + duration = analysis_date[date] + for i in range(duration): + analysis_years[start_year + i] = [] + + smallest_year = min(cash_balance) + largest_year = max(cash_balance) + + for an_year in analysis_years: + if an_year in cash_balance: + analysis_years[an_year] = cash_balance[an_year] + elif an_year < smallest_year: + analysis_years[an_year] = None + elif an_year > largest_year: + previous_year = an_year - 1 + cash_b = analysis_years[previous_year] + if an_year in liability: + liab = liability[an_year] + else: + liab = 0 + if an_year in income_statement_projection: + noi = income_statement_projection[an_year]['noi'] + else: + noi = 0 + analysis_years[an_year] = cash_b - liab + noi + + return analysis_years -- GitLab From 40dd3455505f1f56ebd98f8ab7fdfe1c93533be1 Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Mon, 1 May 2017 14:11:50 -0400 Subject: [PATCH 6/8] Finish balance sheet projection with test --- bpfin/financials/balance_sheet_projection.py | 3 +- .../test_balance_sheet_projection.py | 41 +++++++++++++++++++ bpfin/tests/testdata/sample_data.py | 16 ++++---- 3 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 bpfin/tests/test_financials/test_balance_sheet_projection.py diff --git a/bpfin/financials/balance_sheet_projection.py b/bpfin/financials/balance_sheet_projection.py index f0674ab..dc25fea 100644 --- a/bpfin/financials/balance_sheet_projection.py +++ b/bpfin/financials/balance_sheet_projection.py @@ -2,14 +2,13 @@ import datetime def balance_sheet_projection(cash_balance, liability, - income_statement_projection, growth_rate_flag, + income_statement_projection, analysis_date): """Return balance sheet projection. Args: cash_balance (dictionary): {year:value}, cash per year liability (dictionary): {(year):value} value can be mortgage, loan debt, etc income_statement_projection (dictionary): {year:income statement values - take NOI} - growth_rate_flat (float): indicating assumed growth rate, -2.0 == cagr, -1.0 == historical average analysis_date (dictionary): proforma's starting date and the years of proforma Returns: dictionary: {year: balance sheet // cash proforma} diff --git a/bpfin/tests/test_financials/test_balance_sheet_projection.py b/bpfin/tests/test_financials/test_balance_sheet_projection.py new file mode 100644 index 0000000..05c4afe --- /dev/null +++ b/bpfin/tests/test_financials/test_balance_sheet_projection.py @@ -0,0 +1,41 @@ +from bpfin.financials.balance_sheet_projection import balance_sheet_projection +from bpfin.tests.testdata import sample_data as db +import datetime + + +def test_balance_sheet_projection(): + input_cash_balance = db.cash_balance + input_liability = db.liability_dictionary + input_noi = db.income_statement_projection_cagr + input_date_years = {datetime.date(2012, 1, 15): 25} + output = { + 2012: None, + 2013: None, + 2014: 5000.0, + 2015: 6000, + 2016: 4500.0, + 2017: 35778.43692755746, + 2018: 75992.72229401008, + 2019: 124835.35357997121, + 2020: 177567.28767315467, + 2021: 234506.6375641261, + 2022: 295993.759336618, + 2023: 362325.94364370033, + 2024: 433787.36982739856, + 2025: 510670.2474431231, + 2026: 593249.2143796427, + 2027: 681814.8219497779, + 2028: 776716.587140195, + 2029: 878344.3914861011, + 2030: 987109.6873789529, + 2031: 1103443.8773919346, + 2032: 1227793.8279146897, + 2033: 1360621.1623494846, + 2034: 1502409.5252755708, + 2035: 1653669.0253920422, + 2036: 1814938.615393169 + } + result = balance_sheet_projection(input_cash_balance, input_liability, + input_noi, input_date_years) + + assert output == result diff --git a/bpfin/tests/testdata/sample_data.py b/bpfin/tests/testdata/sample_data.py index 6457cc1..5b6c106 100644 --- a/bpfin/tests/testdata/sample_data.py +++ b/bpfin/tests/testdata/sample_data.py @@ -487,18 +487,18 @@ income_statement_projection_cagr = { 'water_opex': 0.0, 'year': 2036}} - -# {debt ID: debt_value, lender, remaining months, start_date} liability_dictionary = { - 'debt1': (150, 'NYSERDA', 10, datetime.date(2012, 12, 31)), - 'debt2': (100, 'NYCEEC', 20, datetime.date(2012, 8, 31)) + 2012: 650, + 2013: 2550, + 2014: 100, + 2015: 6000, + 2016: 15000, + 2017: 10000, + 2018: 5000 } # {year: value, is_balancesheet (boolean)} cash_balance = { - datetime.date(2014, 11, 1): (500, False), - datetime.date(2015, 12, 31): (600, True), - datetime.date(2016, 11, 11): (500, False), - datetime.date(2016, 10, 10): (400, False) + 2014: 5000.0, 2015: 6000, 2016: 4500.0 } # pro-forma date and bill projection - -- GitLab From ac4ffe758c9618d8ddefbb30a3765d7a3cb9c06c Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Mon, 1 May 2017 14:12:58 -0400 Subject: [PATCH 7/8] Change name of liability variable --- bpfin/financials/balance_sheet_projection.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/bpfin/financials/balance_sheet_projection.py b/bpfin/financials/balance_sheet_projection.py index dc25fea..d5fc23f 100644 --- a/bpfin/financials/balance_sheet_projection.py +++ b/bpfin/financials/balance_sheet_projection.py @@ -2,8 +2,7 @@ import datetime def balance_sheet_projection(cash_balance, liability, - income_statement_projection, - analysis_date): + income_statement_projection, analysis_date): """Return balance sheet projection. Args: cash_balance (dictionary): {year:value}, cash per year @@ -34,13 +33,13 @@ def balance_sheet_projection(cash_balance, liability, previous_year = an_year - 1 cash_b = analysis_years[previous_year] if an_year in liability: - liab = liability[an_year] + liability_value = liability[an_year] else: - liab = 0 + liability_value = 0 if an_year in income_statement_projection: noi = income_statement_projection[an_year]['noi'] else: noi = 0 - analysis_years[an_year] = cash_b - liab + noi + analysis_years[an_year] = cash_b - liability_value + noi return analysis_years -- GitLab From 321f21425b213b29dbe9fded7a0f512ab6c60358 Mon Sep 17 00:00:00 2001 From: Sarey Hamarneh Date: Mon, 1 May 2017 15:34:21 -0400 Subject: [PATCH 8/8] Add comments --- bpfin/financials/balance_sheet_projection.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/bpfin/financials/balance_sheet_projection.py b/bpfin/financials/balance_sheet_projection.py index d5fc23f..60a68da 100644 --- a/bpfin/financials/balance_sheet_projection.py +++ b/bpfin/financials/balance_sheet_projection.py @@ -10,7 +10,11 @@ def balance_sheet_projection(cash_balance, liability, income_statement_projection (dictionary): {year:income statement values - take NOI} analysis_date (dictionary): proforma's starting date and the years of proforma Returns: - dictionary: {year: balance sheet // cash proforma} + dictionary: {year: balance sheet cash available} + The future balance sheet cash available = cash balance + NOI - liability for future. + The past balance sheet cash available = None. + The present balance sheet cash available = cash balance from bank statement or balance sheet + """ analysis_years = {} @@ -27,8 +31,12 @@ def balance_sheet_projection(cash_balance, liability, for an_year in analysis_years: if an_year in cash_balance: analysis_years[an_year] = cash_balance[an_year] + # If the cash available value exists (balance sheet, bank statements), cash available = to that value elif an_year < smallest_year: analysis_years[an_year] = None + # If the analysis period of time starts before cash info is available, return None. + # Ex: If analysis date starts in 1999, but our starting cash balance info is from 2004, + # Then 1999-2003 will be None. elif an_year > largest_year: previous_year = an_year - 1 cash_b = analysis_years[previous_year] @@ -41,5 +49,8 @@ def balance_sheet_projection(cash_balance, liability, else: noi = 0 analysis_years[an_year] = cash_b - liability_value + noi + # If we are asked to project the cash balance for future values, + # We use the most recent cash info + NOI - Liability. For example, if we only have information to 2016, + # Then 2017 = 2016 cash + 2017 NOI (projected) - 2017 liability (projected) return analysis_years -- GitLab