Renting vs. owning comparison calculation











up vote
1
down vote

favorite
1












I have working code that compares rental prices and owning costs, given some parameters. It works, but it surely does not look good. I hadn't worked with time-series before and I wonder how I could improve the code. See it below:



""" Credit: khanacademy.org/downloads/buyrent.xls"""

""" This code compares the cost of renting with the cost of owning a house.
It was orginally thought for the US case. The adjustment of parameteres was made
to fit the case of Brazil. Two alternatives are available the so-called Price table or SAC:
https://pt.wikipedia.org/wiki/Sistema_de_Amortização_Constante"""


import numpy as np
import matplotlib.pyplot as plt


def flow(purchase_p, downpay, inter, yr, prop_tax_rate, yr_maint, yr_cond, yr_ins, appr, inc_tax_rate, inflat,
rent_price, cash, print_ten=120, choice='price'):

if choice == 'price':
fixed_mortgage_payment = (purchase_p - downpay) * (1 - 1/(1 + inter/12)) / (1 - 1/(1 + inter/12) **
(yr * 12 + 1))
else:
fixed_mortgage_payment = (purchase_p - downpay) / (yr * 12)

home_value = np.zeros(yr * 12 + 1)
debt = np.zeros(yr * 12 + 1)
paid_interest = np.zeros(yr * 12 + 1)
insurance = np.zeros(yr * 12 + 1)
cond = np.zeros(yr * 12 + 1)
maint = np.zeros(yr * 12 + 1)
property_tax = np.zeros(yr * 12 + 1)
cash_outflow = np.zeros(yr * 12 + 1)
rent = np.zeros(yr * 12 + 1)
rent_savings = np.zeros(yr * 12 + 1)
paid_principal = np.zeros(yr * 12 + 1)
income_tax = np.zeros(yr * 12 + 1)

home_value[0] = purchase_p
debt[0] = purchase_p - downpay
insurance[0] = yr_ins/12
cond[0] = yr_cond/12
maint[0] = yr_maint/12
rent[0] = rent_price
rent_savings[0] = downpay

for i in range(yr * 12):
paid_interest[i + 1] = debt[i] * inter / 12
if choice == 'price':
paid_principal[i + 1] = fixed_mortgage_payment - paid_interest[i + 1]
debt[i + 1] = debt[i] - paid_principal[i + 1]
else:
paid_principal[i + 1] = fixed_mortgage_payment
debt[i + 1] = debt[i] - fixed_mortgage_payment

home_value[i + 1] = home_value[i] * (1 + appr/12)
insurance[i + 1] = insurance[i] * (1 + inflat/12)
cond[i + 1] = cond[i] * (1 + inflat/12)
maint[i + 1] = maint[i] * (1 + inflat / 12)
property_tax[i + 1] = home_value[i] * (prop_tax_rate/12)
income_tax[i + 1] = (paid_interest[i + 1] + property_tax[i + 1]) * inc_tax_rate
cash_outflow[i + 1] = insurance[i + 1] + cond[i + 1] + maint[i + 1] + property_tax[i + 1] +
paid_interest[i + 1] + paid_principal[i + 1] - income_tax[i + 1]
rent[i + 1] = (1 + appr/12) * rent[i]
rent_savings[i + 1] = rent_savings[i] * (1 + cash/12) + cash_outflow[i + 1] - rent[i + 1]

print('Home value after {:.0f} years: {:,.2f}'.format(print_ten/12, home_value[print_ten]))
print('Debt after {:.0f} years: {:,.2f}'.format(print_ten/12, debt[print_ten]))
print('Equity after {:.0f} years: {:,.2f}'.format(print_ten/12, home_value[print_ten] - debt[print_ten]))
print('Savings if renting after {:.0f} years: {:,.2f}'.format(print_ten/12, rent_savings[print_ten]))
print('Selling cost (6% brokerage rate): {:,.2f}'.format(home_value[print_ten] * .06))
print('Benefit of buying over renting? {:,.2f}'.format(home_value[print_ten] - debt[print_ten]
- rent_savings[print_ten] - home_value[print_ten] * .06))
return {'home_value': home_value, 'debt': debt, 'equity': home_value - debt, 'savings_renting': rent_savings,
'benefit_buying': home_value - debt - rent_savings - (home_value * .06)}


def plotting(data):
plt.plot(data['home_value'], label='Home value')
plt.plot(data['debt'], label='Debt')
plt.plot(data['equity'], label='Equity')
plt.plot(data['savings_renting'], label="Savings when renting")
plt.plot(data['benefit_buying'], label='Benefit of buying')
plt.legend()
plt.annotate('Parms: house price {:,.0f}, ndownpayment {:,.0f}, ninterest annual {:.3f}, years {:.0f}, '
'naluguel {:,.0f}, ncash return annual {:.3f}, ninflation {:.3f},'
'ntabela: {} nhouse appreciation {:.3f}'.format(purchase_price, downpayment, interest, years,
initial_rent, return_cash, inflation, choice,
appreciation),
fontsize=9, xy=(0.43, 0.7), xycoords='axes fraction')
plt.savefig('res1.png')
plt.show()


if __name__ == '__main__':
purchase_price = 800000
downpayment = 0
interest = .08
years = 30
property_tax_rate = 0
yr_maintenance = 0
yr_comdominium = 0
yr_insurance = 0
appreciation = .03 # real appreciation 0%
income_tax_rate = 0 # income deduction on interest and property taxes paid
inflation = .03
initial_rent = purchase_price * .004 # 0.4 % of real values
return_cash = .06 # real return on cash 3%

time = 360
choice = 'SAC'

res = flow(purchase_price, downpayment, interest, years, property_tax_rate, yr_maintenance, yr_comdominium,
yr_insurance, appreciation, income_tax_rate, inflation, initial_rent, return_cash, time, choice)
plotting(res)









share|improve this question









New contributor




B Furtado is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
























    up vote
    1
    down vote

    favorite
    1












    I have working code that compares rental prices and owning costs, given some parameters. It works, but it surely does not look good. I hadn't worked with time-series before and I wonder how I could improve the code. See it below:



    """ Credit: khanacademy.org/downloads/buyrent.xls"""

    """ This code compares the cost of renting with the cost of owning a house.
    It was orginally thought for the US case. The adjustment of parameteres was made
    to fit the case of Brazil. Two alternatives are available the so-called Price table or SAC:
    https://pt.wikipedia.org/wiki/Sistema_de_Amortização_Constante"""


    import numpy as np
    import matplotlib.pyplot as plt


    def flow(purchase_p, downpay, inter, yr, prop_tax_rate, yr_maint, yr_cond, yr_ins, appr, inc_tax_rate, inflat,
    rent_price, cash, print_ten=120, choice='price'):

    if choice == 'price':
    fixed_mortgage_payment = (purchase_p - downpay) * (1 - 1/(1 + inter/12)) / (1 - 1/(1 + inter/12) **
    (yr * 12 + 1))
    else:
    fixed_mortgage_payment = (purchase_p - downpay) / (yr * 12)

    home_value = np.zeros(yr * 12 + 1)
    debt = np.zeros(yr * 12 + 1)
    paid_interest = np.zeros(yr * 12 + 1)
    insurance = np.zeros(yr * 12 + 1)
    cond = np.zeros(yr * 12 + 1)
    maint = np.zeros(yr * 12 + 1)
    property_tax = np.zeros(yr * 12 + 1)
    cash_outflow = np.zeros(yr * 12 + 1)
    rent = np.zeros(yr * 12 + 1)
    rent_savings = np.zeros(yr * 12 + 1)
    paid_principal = np.zeros(yr * 12 + 1)
    income_tax = np.zeros(yr * 12 + 1)

    home_value[0] = purchase_p
    debt[0] = purchase_p - downpay
    insurance[0] = yr_ins/12
    cond[0] = yr_cond/12
    maint[0] = yr_maint/12
    rent[0] = rent_price
    rent_savings[0] = downpay

    for i in range(yr * 12):
    paid_interest[i + 1] = debt[i] * inter / 12
    if choice == 'price':
    paid_principal[i + 1] = fixed_mortgage_payment - paid_interest[i + 1]
    debt[i + 1] = debt[i] - paid_principal[i + 1]
    else:
    paid_principal[i + 1] = fixed_mortgage_payment
    debt[i + 1] = debt[i] - fixed_mortgage_payment

    home_value[i + 1] = home_value[i] * (1 + appr/12)
    insurance[i + 1] = insurance[i] * (1 + inflat/12)
    cond[i + 1] = cond[i] * (1 + inflat/12)
    maint[i + 1] = maint[i] * (1 + inflat / 12)
    property_tax[i + 1] = home_value[i] * (prop_tax_rate/12)
    income_tax[i + 1] = (paid_interest[i + 1] + property_tax[i + 1]) * inc_tax_rate
    cash_outflow[i + 1] = insurance[i + 1] + cond[i + 1] + maint[i + 1] + property_tax[i + 1] +
    paid_interest[i + 1] + paid_principal[i + 1] - income_tax[i + 1]
    rent[i + 1] = (1 + appr/12) * rent[i]
    rent_savings[i + 1] = rent_savings[i] * (1 + cash/12) + cash_outflow[i + 1] - rent[i + 1]

    print('Home value after {:.0f} years: {:,.2f}'.format(print_ten/12, home_value[print_ten]))
    print('Debt after {:.0f} years: {:,.2f}'.format(print_ten/12, debt[print_ten]))
    print('Equity after {:.0f} years: {:,.2f}'.format(print_ten/12, home_value[print_ten] - debt[print_ten]))
    print('Savings if renting after {:.0f} years: {:,.2f}'.format(print_ten/12, rent_savings[print_ten]))
    print('Selling cost (6% brokerage rate): {:,.2f}'.format(home_value[print_ten] * .06))
    print('Benefit of buying over renting? {:,.2f}'.format(home_value[print_ten] - debt[print_ten]
    - rent_savings[print_ten] - home_value[print_ten] * .06))
    return {'home_value': home_value, 'debt': debt, 'equity': home_value - debt, 'savings_renting': rent_savings,
    'benefit_buying': home_value - debt - rent_savings - (home_value * .06)}


    def plotting(data):
    plt.plot(data['home_value'], label='Home value')
    plt.plot(data['debt'], label='Debt')
    plt.plot(data['equity'], label='Equity')
    plt.plot(data['savings_renting'], label="Savings when renting")
    plt.plot(data['benefit_buying'], label='Benefit of buying')
    plt.legend()
    plt.annotate('Parms: house price {:,.0f}, ndownpayment {:,.0f}, ninterest annual {:.3f}, years {:.0f}, '
    'naluguel {:,.0f}, ncash return annual {:.3f}, ninflation {:.3f},'
    'ntabela: {} nhouse appreciation {:.3f}'.format(purchase_price, downpayment, interest, years,
    initial_rent, return_cash, inflation, choice,
    appreciation),
    fontsize=9, xy=(0.43, 0.7), xycoords='axes fraction')
    plt.savefig('res1.png')
    plt.show()


    if __name__ == '__main__':
    purchase_price = 800000
    downpayment = 0
    interest = .08
    years = 30
    property_tax_rate = 0
    yr_maintenance = 0
    yr_comdominium = 0
    yr_insurance = 0
    appreciation = .03 # real appreciation 0%
    income_tax_rate = 0 # income deduction on interest and property taxes paid
    inflation = .03
    initial_rent = purchase_price * .004 # 0.4 % of real values
    return_cash = .06 # real return on cash 3%

    time = 360
    choice = 'SAC'

    res = flow(purchase_price, downpayment, interest, years, property_tax_rate, yr_maintenance, yr_comdominium,
    yr_insurance, appreciation, income_tax_rate, inflation, initial_rent, return_cash, time, choice)
    plotting(res)









    share|improve this question









    New contributor




    B Furtado is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.






















      up vote
      1
      down vote

      favorite
      1









      up vote
      1
      down vote

      favorite
      1






      1





      I have working code that compares rental prices and owning costs, given some parameters. It works, but it surely does not look good. I hadn't worked with time-series before and I wonder how I could improve the code. See it below:



      """ Credit: khanacademy.org/downloads/buyrent.xls"""

      """ This code compares the cost of renting with the cost of owning a house.
      It was orginally thought for the US case. The adjustment of parameteres was made
      to fit the case of Brazil. Two alternatives are available the so-called Price table or SAC:
      https://pt.wikipedia.org/wiki/Sistema_de_Amortização_Constante"""


      import numpy as np
      import matplotlib.pyplot as plt


      def flow(purchase_p, downpay, inter, yr, prop_tax_rate, yr_maint, yr_cond, yr_ins, appr, inc_tax_rate, inflat,
      rent_price, cash, print_ten=120, choice='price'):

      if choice == 'price':
      fixed_mortgage_payment = (purchase_p - downpay) * (1 - 1/(1 + inter/12)) / (1 - 1/(1 + inter/12) **
      (yr * 12 + 1))
      else:
      fixed_mortgage_payment = (purchase_p - downpay) / (yr * 12)

      home_value = np.zeros(yr * 12 + 1)
      debt = np.zeros(yr * 12 + 1)
      paid_interest = np.zeros(yr * 12 + 1)
      insurance = np.zeros(yr * 12 + 1)
      cond = np.zeros(yr * 12 + 1)
      maint = np.zeros(yr * 12 + 1)
      property_tax = np.zeros(yr * 12 + 1)
      cash_outflow = np.zeros(yr * 12 + 1)
      rent = np.zeros(yr * 12 + 1)
      rent_savings = np.zeros(yr * 12 + 1)
      paid_principal = np.zeros(yr * 12 + 1)
      income_tax = np.zeros(yr * 12 + 1)

      home_value[0] = purchase_p
      debt[0] = purchase_p - downpay
      insurance[0] = yr_ins/12
      cond[0] = yr_cond/12
      maint[0] = yr_maint/12
      rent[0] = rent_price
      rent_savings[0] = downpay

      for i in range(yr * 12):
      paid_interest[i + 1] = debt[i] * inter / 12
      if choice == 'price':
      paid_principal[i + 1] = fixed_mortgage_payment - paid_interest[i + 1]
      debt[i + 1] = debt[i] - paid_principal[i + 1]
      else:
      paid_principal[i + 1] = fixed_mortgage_payment
      debt[i + 1] = debt[i] - fixed_mortgage_payment

      home_value[i + 1] = home_value[i] * (1 + appr/12)
      insurance[i + 1] = insurance[i] * (1 + inflat/12)
      cond[i + 1] = cond[i] * (1 + inflat/12)
      maint[i + 1] = maint[i] * (1 + inflat / 12)
      property_tax[i + 1] = home_value[i] * (prop_tax_rate/12)
      income_tax[i + 1] = (paid_interest[i + 1] + property_tax[i + 1]) * inc_tax_rate
      cash_outflow[i + 1] = insurance[i + 1] + cond[i + 1] + maint[i + 1] + property_tax[i + 1] +
      paid_interest[i + 1] + paid_principal[i + 1] - income_tax[i + 1]
      rent[i + 1] = (1 + appr/12) * rent[i]
      rent_savings[i + 1] = rent_savings[i] * (1 + cash/12) + cash_outflow[i + 1] - rent[i + 1]

      print('Home value after {:.0f} years: {:,.2f}'.format(print_ten/12, home_value[print_ten]))
      print('Debt after {:.0f} years: {:,.2f}'.format(print_ten/12, debt[print_ten]))
      print('Equity after {:.0f} years: {:,.2f}'.format(print_ten/12, home_value[print_ten] - debt[print_ten]))
      print('Savings if renting after {:.0f} years: {:,.2f}'.format(print_ten/12, rent_savings[print_ten]))
      print('Selling cost (6% brokerage rate): {:,.2f}'.format(home_value[print_ten] * .06))
      print('Benefit of buying over renting? {:,.2f}'.format(home_value[print_ten] - debt[print_ten]
      - rent_savings[print_ten] - home_value[print_ten] * .06))
      return {'home_value': home_value, 'debt': debt, 'equity': home_value - debt, 'savings_renting': rent_savings,
      'benefit_buying': home_value - debt - rent_savings - (home_value * .06)}


      def plotting(data):
      plt.plot(data['home_value'], label='Home value')
      plt.plot(data['debt'], label='Debt')
      plt.plot(data['equity'], label='Equity')
      plt.plot(data['savings_renting'], label="Savings when renting")
      plt.plot(data['benefit_buying'], label='Benefit of buying')
      plt.legend()
      plt.annotate('Parms: house price {:,.0f}, ndownpayment {:,.0f}, ninterest annual {:.3f}, years {:.0f}, '
      'naluguel {:,.0f}, ncash return annual {:.3f}, ninflation {:.3f},'
      'ntabela: {} nhouse appreciation {:.3f}'.format(purchase_price, downpayment, interest, years,
      initial_rent, return_cash, inflation, choice,
      appreciation),
      fontsize=9, xy=(0.43, 0.7), xycoords='axes fraction')
      plt.savefig('res1.png')
      plt.show()


      if __name__ == '__main__':
      purchase_price = 800000
      downpayment = 0
      interest = .08
      years = 30
      property_tax_rate = 0
      yr_maintenance = 0
      yr_comdominium = 0
      yr_insurance = 0
      appreciation = .03 # real appreciation 0%
      income_tax_rate = 0 # income deduction on interest and property taxes paid
      inflation = .03
      initial_rent = purchase_price * .004 # 0.4 % of real values
      return_cash = .06 # real return on cash 3%

      time = 360
      choice = 'SAC'

      res = flow(purchase_price, downpayment, interest, years, property_tax_rate, yr_maintenance, yr_comdominium,
      yr_insurance, appreciation, income_tax_rate, inflation, initial_rent, return_cash, time, choice)
      plotting(res)









      share|improve this question









      New contributor




      B Furtado is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      I have working code that compares rental prices and owning costs, given some parameters. It works, but it surely does not look good. I hadn't worked with time-series before and I wonder how I could improve the code. See it below:



      """ Credit: khanacademy.org/downloads/buyrent.xls"""

      """ This code compares the cost of renting with the cost of owning a house.
      It was orginally thought for the US case. The adjustment of parameteres was made
      to fit the case of Brazil. Two alternatives are available the so-called Price table or SAC:
      https://pt.wikipedia.org/wiki/Sistema_de_Amortização_Constante"""


      import numpy as np
      import matplotlib.pyplot as plt


      def flow(purchase_p, downpay, inter, yr, prop_tax_rate, yr_maint, yr_cond, yr_ins, appr, inc_tax_rate, inflat,
      rent_price, cash, print_ten=120, choice='price'):

      if choice == 'price':
      fixed_mortgage_payment = (purchase_p - downpay) * (1 - 1/(1 + inter/12)) / (1 - 1/(1 + inter/12) **
      (yr * 12 + 1))
      else:
      fixed_mortgage_payment = (purchase_p - downpay) / (yr * 12)

      home_value = np.zeros(yr * 12 + 1)
      debt = np.zeros(yr * 12 + 1)
      paid_interest = np.zeros(yr * 12 + 1)
      insurance = np.zeros(yr * 12 + 1)
      cond = np.zeros(yr * 12 + 1)
      maint = np.zeros(yr * 12 + 1)
      property_tax = np.zeros(yr * 12 + 1)
      cash_outflow = np.zeros(yr * 12 + 1)
      rent = np.zeros(yr * 12 + 1)
      rent_savings = np.zeros(yr * 12 + 1)
      paid_principal = np.zeros(yr * 12 + 1)
      income_tax = np.zeros(yr * 12 + 1)

      home_value[0] = purchase_p
      debt[0] = purchase_p - downpay
      insurance[0] = yr_ins/12
      cond[0] = yr_cond/12
      maint[0] = yr_maint/12
      rent[0] = rent_price
      rent_savings[0] = downpay

      for i in range(yr * 12):
      paid_interest[i + 1] = debt[i] * inter / 12
      if choice == 'price':
      paid_principal[i + 1] = fixed_mortgage_payment - paid_interest[i + 1]
      debt[i + 1] = debt[i] - paid_principal[i + 1]
      else:
      paid_principal[i + 1] = fixed_mortgage_payment
      debt[i + 1] = debt[i] - fixed_mortgage_payment

      home_value[i + 1] = home_value[i] * (1 + appr/12)
      insurance[i + 1] = insurance[i] * (1 + inflat/12)
      cond[i + 1] = cond[i] * (1 + inflat/12)
      maint[i + 1] = maint[i] * (1 + inflat / 12)
      property_tax[i + 1] = home_value[i] * (prop_tax_rate/12)
      income_tax[i + 1] = (paid_interest[i + 1] + property_tax[i + 1]) * inc_tax_rate
      cash_outflow[i + 1] = insurance[i + 1] + cond[i + 1] + maint[i + 1] + property_tax[i + 1] +
      paid_interest[i + 1] + paid_principal[i + 1] - income_tax[i + 1]
      rent[i + 1] = (1 + appr/12) * rent[i]
      rent_savings[i + 1] = rent_savings[i] * (1 + cash/12) + cash_outflow[i + 1] - rent[i + 1]

      print('Home value after {:.0f} years: {:,.2f}'.format(print_ten/12, home_value[print_ten]))
      print('Debt after {:.0f} years: {:,.2f}'.format(print_ten/12, debt[print_ten]))
      print('Equity after {:.0f} years: {:,.2f}'.format(print_ten/12, home_value[print_ten] - debt[print_ten]))
      print('Savings if renting after {:.0f} years: {:,.2f}'.format(print_ten/12, rent_savings[print_ten]))
      print('Selling cost (6% brokerage rate): {:,.2f}'.format(home_value[print_ten] * .06))
      print('Benefit of buying over renting? {:,.2f}'.format(home_value[print_ten] - debt[print_ten]
      - rent_savings[print_ten] - home_value[print_ten] * .06))
      return {'home_value': home_value, 'debt': debt, 'equity': home_value - debt, 'savings_renting': rent_savings,
      'benefit_buying': home_value - debt - rent_savings - (home_value * .06)}


      def plotting(data):
      plt.plot(data['home_value'], label='Home value')
      plt.plot(data['debt'], label='Debt')
      plt.plot(data['equity'], label='Equity')
      plt.plot(data['savings_renting'], label="Savings when renting")
      plt.plot(data['benefit_buying'], label='Benefit of buying')
      plt.legend()
      plt.annotate('Parms: house price {:,.0f}, ndownpayment {:,.0f}, ninterest annual {:.3f}, years {:.0f}, '
      'naluguel {:,.0f}, ncash return annual {:.3f}, ninflation {:.3f},'
      'ntabela: {} nhouse appreciation {:.3f}'.format(purchase_price, downpayment, interest, years,
      initial_rent, return_cash, inflation, choice,
      appreciation),
      fontsize=9, xy=(0.43, 0.7), xycoords='axes fraction')
      plt.savefig('res1.png')
      plt.show()


      if __name__ == '__main__':
      purchase_price = 800000
      downpayment = 0
      interest = .08
      years = 30
      property_tax_rate = 0
      yr_maintenance = 0
      yr_comdominium = 0
      yr_insurance = 0
      appreciation = .03 # real appreciation 0%
      income_tax_rate = 0 # income deduction on interest and property taxes paid
      inflation = .03
      initial_rent = purchase_price * .004 # 0.4 % of real values
      return_cash = .06 # real return on cash 3%

      time = 360
      choice = 'SAC'

      res = flow(purchase_price, downpayment, interest, years, property_tax_rate, yr_maintenance, yr_comdominium,
      yr_insurance, appreciation, income_tax_rate, inflation, initial_rent, return_cash, time, choice)
      plotting(res)






      python datetime numpy finance






      share|improve this question









      New contributor




      B Furtado is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      B Furtado is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 2 days ago





















      New contributor




      B Furtado is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 2 days ago









      B Furtado

      1086




      1086




      New contributor




      B Furtado is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      B Furtado is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      B Furtado is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          1
          down vote



          accepted










          I can't cover everything that can be done to improve the code, so I will start by the most important parts. Once you incorporate these, you can post the updated version as a new question



          variable names



          the naming of functions, variables etc is more than half of the documentation of your code, so you should be very careful with it. Saving a few characters like maint instead of yearly_maintenanceis not worth it. It made me go back and forth between the method definition and place where you call the method a few times.



          Also make it clear which cost is yearly, and which is monthly.



          You can also include some intermediary variable to clarify some things: loaned_amount = purchase_price - downpayment



          split calculation with presentation



          Your code both calculates the costs and gain, and does a lot of the presentation (for example print('Home value after {:.0f} years: {:,.2f}'.format(print_ten/12, home_value[print_ten]))) in the same method. Separating these two will make testing the code and algorithm a lot easier. If you want to build a GUI later, you will be able to reuse the calculation, which is rather difficult now due to all the side-effects (print)



          vectorize



          The costs which don't change every year, apart from appreciation or inflation, which are all apart from the loan repayments, can be easily vectorized:



          months = years * 12
          months_array = np.arange(months + 1)
          home_value = purchase_price * (1 + appreciation / 12) ** months_array
          maintenance = yearly_maintenance / 12 * (1 + inflation / 12) ** months_array


          and then later summed.



          split of more parts



          The calculation of the amount due each month, or the amortization can be easily split of in different function



          def monthly_payment(*, loaned_amount, months, monthly_interest_rate):
          return (
          loaned_amount
          * (1 - 1 / (1 + monthly_interest_rate))
          / (1 - 1 / (1 + monthly_interest_rate) ** (months))
          )


          little exta comments is needed. The method does what it said in the name and variables. The only thing which might need explanation is the algorithm used.



          def amortize(*, loaned_amount, yearly_interest_rate, monthly_payment):
          monthly_interest_rate = yearly_interest_rate / 12
          principal_paid = 0
          interest = 0
          yield loaned_amount, interest, principal_paid
          while loaned_amount * (1+monthly_interest_rate) >= monthly_payment:
          interest = loaned_amount * monthly_interest_rate
          principal_paid = monthly_payment - interest
          loaned_amount = loaned_amount - principal_paid
          yield loaned_amount, interest, principal_paid

          interest = loaned_amount * monthly_interest_rate
          yield 0, interest, loaned_amount


          Here, a generator is more clear than appending items to 3 different lists, and then returning the lists in the end.



          For both I used keyword-only arguments, which are a lot clearer after 2 years (no more questions: what argument came first...)



          and they are called like this:



          elif system.lower() == "price":
          monthly_amount = monthly_payment(
          loaned_amount=loaned_amount,
          months=months,
          monthly_interest_rate=yearly_interest_rate / 12,
          )
          amortization = np.array(
          list(
          amortize(
          loaned_amount=loaned_amount,
          yearly_interest_rate=yearly_interest_rate,
          monthly_payment=monthly_amount,
          )
          )
          )
          debt, interest_paid, principal_paid = np.split(amortization, 3, axis=1)


          line length



          Some of your lines were very long, requiring horizontal scrolling. Try to limit the length of the lines of code. I use the black formatter to take care of line lengths etc for me.



          the whole thing



          A (simplified) version of the flow method:



          def flow(
          purchase_price,
          downpayment,
          yearly_interest_rate,
          years,
          property_tax_rate,
          yearly_maintenance,
          yearly_comdominium,
          yearly_insurance,
          appreciation,
          income_tax_rate,
          inflation,
          initial_rent,
          return_cash,
          time,
          system,
          ):
          months = years * 12
          months_array = np.arange(months + 1)
          home_value = purchase_price * (1 + appreciation / 12) ** months_array
          maintenance = yearly_maintenance / 12 * (1 + inflation / 12) ** months_array
          insurance = yearly_insurance / 12 * (1 + inflation / 12) ** months_array

          loaned_amount = purchase_price - downpayment

          if system.upper() == "SAC":
          debt = loaned_amount * (1 - months_array / months)
          interest_paid = loaned_amount * yearly_interest_rate / 12
          principal_paid = loaned_amount / months * np.ones_like(months_array)

          elif system.lower() == "price":
          monthly_amount = monthly_payment(
          loaned_amount=loaned_amount,
          months=months,
          monthly_interest_rate=yearly_interest_rate / 12,
          )
          amortization = np.array(
          list(
          amortize(
          loaned_amount=loaned_amount,
          yearly_interest_rate=yearly_interest_rate,
          monthly_payment=monthly_amount,
          )
          )
          )
          debt, interest_paid, principal_paid = np.split(amortization, 3, axis=1)

          property_tax = home_value * property_tax_rate
          income_tax = (interest_paid + property_tax) * income_tax_rate
          cash_outflow = (
          insurance
          + maintenance
          + property_tax
          + interest_paid
          + principal_paid
          - income_tax
          )
          rent = initial_rent * (1 + appreciation / 12) ** months_array

          rent_savings = (cash_outflow - rent) * (
          1 + return_cash / 12
          ) ** months_array

          return months, debt, rent_savings


          the return statement can be expanded. Instead of all the arrays in a tuple, I would combine the either in a dict or a pandas.DataFrame.



          This can be called like:



          if __name__ == "__main__":
          purchase_price = 800000
          downpayment = 0
          interest = 0.08
          years = 20
          property_tax_rate = 0
          yearly_maintenance = 100
          yearly_comdominium = 0
          yearly_insurance = 0
          appreciation = 0.03 # real appreciation 0%
          income_tax_rate = 0 # income deduction on interest and property taxes paid
          inflation = 0.03
          initial_rent = purchase_price * 0.004 # 0.4 % of real values
          return_cash = 0.06 # real return on cash 3%

          time = 240
          choice = "sac"
          months, debt, rent_savings = flow(
          purchase_price,
          downpayment,
          interest,
          years,
          property_tax_rate,
          yearly_maintenance,
          yearly_comdominium,
          yearly_insurance,
          appreciation,
          income_tax_rate,
          inflation,
          initial_rent,
          return_cash,
          time,
          choice,
          )
          rent_savings.sum()





          share|improve this answer





















            Your Answer





            StackExchange.ifUsing("editor", function () {
            return StackExchange.using("mathjaxEditing", function () {
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            });
            });
            }, "mathjax-editing");

            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "196"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });






            B Furtado is a new contributor. Be nice, and check out our Code of Conduct.










             

            draft saved


            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207586%2frenting-vs-owning-comparison-calculation%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            1
            down vote



            accepted










            I can't cover everything that can be done to improve the code, so I will start by the most important parts. Once you incorporate these, you can post the updated version as a new question



            variable names



            the naming of functions, variables etc is more than half of the documentation of your code, so you should be very careful with it. Saving a few characters like maint instead of yearly_maintenanceis not worth it. It made me go back and forth between the method definition and place where you call the method a few times.



            Also make it clear which cost is yearly, and which is monthly.



            You can also include some intermediary variable to clarify some things: loaned_amount = purchase_price - downpayment



            split calculation with presentation



            Your code both calculates the costs and gain, and does a lot of the presentation (for example print('Home value after {:.0f} years: {:,.2f}'.format(print_ten/12, home_value[print_ten]))) in the same method. Separating these two will make testing the code and algorithm a lot easier. If you want to build a GUI later, you will be able to reuse the calculation, which is rather difficult now due to all the side-effects (print)



            vectorize



            The costs which don't change every year, apart from appreciation or inflation, which are all apart from the loan repayments, can be easily vectorized:



            months = years * 12
            months_array = np.arange(months + 1)
            home_value = purchase_price * (1 + appreciation / 12) ** months_array
            maintenance = yearly_maintenance / 12 * (1 + inflation / 12) ** months_array


            and then later summed.



            split of more parts



            The calculation of the amount due each month, or the amortization can be easily split of in different function



            def monthly_payment(*, loaned_amount, months, monthly_interest_rate):
            return (
            loaned_amount
            * (1 - 1 / (1 + monthly_interest_rate))
            / (1 - 1 / (1 + monthly_interest_rate) ** (months))
            )


            little exta comments is needed. The method does what it said in the name and variables. The only thing which might need explanation is the algorithm used.



            def amortize(*, loaned_amount, yearly_interest_rate, monthly_payment):
            monthly_interest_rate = yearly_interest_rate / 12
            principal_paid = 0
            interest = 0
            yield loaned_amount, interest, principal_paid
            while loaned_amount * (1+monthly_interest_rate) >= monthly_payment:
            interest = loaned_amount * monthly_interest_rate
            principal_paid = monthly_payment - interest
            loaned_amount = loaned_amount - principal_paid
            yield loaned_amount, interest, principal_paid

            interest = loaned_amount * monthly_interest_rate
            yield 0, interest, loaned_amount


            Here, a generator is more clear than appending items to 3 different lists, and then returning the lists in the end.



            For both I used keyword-only arguments, which are a lot clearer after 2 years (no more questions: what argument came first...)



            and they are called like this:



            elif system.lower() == "price":
            monthly_amount = monthly_payment(
            loaned_amount=loaned_amount,
            months=months,
            monthly_interest_rate=yearly_interest_rate / 12,
            )
            amortization = np.array(
            list(
            amortize(
            loaned_amount=loaned_amount,
            yearly_interest_rate=yearly_interest_rate,
            monthly_payment=monthly_amount,
            )
            )
            )
            debt, interest_paid, principal_paid = np.split(amortization, 3, axis=1)


            line length



            Some of your lines were very long, requiring horizontal scrolling. Try to limit the length of the lines of code. I use the black formatter to take care of line lengths etc for me.



            the whole thing



            A (simplified) version of the flow method:



            def flow(
            purchase_price,
            downpayment,
            yearly_interest_rate,
            years,
            property_tax_rate,
            yearly_maintenance,
            yearly_comdominium,
            yearly_insurance,
            appreciation,
            income_tax_rate,
            inflation,
            initial_rent,
            return_cash,
            time,
            system,
            ):
            months = years * 12
            months_array = np.arange(months + 1)
            home_value = purchase_price * (1 + appreciation / 12) ** months_array
            maintenance = yearly_maintenance / 12 * (1 + inflation / 12) ** months_array
            insurance = yearly_insurance / 12 * (1 + inflation / 12) ** months_array

            loaned_amount = purchase_price - downpayment

            if system.upper() == "SAC":
            debt = loaned_amount * (1 - months_array / months)
            interest_paid = loaned_amount * yearly_interest_rate / 12
            principal_paid = loaned_amount / months * np.ones_like(months_array)

            elif system.lower() == "price":
            monthly_amount = monthly_payment(
            loaned_amount=loaned_amount,
            months=months,
            monthly_interest_rate=yearly_interest_rate / 12,
            )
            amortization = np.array(
            list(
            amortize(
            loaned_amount=loaned_amount,
            yearly_interest_rate=yearly_interest_rate,
            monthly_payment=monthly_amount,
            )
            )
            )
            debt, interest_paid, principal_paid = np.split(amortization, 3, axis=1)

            property_tax = home_value * property_tax_rate
            income_tax = (interest_paid + property_tax) * income_tax_rate
            cash_outflow = (
            insurance
            + maintenance
            + property_tax
            + interest_paid
            + principal_paid
            - income_tax
            )
            rent = initial_rent * (1 + appreciation / 12) ** months_array

            rent_savings = (cash_outflow - rent) * (
            1 + return_cash / 12
            ) ** months_array

            return months, debt, rent_savings


            the return statement can be expanded. Instead of all the arrays in a tuple, I would combine the either in a dict or a pandas.DataFrame.



            This can be called like:



            if __name__ == "__main__":
            purchase_price = 800000
            downpayment = 0
            interest = 0.08
            years = 20
            property_tax_rate = 0
            yearly_maintenance = 100
            yearly_comdominium = 0
            yearly_insurance = 0
            appreciation = 0.03 # real appreciation 0%
            income_tax_rate = 0 # income deduction on interest and property taxes paid
            inflation = 0.03
            initial_rent = purchase_price * 0.004 # 0.4 % of real values
            return_cash = 0.06 # real return on cash 3%

            time = 240
            choice = "sac"
            months, debt, rent_savings = flow(
            purchase_price,
            downpayment,
            interest,
            years,
            property_tax_rate,
            yearly_maintenance,
            yearly_comdominium,
            yearly_insurance,
            appreciation,
            income_tax_rate,
            inflation,
            initial_rent,
            return_cash,
            time,
            choice,
            )
            rent_savings.sum()





            share|improve this answer

























              up vote
              1
              down vote



              accepted










              I can't cover everything that can be done to improve the code, so I will start by the most important parts. Once you incorporate these, you can post the updated version as a new question



              variable names



              the naming of functions, variables etc is more than half of the documentation of your code, so you should be very careful with it. Saving a few characters like maint instead of yearly_maintenanceis not worth it. It made me go back and forth between the method definition and place where you call the method a few times.



              Also make it clear which cost is yearly, and which is monthly.



              You can also include some intermediary variable to clarify some things: loaned_amount = purchase_price - downpayment



              split calculation with presentation



              Your code both calculates the costs and gain, and does a lot of the presentation (for example print('Home value after {:.0f} years: {:,.2f}'.format(print_ten/12, home_value[print_ten]))) in the same method. Separating these two will make testing the code and algorithm a lot easier. If you want to build a GUI later, you will be able to reuse the calculation, which is rather difficult now due to all the side-effects (print)



              vectorize



              The costs which don't change every year, apart from appreciation or inflation, which are all apart from the loan repayments, can be easily vectorized:



              months = years * 12
              months_array = np.arange(months + 1)
              home_value = purchase_price * (1 + appreciation / 12) ** months_array
              maintenance = yearly_maintenance / 12 * (1 + inflation / 12) ** months_array


              and then later summed.



              split of more parts



              The calculation of the amount due each month, or the amortization can be easily split of in different function



              def monthly_payment(*, loaned_amount, months, monthly_interest_rate):
              return (
              loaned_amount
              * (1 - 1 / (1 + monthly_interest_rate))
              / (1 - 1 / (1 + monthly_interest_rate) ** (months))
              )


              little exta comments is needed. The method does what it said in the name and variables. The only thing which might need explanation is the algorithm used.



              def amortize(*, loaned_amount, yearly_interest_rate, monthly_payment):
              monthly_interest_rate = yearly_interest_rate / 12
              principal_paid = 0
              interest = 0
              yield loaned_amount, interest, principal_paid
              while loaned_amount * (1+monthly_interest_rate) >= monthly_payment:
              interest = loaned_amount * monthly_interest_rate
              principal_paid = monthly_payment - interest
              loaned_amount = loaned_amount - principal_paid
              yield loaned_amount, interest, principal_paid

              interest = loaned_amount * monthly_interest_rate
              yield 0, interest, loaned_amount


              Here, a generator is more clear than appending items to 3 different lists, and then returning the lists in the end.



              For both I used keyword-only arguments, which are a lot clearer after 2 years (no more questions: what argument came first...)



              and they are called like this:



              elif system.lower() == "price":
              monthly_amount = monthly_payment(
              loaned_amount=loaned_amount,
              months=months,
              monthly_interest_rate=yearly_interest_rate / 12,
              )
              amortization = np.array(
              list(
              amortize(
              loaned_amount=loaned_amount,
              yearly_interest_rate=yearly_interest_rate,
              monthly_payment=monthly_amount,
              )
              )
              )
              debt, interest_paid, principal_paid = np.split(amortization, 3, axis=1)


              line length



              Some of your lines were very long, requiring horizontal scrolling. Try to limit the length of the lines of code. I use the black formatter to take care of line lengths etc for me.



              the whole thing



              A (simplified) version of the flow method:



              def flow(
              purchase_price,
              downpayment,
              yearly_interest_rate,
              years,
              property_tax_rate,
              yearly_maintenance,
              yearly_comdominium,
              yearly_insurance,
              appreciation,
              income_tax_rate,
              inflation,
              initial_rent,
              return_cash,
              time,
              system,
              ):
              months = years * 12
              months_array = np.arange(months + 1)
              home_value = purchase_price * (1 + appreciation / 12) ** months_array
              maintenance = yearly_maintenance / 12 * (1 + inflation / 12) ** months_array
              insurance = yearly_insurance / 12 * (1 + inflation / 12) ** months_array

              loaned_amount = purchase_price - downpayment

              if system.upper() == "SAC":
              debt = loaned_amount * (1 - months_array / months)
              interest_paid = loaned_amount * yearly_interest_rate / 12
              principal_paid = loaned_amount / months * np.ones_like(months_array)

              elif system.lower() == "price":
              monthly_amount = monthly_payment(
              loaned_amount=loaned_amount,
              months=months,
              monthly_interest_rate=yearly_interest_rate / 12,
              )
              amortization = np.array(
              list(
              amortize(
              loaned_amount=loaned_amount,
              yearly_interest_rate=yearly_interest_rate,
              monthly_payment=monthly_amount,
              )
              )
              )
              debt, interest_paid, principal_paid = np.split(amortization, 3, axis=1)

              property_tax = home_value * property_tax_rate
              income_tax = (interest_paid + property_tax) * income_tax_rate
              cash_outflow = (
              insurance
              + maintenance
              + property_tax
              + interest_paid
              + principal_paid
              - income_tax
              )
              rent = initial_rent * (1 + appreciation / 12) ** months_array

              rent_savings = (cash_outflow - rent) * (
              1 + return_cash / 12
              ) ** months_array

              return months, debt, rent_savings


              the return statement can be expanded. Instead of all the arrays in a tuple, I would combine the either in a dict or a pandas.DataFrame.



              This can be called like:



              if __name__ == "__main__":
              purchase_price = 800000
              downpayment = 0
              interest = 0.08
              years = 20
              property_tax_rate = 0
              yearly_maintenance = 100
              yearly_comdominium = 0
              yearly_insurance = 0
              appreciation = 0.03 # real appreciation 0%
              income_tax_rate = 0 # income deduction on interest and property taxes paid
              inflation = 0.03
              initial_rent = purchase_price * 0.004 # 0.4 % of real values
              return_cash = 0.06 # real return on cash 3%

              time = 240
              choice = "sac"
              months, debt, rent_savings = flow(
              purchase_price,
              downpayment,
              interest,
              years,
              property_tax_rate,
              yearly_maintenance,
              yearly_comdominium,
              yearly_insurance,
              appreciation,
              income_tax_rate,
              inflation,
              initial_rent,
              return_cash,
              time,
              choice,
              )
              rent_savings.sum()





              share|improve this answer























                up vote
                1
                down vote



                accepted







                up vote
                1
                down vote



                accepted






                I can't cover everything that can be done to improve the code, so I will start by the most important parts. Once you incorporate these, you can post the updated version as a new question



                variable names



                the naming of functions, variables etc is more than half of the documentation of your code, so you should be very careful with it. Saving a few characters like maint instead of yearly_maintenanceis not worth it. It made me go back and forth between the method definition and place where you call the method a few times.



                Also make it clear which cost is yearly, and which is monthly.



                You can also include some intermediary variable to clarify some things: loaned_amount = purchase_price - downpayment



                split calculation with presentation



                Your code both calculates the costs and gain, and does a lot of the presentation (for example print('Home value after {:.0f} years: {:,.2f}'.format(print_ten/12, home_value[print_ten]))) in the same method. Separating these two will make testing the code and algorithm a lot easier. If you want to build a GUI later, you will be able to reuse the calculation, which is rather difficult now due to all the side-effects (print)



                vectorize



                The costs which don't change every year, apart from appreciation or inflation, which are all apart from the loan repayments, can be easily vectorized:



                months = years * 12
                months_array = np.arange(months + 1)
                home_value = purchase_price * (1 + appreciation / 12) ** months_array
                maintenance = yearly_maintenance / 12 * (1 + inflation / 12) ** months_array


                and then later summed.



                split of more parts



                The calculation of the amount due each month, or the amortization can be easily split of in different function



                def monthly_payment(*, loaned_amount, months, monthly_interest_rate):
                return (
                loaned_amount
                * (1 - 1 / (1 + monthly_interest_rate))
                / (1 - 1 / (1 + monthly_interest_rate) ** (months))
                )


                little exta comments is needed. The method does what it said in the name and variables. The only thing which might need explanation is the algorithm used.



                def amortize(*, loaned_amount, yearly_interest_rate, monthly_payment):
                monthly_interest_rate = yearly_interest_rate / 12
                principal_paid = 0
                interest = 0
                yield loaned_amount, interest, principal_paid
                while loaned_amount * (1+monthly_interest_rate) >= monthly_payment:
                interest = loaned_amount * monthly_interest_rate
                principal_paid = monthly_payment - interest
                loaned_amount = loaned_amount - principal_paid
                yield loaned_amount, interest, principal_paid

                interest = loaned_amount * monthly_interest_rate
                yield 0, interest, loaned_amount


                Here, a generator is more clear than appending items to 3 different lists, and then returning the lists in the end.



                For both I used keyword-only arguments, which are a lot clearer after 2 years (no more questions: what argument came first...)



                and they are called like this:



                elif system.lower() == "price":
                monthly_amount = monthly_payment(
                loaned_amount=loaned_amount,
                months=months,
                monthly_interest_rate=yearly_interest_rate / 12,
                )
                amortization = np.array(
                list(
                amortize(
                loaned_amount=loaned_amount,
                yearly_interest_rate=yearly_interest_rate,
                monthly_payment=monthly_amount,
                )
                )
                )
                debt, interest_paid, principal_paid = np.split(amortization, 3, axis=1)


                line length



                Some of your lines were very long, requiring horizontal scrolling. Try to limit the length of the lines of code. I use the black formatter to take care of line lengths etc for me.



                the whole thing



                A (simplified) version of the flow method:



                def flow(
                purchase_price,
                downpayment,
                yearly_interest_rate,
                years,
                property_tax_rate,
                yearly_maintenance,
                yearly_comdominium,
                yearly_insurance,
                appreciation,
                income_tax_rate,
                inflation,
                initial_rent,
                return_cash,
                time,
                system,
                ):
                months = years * 12
                months_array = np.arange(months + 1)
                home_value = purchase_price * (1 + appreciation / 12) ** months_array
                maintenance = yearly_maintenance / 12 * (1 + inflation / 12) ** months_array
                insurance = yearly_insurance / 12 * (1 + inflation / 12) ** months_array

                loaned_amount = purchase_price - downpayment

                if system.upper() == "SAC":
                debt = loaned_amount * (1 - months_array / months)
                interest_paid = loaned_amount * yearly_interest_rate / 12
                principal_paid = loaned_amount / months * np.ones_like(months_array)

                elif system.lower() == "price":
                monthly_amount = monthly_payment(
                loaned_amount=loaned_amount,
                months=months,
                monthly_interest_rate=yearly_interest_rate / 12,
                )
                amortization = np.array(
                list(
                amortize(
                loaned_amount=loaned_amount,
                yearly_interest_rate=yearly_interest_rate,
                monthly_payment=monthly_amount,
                )
                )
                )
                debt, interest_paid, principal_paid = np.split(amortization, 3, axis=1)

                property_tax = home_value * property_tax_rate
                income_tax = (interest_paid + property_tax) * income_tax_rate
                cash_outflow = (
                insurance
                + maintenance
                + property_tax
                + interest_paid
                + principal_paid
                - income_tax
                )
                rent = initial_rent * (1 + appreciation / 12) ** months_array

                rent_savings = (cash_outflow - rent) * (
                1 + return_cash / 12
                ) ** months_array

                return months, debt, rent_savings


                the return statement can be expanded. Instead of all the arrays in a tuple, I would combine the either in a dict or a pandas.DataFrame.



                This can be called like:



                if __name__ == "__main__":
                purchase_price = 800000
                downpayment = 0
                interest = 0.08
                years = 20
                property_tax_rate = 0
                yearly_maintenance = 100
                yearly_comdominium = 0
                yearly_insurance = 0
                appreciation = 0.03 # real appreciation 0%
                income_tax_rate = 0 # income deduction on interest and property taxes paid
                inflation = 0.03
                initial_rent = purchase_price * 0.004 # 0.4 % of real values
                return_cash = 0.06 # real return on cash 3%

                time = 240
                choice = "sac"
                months, debt, rent_savings = flow(
                purchase_price,
                downpayment,
                interest,
                years,
                property_tax_rate,
                yearly_maintenance,
                yearly_comdominium,
                yearly_insurance,
                appreciation,
                income_tax_rate,
                inflation,
                initial_rent,
                return_cash,
                time,
                choice,
                )
                rent_savings.sum()





                share|improve this answer












                I can't cover everything that can be done to improve the code, so I will start by the most important parts. Once you incorporate these, you can post the updated version as a new question



                variable names



                the naming of functions, variables etc is more than half of the documentation of your code, so you should be very careful with it. Saving a few characters like maint instead of yearly_maintenanceis not worth it. It made me go back and forth between the method definition and place where you call the method a few times.



                Also make it clear which cost is yearly, and which is monthly.



                You can also include some intermediary variable to clarify some things: loaned_amount = purchase_price - downpayment



                split calculation with presentation



                Your code both calculates the costs and gain, and does a lot of the presentation (for example print('Home value after {:.0f} years: {:,.2f}'.format(print_ten/12, home_value[print_ten]))) in the same method. Separating these two will make testing the code and algorithm a lot easier. If you want to build a GUI later, you will be able to reuse the calculation, which is rather difficult now due to all the side-effects (print)



                vectorize



                The costs which don't change every year, apart from appreciation or inflation, which are all apart from the loan repayments, can be easily vectorized:



                months = years * 12
                months_array = np.arange(months + 1)
                home_value = purchase_price * (1 + appreciation / 12) ** months_array
                maintenance = yearly_maintenance / 12 * (1 + inflation / 12) ** months_array


                and then later summed.



                split of more parts



                The calculation of the amount due each month, or the amortization can be easily split of in different function



                def monthly_payment(*, loaned_amount, months, monthly_interest_rate):
                return (
                loaned_amount
                * (1 - 1 / (1 + monthly_interest_rate))
                / (1 - 1 / (1 + monthly_interest_rate) ** (months))
                )


                little exta comments is needed. The method does what it said in the name and variables. The only thing which might need explanation is the algorithm used.



                def amortize(*, loaned_amount, yearly_interest_rate, monthly_payment):
                monthly_interest_rate = yearly_interest_rate / 12
                principal_paid = 0
                interest = 0
                yield loaned_amount, interest, principal_paid
                while loaned_amount * (1+monthly_interest_rate) >= monthly_payment:
                interest = loaned_amount * monthly_interest_rate
                principal_paid = monthly_payment - interest
                loaned_amount = loaned_amount - principal_paid
                yield loaned_amount, interest, principal_paid

                interest = loaned_amount * monthly_interest_rate
                yield 0, interest, loaned_amount


                Here, a generator is more clear than appending items to 3 different lists, and then returning the lists in the end.



                For both I used keyword-only arguments, which are a lot clearer after 2 years (no more questions: what argument came first...)



                and they are called like this:



                elif system.lower() == "price":
                monthly_amount = monthly_payment(
                loaned_amount=loaned_amount,
                months=months,
                monthly_interest_rate=yearly_interest_rate / 12,
                )
                amortization = np.array(
                list(
                amortize(
                loaned_amount=loaned_amount,
                yearly_interest_rate=yearly_interest_rate,
                monthly_payment=monthly_amount,
                )
                )
                )
                debt, interest_paid, principal_paid = np.split(amortization, 3, axis=1)


                line length



                Some of your lines were very long, requiring horizontal scrolling. Try to limit the length of the lines of code. I use the black formatter to take care of line lengths etc for me.



                the whole thing



                A (simplified) version of the flow method:



                def flow(
                purchase_price,
                downpayment,
                yearly_interest_rate,
                years,
                property_tax_rate,
                yearly_maintenance,
                yearly_comdominium,
                yearly_insurance,
                appreciation,
                income_tax_rate,
                inflation,
                initial_rent,
                return_cash,
                time,
                system,
                ):
                months = years * 12
                months_array = np.arange(months + 1)
                home_value = purchase_price * (1 + appreciation / 12) ** months_array
                maintenance = yearly_maintenance / 12 * (1 + inflation / 12) ** months_array
                insurance = yearly_insurance / 12 * (1 + inflation / 12) ** months_array

                loaned_amount = purchase_price - downpayment

                if system.upper() == "SAC":
                debt = loaned_amount * (1 - months_array / months)
                interest_paid = loaned_amount * yearly_interest_rate / 12
                principal_paid = loaned_amount / months * np.ones_like(months_array)

                elif system.lower() == "price":
                monthly_amount = monthly_payment(
                loaned_amount=loaned_amount,
                months=months,
                monthly_interest_rate=yearly_interest_rate / 12,
                )
                amortization = np.array(
                list(
                amortize(
                loaned_amount=loaned_amount,
                yearly_interest_rate=yearly_interest_rate,
                monthly_payment=monthly_amount,
                )
                )
                )
                debt, interest_paid, principal_paid = np.split(amortization, 3, axis=1)

                property_tax = home_value * property_tax_rate
                income_tax = (interest_paid + property_tax) * income_tax_rate
                cash_outflow = (
                insurance
                + maintenance
                + property_tax
                + interest_paid
                + principal_paid
                - income_tax
                )
                rent = initial_rent * (1 + appreciation / 12) ** months_array

                rent_savings = (cash_outflow - rent) * (
                1 + return_cash / 12
                ) ** months_array

                return months, debt, rent_savings


                the return statement can be expanded. Instead of all the arrays in a tuple, I would combine the either in a dict or a pandas.DataFrame.



                This can be called like:



                if __name__ == "__main__":
                purchase_price = 800000
                downpayment = 0
                interest = 0.08
                years = 20
                property_tax_rate = 0
                yearly_maintenance = 100
                yearly_comdominium = 0
                yearly_insurance = 0
                appreciation = 0.03 # real appreciation 0%
                income_tax_rate = 0 # income deduction on interest and property taxes paid
                inflation = 0.03
                initial_rent = purchase_price * 0.004 # 0.4 % of real values
                return_cash = 0.06 # real return on cash 3%

                time = 240
                choice = "sac"
                months, debt, rent_savings = flow(
                purchase_price,
                downpayment,
                interest,
                years,
                property_tax_rate,
                yearly_maintenance,
                yearly_comdominium,
                yearly_insurance,
                appreciation,
                income_tax_rate,
                inflation,
                initial_rent,
                return_cash,
                time,
                choice,
                )
                rent_savings.sum()






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered 2 hours ago









                Maarten Fabré

                4,239417




                4,239417






















                    B Furtado is a new contributor. Be nice, and check out our Code of Conduct.










                     

                    draft saved


                    draft discarded


















                    B Furtado is a new contributor. Be nice, and check out our Code of Conduct.













                    B Furtado is a new contributor. Be nice, and check out our Code of Conduct.












                    B Furtado is a new contributor. Be nice, and check out our Code of Conduct.















                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207586%2frenting-vs-owning-comparison-calculation%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Morgemoulin

                    Scott Moir

                    Souastre