贷款计算器通常回答的是:借一笔钱,每月要还多少?
但用户经常需要反过来问:每月最多能拿出多少钱还款,在这个前提下,贷款额度大约是多少?
这个问题不能只用“月收入乘一个倍数”回答。已有负债会占用还款空间,生活支出也会限制可用现金。只有先确定月供上限,才能根据利率和期限反推本金。
本文以贷款能力计算器为例,拆解这一反向计算模型。以下结果是按输入条件进行的现金流试算,不代表贷款机构的审批额度。
第一步:把收入换成月供上限
假设输入包括:
- 家庭税后月收入
income - 固定生活支出
expenses - 其他每月负债
otherDebt - 测算负债比例
ratio
先算负债比例约束下,还能承受多少新月供:
[
available =
\max(0,\ income \times ratio - otherDebt)
]
例如税后月收入 2 万元,测算比例为 40%,已有月供等负债 1000 元:
[
20000 \times 40\% - 1000 = 7000\text{ 元}
]
这里的 40% 是用户选择的测算参数,不是通用审批标准。
但只看这个约束还不够。假如每月生活支出很高,即使负债比例允许 7000 元,也未必有足够现金支付。
因此再计算生活支出之后的月度结余:
[
surplus =
\max(0,\ income - expenses - otherDebt)
]
最终取两个上限中较小的一个:
[
paymentLimit = \min(available,\ surplus)
]
对应代码:
function paymentLimit(
income: number,
expenses: number,
otherDebt: number,
ratio: number, // 小数:40% 传入 0.4
) {
const byDebtRatio = Math.max(0, income * ratio - otherDebt);
const byCashFlow = Math.max(
0,
income - expenses - otherDebt,
);
return Math.min(byDebtRatio, byCashFlow);
}
otherDebt 在两个约束里都出现,并不是重复扣款:一个检查总债务占收入的比例,另一个检查支付生活支出和已有负债后还剩多少现金。最后取较小值。
第二步:从月供反推贷款本金
以等额本息为例,设:
- 贷款本金为
P - 月利率为
r - 总期数为
n - 每期月供为
A
月供公式为:
[
A =
\frac{P \times r \times (1+r)^n}
{(1+r)^n - 1}
]
把 P 移到左边,就能从月供反推本金:
[
P =
\frac{A \times ((1+r)^n - 1)}
{r \times (1+r)^n}
]
写成代码:
function principalFromPayment(
payment: number,
annualRate: number,
months: number,
) {
if (
!Number.isFinite(payment) ||
!Number.isFinite(annualRate) ||
!Number.isInteger(months) ||
payment < 0 ||
annualRate < 0 ||
months <= 0
) {
throw new Error("输入不合法");
}
const monthlyRate = annualRate / 12;
if (monthlyRate === 0) {
return payment * months;
}
// 与等额本息反推公式等价;小利率下可减少精度损失。
const denominator = -Math.expm1(
-months * Math.log1p(monthlyRate),
);
return payment * denominator / monthlyRate;
}
当利率为 0 时,贷款本金就是每月还款额乘期数。这个分支不能省,否则公式会出现除零。
这里假设贷款按月等额本息偿还、利率在整个试算期内保持不变。等额本金、先息后本和包含尾款的贷款,不能直接使用这一反推公式。
用一组数据验算
假设用户输入:
| 项目 | 数值 |
|---|---|
| 家庭税后月收入 | 20,000 元 |
| 固定生活支出 | 8,000 元 |
| 其他每月负债 | 1,000 元 |
| 测算负债比例 | 40% |
| 贷款年利率 | 4% |
| 贷款期限 | 20 年 |
负债比例约束:
[
20000 \times 40\% - 1000 = 7000\text{ 元}
]
现金流约束:
[
20000 - 8000 - 1000 = 11000\text{ 元}
]
因此,可用于新贷款月供的上限取较小值,为 7000 元。
将 7000 元、年利率 4%、240 期代入等额本息反推公式,得到的贷款本金约为 1,155,153 元。
支付新月供后,按上述固定支出口径,月度剩余资金为:
[
11000 - 7000 = 4000\text{ 元}
]
计算器给出的额度是模型结果。银行还会根据征信、收入稳定性、负债情况、担保条件及产品规则等进行审核。
用正向计算检查反推结果
反向公式写完后,最好用正向月供公式做一次回代。比如反推出 1,155,153 元,再以 4%、240 期计算月供,结果应接近 7000 元。
function annuityPayment(
principal: number,
annualRate: number,
months: number,
) {
const rate = annualRate / 12;
if (rate === 0) return principal / months;
const denominator = -Math.expm1(
-months * Math.log1p(rate),
);
return principal * rate / denominator;
}
const principal = principalFromPayment(7000, 0.04, 240);
const payment = annuityPayment(principal, 0.04, 240);
console.log(principal.toFixed(2)); // 1155153.01
console.log(payment.toFixed(2)); // 7000.00
回代测试比只检查一个固定答案更有用:它能发现年利率没有除以 12、期限单位混淆等问题。
哪个约束生效,应在结果中说明
同一套输入,可能由不同约束决定月供上限。
例如月收入仍为 2 万元,但固定生活支出提高到 1.5 万元,其他负债仍为 1000 元:
- 负债比例约束允许的新月供:7000 元;
- 现金流约束允许的新月供:4000 元。
此时应使用 4000 元反推额度。页面如果能同时展示两个上限,用户就能看出到底是负债比例还是实际月度结余限制了结果。
const bindingConstraint =
byDebtRatio <= byCashFlow
? "负债比例"
: "月度结余";
若两者相等,两项约束同时生效;实际产品可以单独展示这一情况。
边界条件与测试
几个输入场景需要明确处理:
- 已有月负债超过比例上限:新月供空间按 0 处理。
- 生活支出和已有负债超过收入:月度结余按 0 处理,不输出负贷款额度。
- 期限为 0 或非整数期:拒绝计算。
- 零利率:本金等于月供乘期数。
- 非数值、负收入或负支出:提示用户修正输入。
测试不必只检查“结果大于 0”。下面几项能覆盖模型的关键关系:
import assert from "node:assert/strict";
import test from "node:test";
test("两个约束取较小值", () => {
assert.equal(paymentLimit(20_000, 15_000, 1_000, 0.4), 4_000);
});
test("已有负债超过比例上限时,新月供空间为零", () => {
assert.equal(paymentLimit(10_000, 3_000, 5_000, 0.4), 0);
});
test("零利率时,本金等于月供乘期数", () => {
assert.equal(principalFromPayment(5_000, 0, 12), 60_000);
});
test("反推本金代回月供公式", () => {
const principal = principalFromPayment(7_000, 0.04, 240);
const payment = annuityPayment(principal, 0.04, 240);
assert.ok(Math.abs(payment - 7_000) < 0.01);
});
test("月供和期限不变时,利率上升会降低可反推本金", () => {
const lowerRate = principalFromPayment(7_000, 0.03, 240);
const higherRate = principalFromPayment(7_000, 0.05, 240);
assert.ok(higherRate < lowerRate);
});
这个模型最值得展示的结果,其实不只是一个贷款额度:月供上限是由什么约束决定的,贷款期限和利率变化后额度如何变化,都会影响用户对结果的理解。把这些条件留在结果旁边,比给出一个孤立的“可贷金额”更容易核对。