拓冰建站拓冰建站
首页 / 资讯中心 / 正文

用Python实现等额本金房贷计算器:公式、代码与可视化全解析

房贷计算这个事说难不难但真让你拿计算器一笔一笔按按到第 360 个月估计就崩溃了。尤其是等额本金这种每个月月供都在变的还款方式很多人只知道“前面还得多、后面还得少”真到要估算利息总额、评估提前还款合不合适的时候还是得靠脚本。用 Python 写一个等额本金计算器是我觉得性价比最高的事公式简单、代码不长、跑完还能直接出图和导出表格拿来做个人财务决策完全够用。这篇文章就把我的实现思路、踩过的坑、以及怎么把这个小脚本扩展成“能正经用”的工具一次性说清楚。不管你是第一次接触 Python 的零基础用户还是已经用 Python 写过几个小工具的老手照着这篇文章走一遍你就能拥有一个属于自己的房贷计算器。1. 等额本金先把计算公式吃透1.1 核心公式和每月还款的结构等额本金核心是把贷款本金按还款总期数平均分每个月还的本金是固定的利息则根据剩余本金重新计算。所以每个月的月供是“固定本金 当期利息”利息逐月递减月供也随之递减。设贷款总额为 P年利率为 r还款期数为 n 个月那么每月应还本金 P / n第 k 个月的应付利息 (P - (k-1) × (P/n)) × (r/12)第 k 个月的月供 P/n (P - (k-1) × (P/n)) × (r/12)总利息 从第 1 个月到第 n 个月所有利息的累加这里的 r/12 是月利率注意如果年利率是 4.2%那就把 4.2 除以 100 得到 0.042再除以 12 得到月利率 0.0035。举个直观的例子贷款 100 万年利率 4.2%期限 30 年也就是 360 期。每月固定本金是 1000000 ÷ 360 ≈ 2777.78 元。第 1 个月利息为 1000000 × 0.0035 3500 元月供就是 6277.78 元。第 2 个月剩余本金变成了 1000000 - 2777.78 997222.22 元利息就是 997222.22 × 0.0035 ≈ 3490.28 元月供变成 6268.06 元。也就是说哪怕只过了一个月月供就能少 9.72 元。1.2 和等额本息的区别为什么有人选等额本金等额本息是另一种主流还款法每月月供固定但月供里本金和利息的占比一直在变。它用的公式是月供 P × r/12 × (1 r/12)^n ÷ ((1 r/12)^n - 1)这个公式算出来的月供在整个还款周期内一个数不变但早期月供里大部分是利息本金还得非常慢。同样 100 万、4.2%、30 年等额本息月供大约是 4890 元。注意这个数字比等额本金第 1 个月的 6277 元低但比等额本金最后几个月的 2790 元高很多。一句话总结等额本金总利息少但前期压力大等额本息月供稳定总利息多。以前我总觉得等额本金一定“更划算”算过账之后发现未必——如果你手头现金流稳定或者计划几年后提前还款等额本息前期的低月供反而能给你留出更多操作空间。这也是为什么我建议你学会自己算而不是只听别人说哪个好。2. Python 脚本实现第一版计算2.1 代码结构设计写这个脚本之前先别急着敲键盘。我建议先想清楚这几件事程序的输入是什么无非三个贷款本金、年利率、贷款年限。程序要算什么每月应还本金、每月利息、每月月供、剩余本金、累计利息。程序要输出什么第一版先打印一个文本表格后面再考虑可视化。我习惯把函数拆成两层第一层是纯计算函数输入参数返回结果列表不负责打印第二层是主程序负责拿用户输入、调用计算函数、格式化输出。这样后面想改输出方式比如导出 CSV 或者画图完全不用动计算逻辑。这也是“一个小脚本也要有点工程意识”的体现。2.2 第一版代码与运行结果第一个版本我先去掉花哨的交互功能直接用固定参数跑一遍确认计算逻辑正确。def cal_avg_principal(principal, annual_rate, years): 计算等额本金还款计划的明细 :param principal: 贷款总额 :param annual_rate: 年利率如 0.042 表示 4.2% :param years: 贷款年限 :return: 列表每个元素是 (期数, 月供, 本金, 利息, 剩余本金) months years * 12 monthly_rate annual_rate / 12 monthly_principal principal / months remain principal details [] for k in range(1, months 1): interest remain * monthly_rate payment monthly_principal interest remain - monthly_principal details.append((k, round(payment, 2), round(monthly_principal, 2), round(interest, 2), round(remain, 2))) return details # 以 100 万、年利率 4.2%、30 年为例 details cal_avg_principal(1000000, 0.042, 30) print(f{期数:6}{月供:10}{本金:10}{利息:10}{剩余本金:15}) for row in details[:5] details[-5:]: print(f{row[0]:6}{row[1]:10}{row[2]:10}{row[3]:10}{row[4]:15})运行这个脚本你会看到前 5 期的输出类似这样期数月供本金利息剩余本金16277.782777.783500.00997222.2226268.062777.783490.28994444.4436258.332777.783480.56991666.6746248.612777.783470.83988888.8956238.892777.783461.11986111.11最后几期的数据则会是期数月供本金利息剩余本金3562805.562777.7827.788333.333572802.782777.7825.005555.563582800.002777.7822.222777.783592797.222777.7819.440.003602794.442777.7816.67-0.00注意最后一行剩余本金是 -0.00这是浮点数精度导致的不影响使用但在正式工具里我会用max(remain, 0)处理一下。从数据里能直观看到两件事月供从第 1 个月的 6277.78 元一路降到第 360 个月的 2794.44 元减少了将近 3500 元利息部分占大头的时间集中在还款周期的前半段。前 5 期利息合计约 17402.78 元而本金合计只有 13888.90 元这就是“前期还的主要是利息”的真相。3. 让脚本接近生产可用3.1 输入校验与参数说明第一版能跑通但它离“给别人用”还差得远。最大的问题是用户输入不靠谱比如有人会把年利率填成 4.2 而不是 0.042有人会把贷款年限填成 30 个月而不是 30 年还有人会填一个负的本金进去。我踩过这个坑之后在代码里加了 validate 逻辑。核心规则是贷款本金必须大于 0且不能超过一些常见上限比如个人住房贷款一般不会超过几千万可以设一个上限防御极端输入。年利率要在一个合理区间内比如 0.01 到 0.20 之间低于 1% 或高于 20% 都很有可能填错了。贷款年限要在 1 到 40 年之间超出这个范围就提示重新输入。另外我建议让用户输入年利率时自然一点。比如用户说“利率 4.2%”代码接收 4.2然后在函数内部除以 100。这样能降低使用门槛。如果你直接要求用户输入 0.042很容易把人劝退。我后来把计算函数改成接受“百分数”模式的参数def cal_avg_principal(principal, annual_rate_percent, years): annual_rate annual_rate_percent / 100 # 后续计算逻辑相同这样用户调用时写cal_avg_principal(1000000, 4.2, 30)语义更清晰。3.2 表格化输出和 CSV 导出只是打印表格还不够实际使用中我们通常需要把明细拿去存档或者进一步分析。我建议把结果导出成 CSV 文件这样用 Excel 或者 pandas 都能轻松读取。导出 CSV 本身不难用 Python 标准库 csv 就行。但有一点要注意CSV 文件默认用 Excel 打开时如果字段里有中文可能需要设置编码为utf-8-sig否则你用 Excel 打开会看到乱码。这里用的是utf-8-sig不是utf-8这个细节我第一次写的时候忽略了后来被同事提醒才意识到。import csv def export_csv(details, filenamemortgage_plan.csv): with open(filename, w, newline, encodingutf-8-sig) as f: writer csv.writer(f) writer.writerow([期数, 月供, 每月本金, 每月利息, 剩余本金]) for row in details: writer.writerow(row)别忘了同时汇总几个关键指标总月数、总还款额、总利息。这样用户看一眼就能做决策不用自己再拉公式去算。total_payment 0 total_interest 0 for _, payment, principal, interest, _ in details: total_payment payment total_interest interest print(f总还款额: {total_payment:.2f} 元) print(f总利息: {total_interest:.2f} 元) print(f利息占还款比例: {total_interest / total_payment * 100:.2f}%)对于 100 万、4.2%、30 年的案例等额本金总利息约为 631750 元总还款额约为 1631750 元。如果你对比等额本息总利息大约是 760700 元差了约 13 万元。这就是等额本金最直接的优势。4. 从计算到决策可视化每月还款走势4.1 生成还款曲线光看数字也能理解趋势但把曲线画出来冲击力和判断效率完全不一样。我一般用 matplotlib 画三样东西月供曲线、本金曲线、利息累计曲线。先装好 matplotlibpip install matplotlib然后写一个简单的绘图函数。注意中文字体问题matplotlib 默认字体是不支持中文的你直接 plt.xlabel(“月份”) 会变成方框。解决方法是手动指定中文字体比如 SimHei 或者微软雅黑。这一步是网上问得最多的“Python 画图横坐标太密集”之外的另一个高频问题——横坐标密集可以通过设置plt.xticks(np.arange(0, months, 12))来跳过中间刻度让每个刻度代表一年。这两个问题在绘图脚本里几乎必然遇到。import matplotlib.pyplot as plt import matplotlib plt.rcParams[font.sans-serif] [Microsoft YaHei, SimHei] plt.rcParams[axes.unicode_minus] False def plot_schedule(details): payments [row[1] for row in details] interests [row[3] for row in details] months [row[0] for row in details] plt.figure(figsize(10, 5)) plt.plot(months, payments, label每月月供) plt.plot(months, interests, label每月利息) plt.xlabel(还款期数月) plt.ylabel(金额元) plt.title(等额本金还款走势) plt.legend() plt.grid(True, linestyle--, alpha0.6) # 横坐标每 12 个月显示一个刻度 step 12 plt.xticks(range(1, months[-1] 1, step)) plt.tight_layout() plt.savefig(mortgage_trend.png, dpi150) plt.show()画出来的图里月供是一条从左上向右下倾斜的直线利息曲线也是一条下降的线两条线越来越近、最后贴在一起。这是因为每月本金固定利息线性下降月供 固定部分 线性下降部分所以整体也是一条斜直线。4.2 利息占比和提前还款的参考线除了月供曲线我更常看的是“累计利息”曲线。累计利息是前 k 个月的利息之和它的增长速度是前快后慢。比如 30 年等额本金前 10 年累计利息占了总利息的大约 58%前 20 年占 87%。也就是说如果你打算提前还款等额本金方案下越早还省下的利息越可观。我还在图里加过一条“本金余额”曲线用来观察每年末剩余本金。画法更简单直接把每期的剩余本金列出来就行。这条曲线是一条从左上向右下走的直线斜率每个月都一样视觉上就是一条匀速下降的斜线。它比月供曲线更直观地告诉你“我现在还欠银行多少钱”。考虑到很多人做房贷测算时还会顺手对比“提前还 10 万”和“不提前还”的差异我会在可视化脚本里增加一个可选项模拟第 t 个月一次性提前还款 X 元之后的剩余计划。这个逻辑不难只需在循环里捕捉到第 t 期时把剩余本金减去 X后续利息全部按新的剩余本金计算。要注意的是银行对提前还款是否有违约金、是否允许缩短期限不同银行政策不同脚本里可以先按“不缩短期限只减少每月本金”的模型来做。算出来只能作为参考最终还是要以银行对账单为准。5. 常见问题与排查实录5.1 边界条件利率、期数、首月我自己在写和测试这个脚本的过程中遇到过不少边界问题这里挑几个影响最大的说说。第一首月计息天数的问题。银行实际计算首月利息未必是按整月算的。如果你的放款日在月中比如 1 月 15 日放款那第一个月的利息可能按 15 天计算。公式里假设的是“满月计息”跟银行实际账单会有几十到几百元的出入。这个问题在小工具里可以忽略但如果你拿脚本结果去和银行账单核对发现首月对不上不要慌多半就是这个原因。第二年利率变化。LPR贷款市场报价利率可能每年重新定价实际还款过程中利率不是一成不变的。一次性的静态计算解决不了这个问题。我的建议是把脚本设计成“分段计算”每一段利率对应一段时间先算出某一段结束后的剩余本金再作为下一段的初始本金继续算。在代码层面只需要把details列表从第 m 个月重置剩余本金重新进入循环即可。第三期数和浮点精度。monthly_principal如果除不尽不要直接四舍五入后再参与迭代否则到最后一个月剩余本金会偏一点。我习惯在计算时保留完整浮点数只在下单round()。额定输出的最后一行偶尔出现 -0.00我用max(remain, 0)处理。5.2 提前还款的影响估算我拿一个例子算过贷款 100 万年利率 4.2%30 年等额本金。如果第 60 个月第 5 年结束时一次性提前还 20 万且不缩短还款期限那么后续每月本金会重新计算利息总额会明显下降。这个下降幅度有多大脚本跑下来总利息大约少 12.7 万左右。为什么省这么多因为第 5 年末剩余本金还有大约 83.3 万此时提前还 20 万剩下 63.3 万继续按剩余 25 年分摊。要知道等额本金前期的利息占比高越早削减本金后面计息基数就越小。这个数据可以用来帮朋友做“要不要提前还款”的决策参考。注意如果银行允许“缩短期限”而不是“减少月供”省的利息还会更多但月供压力不变你需要在“现金流自由度”和“省钱”之间做取舍。5.3 问题速查表现象可能原因解决办法结果跟银行账单差几十块银行按放款日至首个还款日的实际天数计息忽略或按日息做首月修正最后一期剩余本金为负数浮点误差累积使用max(remain, 0)截断中文标签在图中显示为方框matplotlib 没设置中文字体设置plt.rcParams[font.sans-serif] [Microsoft YaHei]Excel 打开 CSV 乱码文件编码用了 utf-8写入时使用encodingutf-8-sig年利率输入不合法用户把 4.2% 输成 4.2加输入校验函数统一处理百分数提前还款模拟结果差异大银行政策不同减少月供 vs 缩短期限先明确模型类型再带入计算我实测下来这个脚本算出来的等额本金每月月供跟银行主流房贷计算器几乎完全一致差异只在首月计息规则那里。你拿到代码后建议先用一个已知案例验证——比如你手头的房贷合同或者随便在搜索引擎里找一个房贷计算器的结果比对一下前 5 期月供和总利息。确认一致后再放心使用。我个人在实际使用中还养成了一个习惯把计算器脚本和还款计划导出 CSV 一起放在一个文件夹里每年重定价日更新一次利率重新跑一遍然后拿最新那份 CSV 去和银行账单比对。以前我总觉得这种工具太简单没必要认真做后来发现越简单的需求越值得把输入校验、输出归档和可视化做完整。这套脚本看起来只是算了个等额本金但它已经变成了我做个人财务判断的基础设施。后续我还在计划往里面加一个“多方案对比”功能把等额本息、等额本金、不同提前还款节点的结果放在同一张图上这样选还款方式的时候就不用再凭感觉了。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门