房屋贷款计算器(还在头疼每月房贷还款,这个房贷计算机让你一目了然)

还在头疼每月房贷还款,这个房贷盘算机让你一清二楚

本文分享自华为云社区《房贷盘算器-从原理、盘算到事先还款和可视化-云社区-华为云》,作者: 蜉蝣与海 。

择要:迩来各地楼市震荡不休,不少银行纷繁降息,随后更是引发了一波事先还款的大潮。经过楼市小步骤上存款盘算器等东西人们可以很容易的了解每期还款本金、不同还款办法的利钱差别、事先还款节流利钱等成绩。了解这些东西的盘算原理,可以做到胸有定见,临危不慌。本文已公布至华为云生态社区AI Gallery,文中触及一切代码可以直接经过页面进入云上Code Lab运转,接待开发者前去体验。

弁言

迩来各地楼市震荡不休,2022年12月份以来不少银行纷繁降息,随后更是引发了一波事先还款的大潮。不少地区楼市干系的微信小步骤也自带了存款盘算器、事先还款盘算器等东西,经过这些东西人们可以很容易的了解每期还款本金、等额本金/本息的利钱差别、事先还款节流利钱的成绩。

了解这些盘算东西的干系原理,可以做到胸有定见,临危不慌。

  1. 本文对应代码和脚本公布至华为云生态社区AI Gallery:存款盘算器-从原理、公式到事先还款和可视化→AI Gallery_Notebook具体_开发者_华为云,接待开发者前去体验,文中触及一切代码可以直接经过页面进入Model Arts Code Lab运转。使用该脚本稍加修正后即可实验开发一个合适本身地区政策的存款盘算&事先还款小步骤。
  2. 本文只是研讨存款天生、事先还贷方面的干系盘算原理,不构成任何投资理财方面的发起。

先来看个使用东西盘算事先还款的后果

先来看个使用东西盘算事先还款的后果,再来探究干系原理。

存款87.5万,利率4.9%还20年,使用等额本息的办法,在第13个月事先还10万,使用月供安定年限延长办法,在CodeLab中运转下述步骤后可以盘算事先还款节流利钱,和微信上事先还款小步骤盘算后果一律:

a, b, c, d, e = extraPaidWithFixedPaid(12 * 20, 875000, 0.049, False, [(13, 100000)])
drawDiagramExtraPaid(12 * 20, a, b, d, e)
drawTableExtraPaid(12 * 20, a, b, c, d, e)[10:20]


如图,延长了40个月(3年4个月)账期,次月还款额以及节流利钱等都与小步骤盘算一律。

怎样盘算利钱

背景:等额本金和等额本息的协同点

了解过存款的小伙伴都晓得,存款有等额本金和等额本息这两种办法,前者每月还款的本金相反,利钱逐月渐减;后者每月还款额相反,刚开头还款时利钱还的多,后方本金还的渐渐增多。参考网上讨论利钱盘算的诸多文章,两个模子实际上,都有下列协同特点:

  • 利钱按月利率盘算,一月一期
  • 定期还款情况下当月应还利钱只由未还完的本金决定
  • 每月还款额除了未还本金产生的全部利钱外,剩下的金额应该全部用于奉还本金

像迩来局部银行提出的先息后本(先还利钱多少年,最初一次性奉还本金)则不切合这个条件。

还款额的盘算

知乎文章为什么买房存款,最好选择等额本金?中提到了一个例子:

前阵子,院长有位伙伴在惠州买了套120平米的房,总价125万支配,约莫贷了87.5万。
办房贷的时分,他听从贩卖的发起,选了【等额本息】的还款办法。每个月安稳还5726.39元。这个还款额度在他的承受范围之内,因此就选了。
那假定选择等额本金呢?第一个月要还的金额为7218.75元,今后每个月少还14.89元,直至20年后还完。

经过形貌可知,存款87.5万,贷20年,等额本息每月还款5726.39元,等额本金首月还款7218.75元。假定文中的存款未使用公积金,盘算时利率为安稳利率,依据网上的存款盘算器可知此时的存款年利率为4.9%。

以这个例子为例,简便分析等额本金和等额本息的盘算办法:

起首贷20年,按月分期,存款为

20?12=240期。

年利率4.9%,月利率为

0.049÷12=0.004983 即0.4083%。

等额本金 情况下:

每月应还本金=总本金÷期数

每月应还利钱=剩余本金×月利率

每月还款额=每月应还本金+每月应还利钱

在这个例子中:

  • 每月应还本金为
    875000÷240=3645.83元
  • 首月应还利钱为
    875000×0.4083元
  • 首月应还:
    3645.83+3572.92=7218.75元。
  • 第2月剩余本金为
    875000?3645.83=871354.17元。
  • 第2月应还利钱为
    871354.17×0.4083元。
  • 第2月应还:
    3645.83+3558.03=7203.86元。

将这段逻辑笼统为代码有:

import matplotlib.pyplot as plt
import numpy as np
def averageCapital(months, principal, rate):
month_rate = rate / 12
monthly_capital = principal / months
interests = [0] * months
capitals = [0] * months
left_principal = [0] * months
left_principal[0] = principal
total_payment = [0] * months
for i in range(0, months):
interests[i] = left_principal[i] * month_rate
capitals[i] = monthly_capital
total_payment[i] = monthly_capital + interests[i]
if i + 1 < months:
left_principal[i + 1] = left_principal[i] - monthly_capital
return capitals, interests, total_payment

为了便于查察再封装一个打印成表格的函数:

import pandas as pd
def drawTable(months, fn, *args, **kwargs):
capitals, interests, total_payment = fn(months, *args, **kwargs)
paid_capital = [0] * months
paid_interests = [0] * months
paid_capital[0] = capitals[0]
paid_interests[0] = interests[0]
for x in range(1, months):
paid_capital[x] = paid_capital[x - 1] + capitals[x]
paid_interests[x] = paid_interests[x - 1] + interests[x]
origin = pd.DataFrame([total_payment, capitals, interests, paid_capital, paid_interests])
return pd.DataFrame(origin.values.T, columns=['还款额','还款本金','还款利钱','已还本金','已还利钱'], index=np.arange(1, months + 1))

我们运转一下知乎上的例子,看看头几年还款的本金、利钱等:

pd.options.display.float_format = '{:.2f}'.format
drawTable(12 * 20, averageCapital, 875000, 0.049)[0:10]

可以看到和文中形貌一律,使用微信房小团小步骤,也可以打印出一律的后果。
等额本息 的盘算办法有些繁复,参考用Python深度解读房贷利率文中的解法,设A为本金,第i个月月末所欠银行本金为Ai,每月所还存款总额为X,月利率为β, 则有:

由于最初一期时剩余本金为0,可反解得:

这里m为总期数(在刚刚的例子中,m=240)。尔后就可以使用与等额本金盘算中相似的逻辑,从第一期所还利钱开头,反推每期的利钱与本金。具体代码如下:

def averageCapitalPlusInterest(months, principal, rate):
month_rate = rate / 12
monthly_payment = principal * month_rate * (1 + month_rate) ** months / ((1 + month_rate) ** months - 1)
interests = [0] * months
capitals = [0] * months
left_principal = [0] * months
left_principal[0] = principal
total_payment = [0] * months
for i in range(0, months):
total_payment[i] = monthly_payment
interests[i] = left_principal[i] * month_rate
capitals[i] = total_payment[i] - interests[i]
if i + 1 < months:
left_principal[i + 1] = left_principal[i] - capitals[i]
return capitals, interests, total_payment

我们运转一下知乎上的例子,看看等额本息形式下第8年四周,毕竟还了几多利钱和本金:

drawTable(12 * 20, averageCapitalPlusInterest, 875000, 0.049)[90:100]

可以看到第96期(第8年年末)时,本金还了25万,但利钱以前还了近30万了,和之前文中例子的数据是可以对得上的。

还款可视化

刚刚我们以前将还款的各项数据以表格的情势打印。别的我们还可以借助python的才能,打印还款的柱状图。

import numpy as np
def printStatistics(capitals, interests, total_payment, months):
print("总本金:" + str(np.sum(capitals)))
print("总利钱:" + str(np.sum(interests)))
print("总利钱/总本金" + str(np.sum(interests)/np.sum(capitals)))
print("首月还款 %.2f 末月还款: %.2f" % (total_payment[0], total_payment[months - 1]))

def drawDiagram(months, fn, *args, **kwargs):
capitals, interests, total_payment = fn(months, *args, **kwargs)
printStatistics(capitals, interests, total_payment, months)
month_array = np.arange(1, months + 1, 1)
height = interests
plt.bar(month_array, capitals, width=0.2, align='center', color='red')
plt.bar(month_array, interests, width=0.2, align='center', color='blue', bottom=capitals)
plt.show()

再跑一下知乎的例子,绘制等额本金和等额本息的还款柱状图:

drawDiagram(12 * 20, averageCapital, 875000, 0.049)

如图,蓝色是所还利钱,赤色是所还本金。可以看出本金每月安定,利钱逐月渐减的特性。

等额本息情况下:

drawDiagram(12 * 20, averageCapitalPlusInterest, 875000, 0.049)

也能看出所画图形和等额本息的涵义基本一律。

别的局部都市可以公积金存款,以杭州为例,现在杭州公积金富裕情况下可贷50w-60w,这里思索一下公积金的情况:

def averageCapitalWithPublicFund(months, principal1, rate1, principal2, rate2):
a, b, c = averageCapital(months, principal1, rate1)
a1, b1, c1 = averageCapital(months, principal2, rate2)
return np.sum([a,a1],axis=0).tolist(), np.sum([b,b1],axis=0).tolist(), np.sum([c,c1],axis=0).tolist()

drawTable(12 * 20, averageCapitalWithPublicFund, 700000, 0.041, 300000, 0.031)[0:10]

这里算了下商贷70w(利率4.1%),公积金贷30w(利率3.1%)下组合存款的情况,和微信小步骤房小团的盘算是一律的。

事先还款干系原理

再来讨论下事先还款。假如知乎文中买房的那位,在存款1年后事先还款10w会怎样呢?了解一点背景知识的伙伴,都知晓事先还款分两种情况:

  • 年限安定,月供变小
  • 年限延长,月供安定

如今分情况讨论,并给出盘算函数。

注:notebook中一切盘算后果均在微信房小团小步骤上取得互相验证。

年限安定,月供变小

这种情况下,相当于在事先还款月之后重新做了一次存款。我们起首对刚刚的盘算函数举行一定的简化,笼一致下公用的局部。

def normalPaid(months, principal, rate, capitalAveraged):
month_rate = rate / 12
monthly_capital = principal / months
monthly_payment = principal * month_rate * (1 + month_rate) ** months / ((1 + month_rate) ** months - 1)
interests = [0] * months
capitals = [0] * months
left_principal = [0] * months
left_principal[0] = principal
total_payment = [0] * months
for i in range(0, months):
interests[i] = left_principal[i] * month_rate
if capitalAveraged:
capitals[i] = monthly_capital
total_payment[i] = monthly_capital + interests[i]
else:
total_payment[i] = monthly_payment
capitals[i] = total_payment[i] - interests[i]
if i + 1 < months:
left_principal[i + 1] = left_principal[i] - capitals[i]
return capitals, interests, total_payment

drawTable(12 * 20, normalPaid, 875000, 0.049, False)[10:14]

drawTable(12 * 20, normalPaid, 875000, 0.049, True)[10:14]

可以看到笼统出公用布局后,前后的盘算后果并没有产生厘革。

思索年限安定事先还款的情况,这里将每次事先还款的时间和金额构成python的元组,多少个(账期,还款金额)元组构成一个list输入函数。函数起首盘算正常情况下的还款信息,尔后依据事先还款信息,修要事先还款日的剩余本金,并从各个事先还款日重新盘算剩余还款。

def extraPaidWithFixedPeriod(months, principal, rate, capitalAveraged, extraPaidList :list):
capitals, interests, total_payment = normalPaid(months, principal, rate, capitalAveraged)
extraPaidList.sort(key=lambda x:x[0])
originCapital, originInterests, originTotal = capitals.copy(), interests.copy(), total_payment.copy()
left_principal = [0] * months
left_principal[0] = principal
for x in range(0,months):
if x < months - 1:
left_principal[x + 1] = left_principal[x] - capitals[x]
def normalPaidOffset(left_months, principal, rate, capitalAveraged, offset):
month_rate = rate / 12
monthly_capital = left_principal[offset] / left_months
monthly_payment = left_principal[offset] * month_rate * (1 + month_rate) ** left_months / ((1 + month_rate) ** left_months - 1)
for i in range(0, left_months):
interests[offset + i] = left_principal[offset + i] * month_rate
if capitalAveraged:
capitals[offset + i] = monthly_capital
total_payment[offset + i] = monthly_capital + interests[offset + i]
else:
total_payment[offset + i] = monthly_payment
capitals[offset + i] = total_payment[offset + i] - interests[offset + i]
if i == 0:
print("次月还款 %.2f" % total_payment[offset + i])
if offset + i + 1 < months:
left_principal[offset + i + 1] = left_principal[offset + i] - capitals[offset + i]
return
for x,y in extraPaidList:
capitals[x] = capitals[x] + y
left_principal[x + 1] = left_principal[x] - capitals[x]
total_payment[x] = capitals[x] + interests[x]
print("当月需还 %.f 剩余本金 %.f" %(total_payment[x], left_principal[x + 1]))
normalPaidOffset(months - x - 1, left_principal[x + 1], rate, capitalAveraged, x + 1)
printStatistics(originCapital, originInterests, originTotal, months)
print("")
printStatistics(capitals, interests, total_payment, months)
print("节流利钱 %.2f" % (np.sum(originInterests) - np.sum(interests)))
return capitals, interests, total_payment, originTotal, originInterests

再界说几个函数对事先还款节流的利钱举行可视化。

def drawDiagramExtraPaid(months, capitals, interests, originalTotal, originalInterests, showOriginTotal=True):
month_array = np.arange(1, months + 1, 1)
capital_with_origin_interest = [0] * months
height = interests
for x in range(1, months):
capital_with_origin_interest[x] = capitals[x] + originalInterests[x]
l1 = plt.bar(month_array, originalTotal if showOriginTotal else capital_with_origin_interest, width=0.2, align='center', color='yellow')
l2 = plt.bar(month_array, capitals, width=0.2, align='center', color='red')
l3 = plt.bar(month_array, interests, width=0.2, align='center', color='blue', bottom=capitals)
# plt.legend(handles = [l1, l2,l3], labels = ['每月少还' if showOriginTotal else '节流利钱', '本金','利钱'], loc = 'best',fontsize=20)
plt.ylim(0, (capitals[0]+interests[0])*1.1)
plt.show()

def drawTableExtraPaid(months, capitals, interests, total_payment, originalTotal, originalInterests):
paid_capital = [0] * months
paid_interests = [0] * months
saved_money = [0] * months
paid_capital[0] = capitals[0]
paid_interests[0] = interests[0]
for x in range(1, months):
paid_capital[x] = paid_capital[x - 1] + capitals[x]
paid_interests[x] = paid_interests[x - 1] + interests[x]
saved_money[x] = saved_money[x - 1] + (originalInterests[x] - interests[x] )
origin = pd.DataFrame([total_payment, capitals, interests, paid_capital, paid_interests,saved_money])
return pd.DataFrame(origin.values.T, columns=['还款额','还款本金','还款利钱','已还本金','已还利钱','累计节流'], index=np.arange(1, months + 1))

经过参数showOriginTotal的取值,可以分散绘制每月少还的钱与当月节流利钱的情况。底下分散绘制了等额本金和等额本息情况下,87.5万贷20年,在第一年还10万后还款和利钱的厘革情况。

a, b, c, d, e = extraPaidWithFixedPeriod(12 * 20, 875000, 0.049, True, [(13,100000)])
drawDiagramExtraPaid(12 * 20, a, b, d, e)
drawDiagramExtraPaid(12 * 20, a, b, d, e, False)
drawTableExtraPaid(12 * 20, a, b, c, d, e)[10:20]

a, b, c, d, e = extraPaidWithFixedPeriod(12 * 20, 875000, 0.049, False, [(13,100000)])
drawDiagramExtraPaid(12 * 20, a, b, d, e)
drawDiagramExtraPaid(12 * 20, a, b, d, e, False)
drawTableExtraPaid(12 * 20, a, b, c, d, e)[10:20]

可以很便利地看出节流利钱在每个月还款额中的比重。

月供安定,年限延长

这种情况下事先还款招致后续每个月产生的利钱少了,但是月供没变,相当于后续每个月分外多还了本金。但是在各种事先还款盘算器的盘算中,月供并不是和之前相反的,颠末反复的盘算后和网上的存款盘算器后果终极一律,发觉各种事先还款盘算器隐含了下列束缚:

  • 事先还款相当于用剩余本金新做一个存款。
  • “月供”不是真的安定。而是经过延常年限办法,使得新存款首月月供尽约莫和如今月供相当。
  • 假如是等额本金形式,新存款首月月供中,奉还本金并未增多,必要略低于上月奉还本金,等额本息形式则无此束缚。

想想这个逻辑也有真理,假如真的“月供安定”,那么等额本金形式下事先还款后,后续每个月奉还的本金都市比新做存款的奉还的本金多,相当于后续每个月都在事先还款,后续每个月月供本金就不克不及称为“等额”了。
我们底下先写个求解首月月供的函数,以及经过延常年限迫近上月月供总额和月供本金的函数。尔后盘算“月供安定,年限延长”形式下节流的具体利钱。

def getFirstPaid(months, principal, rate, capitalAveraged):
month_rate = rate / 12
monthly_capital = principal / months
monthly_payment = principal * month_rate * (1 + month_rate) ** months / ((1 + month_rate) ** months - 1)
interests1 = principal * month_rate
if capitalAveraged:
return monthly_capital + interests1, monthly_capital
else:
return monthly_payment, monthly_payment - interests1

def getLeftMonths(leftMonthsMax, capitalPaidMax, paidMax, leftPrincipal, rate, capitalAveraged):
lastPaid, lastCapitalPaid, lastMonths = 0, 0, 0
for i in range(leftMonthsMax, 1, -1):
paid, capitalPaid = getFirstPaid(i, leftPrincipal, rate, capitalAveraged)
if paid > paidMax or (capitalAveraged and capitalPaid > capitalPaidMax):
return lastMonths, lastPaid, lastCapitalPaid
else:
lastPaid, lastCapitalPaid, lastMonths = paid, capitalPaid, i

def extraPaidWithFixedPaid(months, principal, rate,
capitalAveraged, extraPaidList: list):
capitals, interests, total_payment = normalPaid(
months, principal, rate, capitalAveraged)
extraPaidList.sort(key=lambda x: x[0])
originCapital, originInterests, originTotal = capitals.copy(), interests.copy(), total_payment.copy()
left_principal = [0] * months
left_principal[0] = principal
for x in range(0, months):
if x < months - 1:
left_principal[x + 1] = left_principal[x] - capitals[x]

def normalPaidOffset(left_months, principal, rate,
capitalAveraged, offset, left_months2):
month_rate = rate / 12
monthly_capital = left_principal[offset] / left_months
monthly_payment = left_principal[offset] * month_rate * (1 + month_rate) ** left_months / ((1 + month_rate) ** left_months - 1)
for i in range(0, left_months):
interests[offset + i] = left_principal[offset + i] * month_rate
if capitalAveraged:
capitals[offset + i] = monthly_capital
total_payment[offset + i] = monthly_capital + interests[offset + i]
else:
total_payment[offset + i] = monthly_payment
capitals[offset + i] = total_payment[offset + i] - interests[offset + i]
if i == 0:
print("次月还款 %.2f" % total_payment[offset + i])
if offset + i + 1 < months:
left_principal[offset + i + 1] = left_principal[offset + i] - capitals[offset + i]
for i in range(left_months, left_months2):
interests[offset + i] = 0
capitals[offset + i] = 0
total_payment[offset + i] = 0
return
realMonth = months
for x, y in extraPaidList:
capitalParam = capitals[x]
capitals[x] = capitals[x] + y
left_principal[x + 1] = left_principal[x] - capitals[x]
total_payment[x] = capitals[x] + interests[x]
maxMonth, maxPaid, maxPaidCapital = getLeftMonths(months - x - 1, capitalParam, total_payment[x - 1], left_principal[x + 1], rate, capitalAveraged)
normalPaidOffset(maxMonth, left_principal[x + 1], rate, capitalAveraged, x + 1, months - x - 1)
realMonth = x + 1 + maxMonth
print("当月需还 %.2f 剩余本金 %.2f 下月需还:%.2f 原本剩余账期:%d,如今剩余账期:%d, 账期延长:%d" %(total_payment[x], left_principal[x + 1],total_payment[x + 1], months - x - 1,maxMonth, months - x - 1 - maxMonth))
printStatistics(originCapital, originInterests, originTotal, months)
print("")
printStatistics(capitals, interests, total_payment, realMonth)
print("节流利钱 %.2f" % (np.sum(originInterests) - np.sum(interests)))
return capitals, interests, total_payment, originTotal, originInterests

a, b, c, d, e = extraPaidWithFixedPaid(12 * 20, 875000, 0.049, True, [(13, 100000)])
drawDiagramExtraPaid(12 * 20, a, b, d, e)
drawTableExtraPaid(12 * 20, a, b, c, d, e)[10:20]

a, b, c, d, e = extraPaidWithFixedPaid(12 * 20, 875000, 0.049, False, [(13, 100000)])
drawDiagramExtraPaid(12 * 20, a, b, d, e)
drawTableExtraPaid(12 * 20, a, b, c, d, e)[10:20]

可以看出,固然延常年限的实质也是重新做一次存款,但的确可以节流很多利钱。

小结

本文初稿写于华为云AI-Gallery存款盘算器-从原理、公式到事先还款和可视化,经过页面进入CodeLab可以直接在界面上调停参数举行房贷利钱、事先还款等干系盘算,盘算历程原理直观,共同可视化便利了解,接待开发者前去体验。

整篇文章带各位了解了不同房贷存款办法的差别,以及对房贷利钱盘算、事先还款的原理做了较为过细的分析和数据可视化。后续在面临存款利钱盘算的成绩时,可以直面原理、胸有定见、临危不慌。

参考材料

[1]用Python深度解读房贷利率(
https://mp.weixin.qq.com/s/hdRb4b7ufYd-hujV1TKHZg)

[2]为什么买房存款,最好选择等额本金?

[3]杭州房小团微信小步骤-存款盘算

[4]杭州房小团微信小步骤-事先还款

点击下方,第一时间了解华为云新颖武艺~

华为云博客_大数据博客_AI博客_云盘算博客_开发者中央-华为云

#华为云开发者同盟#

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享