贷款怎么还最划算,先说答案:越早越划算
很多人没有研究过房贷怎么算的,就觉得刚开始还的都是利息,到后期利息少了,就没必要提前还了。这是一种错觉,后期还的少的原因是因为你的贷款本金少了,当月的利息多少之和当月的持有本金相关。
等额本息的还款方式是利用的一个数学公式让每个月的还款相同,两者相差不多,本篇以等额本金为例。
等额本金
等额本金从表面来看就是每个月还的本金固定为贷款金额/(贷款年限*12),利率逐月减少,可以说每个月少还的几块钱都是利息的减少。
等额本金的计算公式:月利息 = 贷款利率*当月贷款持有本金 / 12
代码实现
function getMonthlyPayment(moneyRate, totalPrincipal, year) {
// 结果列表
const resultList = [];
// 总月份
const totalMonth = year * 12;
// 剩余持有本金
let tp = totalPrincipal;
// 总利息
let interest = 0;
// 每个月的还款本金
let oneMonthPrincipal = tp / totalMonth;
for (let i = 1; i <= totalMonth; i++) {
// 本月的利息
const curInterest = (tp * moneyRate) / 12;
interest += curInterest;
let curPrincipal = oneMonthPrincipal;
tp -= oneMonthPrincipal;
resultList.push({
期数: i,
贷款剩余本金: Math.round(tp),
已还总利息: Math.round(interest),
本期归还本金: Math.round(curPrincipal),
本期利息: Math.round(curInterest),
});
}
return resultList;
}
提前还款
等额本金的计算逻辑很简单,接下来我们看看提前还款的逻辑,
提前还款会有两种方式:月供不变年限减少和年限不变月供减少,看起来月供不变年限减少这种方式更省利息,其实在提前还款没有违约金的情况下,这两种方式区别不大,对于月供压力大的人最好选择年限不变月供减少降低压力。
也可以用这种方式,提前还剩下几百,每个月就剩几毛钱的贷款 用来抵税。
月供不变年限减少相当于减少的是贷款年限(贷款的时候少贷几年)
年限不变月供减少相当于减少的是贷款金额(贷款的时候少贷几万)
年限不变月供减少 提前还款计算代码实现
- 写一个计算月差的函数,d1和d2都是月份,比如(2024-5)
function subMonth(startDateStr, endDateStr) {
// 将日期字符串解析为日期对象
// 注意:这里我们假设日期的日部分是1,因为我们只关心年和月
const startDate = new Date(
startDateStr.split("-")[0],
startDateStr.split("-")[1] - 1,
1
);
const endDate = new Date(
endDateStr.split("-")[0],
endDateStr.split("-")[1] - 1,
1
);
const yearsDiff = endDate.getFullYear() - startDate.getFullYear();
const monthsDiff =
yearsDiff * 12 + (endDate.getMonth() - startDate.getMonth()) + 1;
return monthsDiff - 1;
}
- 设定提前还款的列表是下面这样的,date是提前还款时间,money是提前还款金额
const prePayList = [
{ date: "2024-9", money: 10000 },
// { date: "2024-10", money: 20000 },
];
- 写一个函数给这个列表添加是第几期,比如如果第一次还款是
2024-5,那么2024-9就是第5期,则添加一个num:5
function addNum(prePayList, firstPayment) {
const list = [...prePayList];
list.forEach((item) => {
const num = subMonth(item.date, firstPayment);
item.num = num + 1;
});
return list;
}
- 核心逻辑
function getMonthlyPayment(
moneyRate,
totalPrincipal,
year,
firstRepayment,
repaymentList
) {
const totalMonth = year * 12;
let tp = totalPrincipal;
const prePayListWithNum = addNum(repaymentList, firstRepayment);
let interest = 0;
const resultList = [];
let oneMonthPrincipal;
oneMonthPrincipal = tp / totalMonth;
for (let i = 1; i <= totalMonth; i++) {
const prePayItem = prePayListWithNum.find((item) => {
return item.num === i;
});
const curInterest = (tp * moneyRate) / 12;
interest += curInterest;
let curPrincipal = oneMonthPrincipal;
tp -= oneMonthPrincipal;
if (prePayItem) {
tp -= prePayItem.money;
oneMonthPrincipal = tp / (totalMonth - i);
}
resultList.push({
期数: i,
贷款剩余本金: Math.round(tp),
已还总利息: Math.round(interest),
本期归还本金: Math.round(curPrincipal),
本期利息: Math.round(curInterest),
提前还款: prePayItem?.money || 0,
本期还款总额: curPrincipal + (prePayItem?.money || 0),
});
}
return resultList;
}
- 测试
const prePayList = [
{ date: "2024-9", money: 10000 },
{ date: "2024-10", money: 20000 },
];
const payment = getMonthlyPayment(0.0345, 600000, 20, "2024-5", prePayList);
// 这个结果应该等于或者趋近于贷款金额
console.log(
payment.reduce((pre, cur) => {
return pre + cur["本期还款总额"];
}, 0)
);
- 如果用的node环境,控制台不方便展示太多,可以写入文件中
require("fs").writeFileSync("payment.json", JSON.stringify(payment, null, 2));
月供不变年限减少 提前还款计算代码实现
- 只需要修改核心代码的这里的逻辑
if (prePayItem) {
tp -= prePayItem.money;
totalMonth = prePayItem.num + Math.ceil(tp / oneMonthPrincipal);
}
- 核心逻辑代码
function getMonthlyPayment(
moneyRate,
totalPrincipal,
year,
firstRepayment,
repaymentList
) {
let totalMonth = year * 12;
let tp = totalPrincipal;
const prePayListWithNum = addNum(repaymentList, firstRepayment);
let interest = 0;
const resultList = [];
let oneMonthPrincipal;
oneMonthPrincipal = tp / totalMonth;
for (let i = 1; i <= totalMonth; i++) {
const prePayItem = prePayListWithNum.find((item) => {
return item.num === i;
});
const curInterest = (tp * moneyRate) / 12;
interest += curInterest;
let curPrincipal = oneMonthPrincipal;
tp -= oneMonthPrincipal;
if (prePayItem) {
tp -= prePayItem.money;
totalMonth = prePayItem.num + Math.ceil(tp / oneMonthPrincipal);
console.log(totalMonth);
}
resultList.push({
期数: i,
贷款剩余本金: Math.round(tp),
已还总利息: Math.round(interest),
本期归还本金: Math.round(curPrincipal),
本期利息: Math.round(curInterest),
提前还款: prePayItem?.money || 0,
本期还款总额: curInterest + curPrincipal + (prePayItem?.money || 0),
提前还款日期: prePayItem?.date || "",
});
}
return resultList;
}
完整代码
function subMonth(startDateStr, endDateStr) {
// 将日期字符串解析为日期对象
// 注意:这里我们假设日期的日部分是1,因为我们只关心年和月
const startDate = new Date(
startDateStr.split("-")[0],
startDateStr.split("-")[1] - 1,
1
);
const endDate = new Date(
endDateStr.split("-")[0],
endDateStr.split("-")[1] - 1,
1
);
const yearsDiff = endDate.getFullYear() - startDate.getFullYear();
const monthsDiff =
yearsDiff * 12 + (endDate.getMonth() - startDate.getMonth()) + 1;
return monthsDiff - 1;
}
function addNum(prePayList, firstPayment) {
const list = [...prePayList];
list.forEach((item) => {
const num = subMonth(item.date, firstPayment);
item.num = num + 1;
});
return list;
}
function getMonthlyPayment(
moneyRate,
totalPrincipal,
year,
firstRepayment,
repaymentList
) {
const totalMonth = year * 12;
let tp = totalPrincipal;
const prePayListWithNum = addNum(repaymentList, firstRepayment);
let interest = 0;
const resultList = [];
let oneMonthPrincipal;
oneMonthPrincipal = tp / totalMonth;
for (let i = 1; i <= totalMonth; i++) {
const prePayItem = prePayListWithNum.find((item) => {
return item.num === i;
});
const curInterest = (tp * moneyRate) / 12;
interest += curInterest;
let curPrincipal = oneMonthPrincipal;
tp -= oneMonthPrincipal;
if (prePayItem) {
tp -= prePayItem.money;
oneMonthPrincipal = tp / (totalMonth - i);
}
resultList.push({
期数: i,
贷款剩余本金: Math.round(tp),
已还总利息: Math.round(interest),
本期归还本金: Math.round(curPrincipal),
本期利息: Math.round(curInterest),
提前还款: prePayItem?.money || 0,
本期还款总额: curPrincipal + (prePayItem?.money || 0),
});
}
return resultList;
}
const prePayList = [
{ date: "2024-9", money: 10000 },
// { date: "2024-10", money: 20000 },
];
const payment = getMonthlyPayment(0.0345, 600000, 20, "2024-5", prePayList);
console.log(
payment.reduce((pre, cur) => {
return pre + cur["本期还款总额"];
}, 0)
);
require("fs").writeFileSync("payment.json", JSON.stringify(payment, null, 2));