组合贷不是计算一个平均利率:两套还款计划如何逐月合并

简介: 组合贷由商贷与公积金贷款构成,二者利率、期限、还款计划独立。不可简单取平均利率计算月供,须分别生成两套还款计划,再逐期加总本金、利息及月供,确保结果精准可复核。

组合贷由两笔独立贷款构成:商业贷款和公积金贷款。它们的本金、利率、放款规则和可能的重定价方式都不相同。

因此,组合贷不能把两笔贷款加总后,套一个“平均利率”算月供。正确做法是分别生成两套还款计划,再把同一期的本金、利息、月供和剩余本金逐项相加。

房贷计算器 采用的就是这个口径。

为什么平均利率不可靠

假设:

  • 商贷本金 P_c,年利率 R_c
  • 公积金贷款本金 P_g,年利率 R_g
  • 贷款期限均为 n 期

很多实现会先算一个加权平均利率:

[
R_{avg} =
\frac{P_c \times R_c + P_g \times R_g}
{P_c + P_g}
]

再把 P_c + P_g 与 R_avg 代进等额本息公式。

这个方法看起来合理,但不是精确计算。

等额本息月供公式中包含幂函数:

[
A =
\frac{P \times r \times (1+r)^n}
{(1+r)^n - 1}
]

利率与本金之间不是线性关系。两个不同利率的还款计划相加,不等于先平均利率,再生成一份计划。期限越长、两种利率差距越大,误差越明显。

正确的数据模型:两笔贷款,两套计划

先定义单笔贷款输入:

type LoanInput = {
   
  principal: number;
  annualRate: number;
  months: number;
  method: "annuity" | "principal";
};

还款计划的每一行都保留本金、利息和余额:

type ScheduleRow = {
   
  period: number;
  payment: number;
  principal: number;
  interest: number;
  balance: number;
};

组合贷不需要另一套复杂公式。它只需要复用单笔贷款的计算器两次:

const commercial = calculateLoan({
   
  principal: commercialAmount * 10_000,
  annualRate: commercialRate / 100,
  months,
  method,
});

const provident = calculateLoan({
   
  principal: providentAmount * 10_000,
  annualRate: providentRate / 100,
  months,
  method,
});

这里的 months 在基础版本中相同。若商贷和公积金贷款期限不同,后面需要按日期或期数补零合并,不能直接按数组下标相加。

逐月合并才是组合贷计算的主体

两份计划生成后,第 i 期组合月供等于两笔贷款第 i 期月供之和:

[
paymenti =
payment
{c,i} + payment_{g,i}
]

同样地:

[
principali =
principal
{c,i} + principal_{g,i}
]

[
interesti =
interest
{c,i} + interest_{g,i}
]

[
balancei =
balance
{c,i} + balance_{g,i}
]

实现可以保持很直接:

const schedule = commercial.schedule.map((row, index) => {
   
  const providentRow = provident.schedule[index];

  return {
   
    period: row.period,
    payment: row.payment + providentRow.payment,
    principal: row.principal + providentRow.principal,
    interest: row.interest + providentRow.interest,
    balance: row.balance + providentRow.balance,
  };
});

这样导出的还款计划可以回答用户真正关心的问题:

  • 第 1 期总共需要准备多少钱;
  • 已还 60 期后还剩多少本金;
  • 某一期利息中,商贷和公积金贷款各占多少;
  • 提前还款时到底该对哪一部分本金操作。

一个可复核的算例

设:

项目 商贷 公积金贷款
本金 70 万元 30 万元
年利率 3.5% 2.6%
期限 30 年 30 年
还款方式 等额本息 等额本息

单独计算后:

指标 商贷 公积金贷款 合并后
首期月供 3143.31 元 1201.02 元 4344.33 元
首期本金 1101.65 元 551.02 元 1652.67 元
首期利息 2041.67 元 650.00 元 2691.67 元
总利息 43.16 万元 13.24 万元 56.40 万元左右

组合后的首期月供不是“100 万元按某个平均利率”的月供,而是 3143.31 元与 1201.02 元相加的结果。

这也是为什么组合贷计算器应保存两套底层计划。只展示一个汇总结果,后续很难支持查余额、提前还款或利率调整。

不同期数时,不能继续按数组下标合并

现实中,商贷和公积金贷款的放款日、还款日或期限可能不同。

例如:

  • 商贷剩余 240 期;
  • 公积金贷款剩余 180 期。

此时第 181 期开始,公积金贷款应视为 0,不是访问不存在的数组项:

const length = Math.max(
  commercial.schedule.length,
  provident.schedule.length,
);

const schedule = Array.from({
    length }, (_, index) => {
   
  const c = commercial.schedule[index];
  const p = provident.schedule[index];

  return {
   
    period: index + 1,
    payment: (c?.payment ?? 0) + (p?.payment ?? 0),
    principal: (c?.principal ?? 0) + (p?.principal ?? 0),
    interest: (c?.interest ?? 0) + (p?.interest ?? 0),
    balance: (c?.balance ?? 0) + (p?.balance ?? 0),
  };
});

这只是按“期数对齐”的简化版本。

如果两笔贷款实际还款日不同,例如一笔每月 5 日扣款,另一笔每月 20 日扣款,最稳妥的模型应以真实还款日期为键生成现金流。否则“第 12 期”只是数组序号,不一定对应同一个自然月的资金压力。

因此,基础工具适合在两部分期限和还款节奏一致时合并;实际放款日、扣款日或期限不一致时,应分开试算,再按实际日期汇总。

等额本金也能用同一套合并逻辑

若两部分都选择等额本金,单笔计划的月供会逐月递减。组合计划不需要改公式,仍然按期相加。

const payment =
  commercialRow.payment +
  providentRow.payment;

区别仅在于每一行的来源数据变了:

  • 等额本息:两部分各自月供固定;
  • 等额本金:两部分各自月供递减;
  • 合并后:总月供遵循两部分月供的叠加结果。

不要因为组合贷存在两种利率,就强制使用等额本息。还款方式是每笔贷款计划的属性,而不是组合公式的一部分。

舍入位置会影响尾差

金额显示需要保留两位小数,但不应该在每一步都拿显示值继续计算。

更稳妥的方式是:

  1. 单笔计划内部保留未舍入金额;
  2. 合并后再对展示字段保留两位小数;
  3. 最后一期用剩余本金兜底归零;
  4. 汇总时优先从内部原始值累计。
const money = (value: number) =>
  Math.round((value + Number.EPSILON) * 100) / 100;

const merged = {
   
  payment: money(c.payment + p.payment),
  principal: money(c.principal + p.principal),
  interest: money(c.interest + p.interest),
  balance: money(c.balance + p.balance),
};

否则可能出现一个让用户困惑的现象:逐期月供合计、本金合计、利息合计之间差几角钱甚至几元。

组合贷计算需要锁住的测试

test("组合首期月供等于两部分首期月供之和", () => {
   
  const commercial = calculateLoan({
   
    principal: 700_000,
    annualRate: 0.035,
    months: 360,
    method: "annuity",
  });

  const provident = calculateLoan({
   
    principal: 300_000,
    annualRate: 0.026,
    months: 360,
    method: "annuity",
  });

  const merged = mergeSchedules(
    commercial.schedule,
    provident.schedule,
  );

  assert.equal(
    merged[0].payment,
    commercial.schedule[0].payment +
      provident.schedule[0].payment,
  );
});

test("组合计划的最终剩余本金为零", () => {
   
  const merged = mergeSchedules(
    commercialSchedule,
    providentSchedule,
  );

  assert.equal(merged.at(-1).balance, 0);
});

test("期限不一致时,已结清部分不再产生月供", () => {
   
  const merged = mergeSchedules(
    scheduleWith240Months,
    scheduleWith180Months,
  );

  assert.equal(merged[200].payment, scheduleWith240Months[200].payment);
});

组合贷的正确实现并不在于找到一个“平均利率”。商贷和公积金贷款各自算清楚,再逐月合并,才能让月供、利息、剩余本金和后续操作都经得起核对。

相关文章
|
1天前
|
人工智能 弹性计算 数据库
2026年阿里云双十一大促活动内容详解,新老用户、企业采购优惠与服务器AI产品全梳理
综合来看,2026阿里云双十一大促兼顾入门用户的低价试错需求,也满足企业长期稳定上云、AI业务落地的算力采购需求,优惠分层清晰,从几十元的入门服务器到高端GPU算力套餐都有覆盖。在下单之前,先用阿里云CLI清点存量资源,区分新购、续费、升配需求,领取对应代金券,再结合业务周期选择合约时长,同时合理利用百炼免费额度测试模型接口,能够最大化利用本次大促权益,有效降低云上业务的整体投入。
|
1天前
|
弹性计算 人工智能 对象存储
2026阿里云双十一大促活动,个人开发者、初创团队、中小企业采购选型建议
最后总结不同人群的采购思路。个人开发者优先38元轻量+百炼免费Token,主打低成本学习和原型测试;初创团队优先ECS经济型实例+Token Plan,原型验证用轻量,正式业务上ECS,弹性扩容;中小企业优先企业专场、多年合约、续费同价方案,核心业务用ECS集群+RDS,AI算力按需采购GPU资源包。结合本次2026阿里云双十一大促的优惠节奏,先领券、先测试、再下单,配合CLI工具盘点资源,就可以把预算花在核心业务上,拿到最优的上云成本。
|
23小时前
|
弹性计算 人工智能 监控
2026年阿里云双十一老用户必看,云产品优惠、参与门槛、采购方案
老用户不用错过 阿里云轻量应用服务器、阿里云ECS云服务器、阿里云GPU云服务器、阿里云大模型服务平台 专属活动,轻量、ECS、GPU多款机型都开放专属特惠。在选购时,结合业务场景挑选机型,注意库存、保有数量限制,利用CLI工具管理实例、监控资源,做好成本规划,就能借助活动降低云服务器长期使用成本。在活动周期内,可以定期进入老用户特惠专区,查看库存更新,抓住合适时机采购或者续费。
|
22小时前
|
传感器 数据采集 监控
生态流量远程监测SL651数据传输系统方案
本项目构建水库河道生态流量智能监控系统,通过工业网关接入传感器,实时采集流量、水位等数据,支持4G远程传输与SL651规约上报,实现低功耗、断网续传、多平台共享,提升生态流量监管与调度决策水平。(239字)
23 0
|
开发者
阿里云开发者社区Markdown语法
阿里云开发者社区Markdown语法
18604 4
|
7天前
|
存储 算法 JavaScript
时间戳与 JWT:令牌解析、验签与时区陷阱
本文详解时间戳与JWT时间声明的常见误区:Unix时间戳是UTC秒数,JWT的`exp`/`nbf`/`iat`也是秒级(非毫秒);解码JWT不等于验签成功;时区错位、单位混淆(秒/毫秒)、本地时间输入歧义是故障主因。推荐两个工具辅助排查:Unix时间戳转换器与JWT解码器(仅解码,不验签)。
|
1月前
|
存储 人工智能 安全
结构化数据互转(下):任意进制与罗马数字的换算实现
本文深入探讨数字的多种表示法(十进制、二进制、十六进制、罗马数字等),强调数值与表示法的本质区别;详解进制转换原理、`parseInt`陷阱、`BigInt`精度保障、前导零语义、二进制补码位宽依赖及罗马数字规范校验,助力开发者安全、准确地处理各类数字转换场景。(239字)
|
2月前
|
JSON 安全 JavaScript
结构化数据互转(上):JSON 与 CSV 的字段映射、类型推断
本文详解JSON与CSV互转的核心陷阱:字段映射易错、类型自动推断致精度丢失(如`000128`变`128`)、嵌套结构扁平化无标准解。强调“JSON是树,CSV是表”,厘清记录路径选取、数组处理策略、安全引号转义及长数字/前导零必须字符串化等关键规则。(239字)
|
2月前
|
存储 JavaScript 前端开发
不用“利息÷本金÷年限”:如何用现金流 IRR 计算贷款真实年化率
本文详解如何用现金流IRR替代简单“利息÷本金÷年限”,精准计算贷款真实年化利率。揭示等额本息下本金动态减少、手续费时点影响等关键因素,演示JavaScript二分法求解月IRR并换算有效年化率(非简单×12),指出XIRR适用不规则还款、避免多解陷阱,助你识破名义利率误导。(239字)
|
2月前
|
编解码 前端开发 JavaScript
编码与转义三件套:URL 编码、Base64、HTML 实体的实现与常见坑
本文详解URL编码、Base64与HTML实体三大字符处理机制的区别与适用场景:URL编码用于查询参数(如`C++→C%2B%2B`),Base64用于字节序列化(需先UTF-8再编码),HTML实体用于安全显示标签(如`<div>→<div>`)。强调“数据交给谁解析”是选择方案的关键,避免误用与重复编码。