也就是本金+利息每月是相等的,即每月还款额是等额的。
随着占用资金成本的减少所产生的每月利息也会对应减少,在每月还款额不变的情况下,每月需还款本金是递增的。
计算步骤如下:
1.按照推导公式优先计算每月还款额。
每月还款额=(贷款本金月利率*(1+月利率)^还款月数))/((1+月利率)^还款月数-1)
2.根据剩余本金计算当期利息。
利息=剩余本金*月利率
3.计算当期本金。
本金=每月还款额-利息。
4.最后一期使用倒推法先计算本金。
本金=贷款金额-前期合计本金
本金每月是等额的,随着占用资金成本的减少所产生的每月利息也会对应减少,在本金不变的情况下,每月还款额是逐月递减的。
计算步骤如下:
1.按照推导公式优先计算每月本金。
本金=贷款金额/贷款期数
2.根据剩余本金计算当期利息。
利息=剩余本金*月利率
3.计算每月还款额。
每月还款额=本金+利息
4.最后一期使用倒推法先计算本金。
本金=贷款金额-前期合计本金
5.计算最后一期利息。
利息=剩余本金*月利率
6.计算最后一期还款额。
每月还款额=本金+利息
计算工具类
- public class LoanCalculator {
-
- /**
- * 等额本息计算公式
- *
- * @param param - 贷款信息
- */
- public static Map
calcEqCapitalAndInterest(Param param) { - Map
result = new TreeMap<>(Comparator.comparingInt(o -> o)); - // 总贷款期限
- int loanPeriods = param.getLoanPeriods();
- // 贷款月利率
- BigDecimal monthRate = param.getMonthRate();
- // 每月还款金额
- BigDecimal monthAmount = calMonthRepayment(param);
- // 剩余本金
- BigDecimal balance = param.getLoanAmount();
- // 出最后一期本金和
- BigDecimal noneLastCapitalTotal = BigDecimal.ZERO;
- Loan loan;
- LocalDate date = ObjectsUtil.isNull(param.getStartRepaymentDate()) ? LocalDate.now() : param.getStartRepaymentDate();// 还款日
- for (int i = 1; i <= loanPeriods; i++) {
- loan = new Loan().setPeriod(i).setAmount(monthAmount);// 每月还款金额
- loan.setInterest(calMonthInterest(balance, monthRate));// 利息=剩余本金*月利率
- loan.setCapital(monthAmount.subtract(loan.getInterest()));// 本金=每月还款额-利息
- loan.setCapitalBalance(balance = balance.subtract(loan.getCapital()));// 当期剩余本金
- loan.setRepaymentDate(date.plusMonths(i - 1));// 还款日
- result.put(i, loan);
- if (i != loanPeriods) {
- noneLastCapitalTotal = noneLastCapitalTotal.add(loan.getCapital());
- }
- }
- // 修正最后一期的数值
- Loan lastLoan = result.get(loanPeriods);
- lastLoan.setCapital(param.getLoanAmount().subtract(noneLastCapitalTotal));// 最后一期使用倒推法先计算本金,本金=贷款金额-前期合计本金。
- lastLoan.setInterest(monthAmount.subtract(lastLoan.getCapital()));// 计算最后一期利息,当期利息=每月还款额-本金。
- lastLoan.setCapitalBalance(BigDecimal.ZERO);// 最后一期剩余本金为零,剩余的全部加在最后一期本金计算利息
- return result;
- }
-
- /**
- * 等额本金计算公式
- *
- * @param param - 贷款信息
- */
- public static Map
calcEqCapital(Param param) { - Map
result = new TreeMap<>(Comparator.comparingInt(o -> o)); - // 总贷款期限
- int loanPeriods = param.getLoanPeriods();
- // 贷款月利率
- BigDecimal monthRate = param.getMonthRate();
- // 每月还款本金
- BigDecimal monthCapital = calMonthCapital(param);
- // 剩余本金
- BigDecimal balance = param.getLoanAmount();
- Loan loan;
- LocalDate date = ObjectsUtil.isNull(param.getStartRepaymentDate()) ? LocalDate.now() : param.getStartRepaymentDate();// 还款日
- for (int i = 1; i <= loanPeriods; i++) {
- loan = new Loan().setPeriod(i).setCapital(monthCapital);// 本金
- loan.setInterest(calMonthInterest(balance, monthRate));// 利息=剩余本金*月利率
- loan.setAmount(loan.getCapital().add(loan.getInterest()));// 每月还款额=本金+利息
- loan.setCapitalBalance(balance = balance.subtract(monthCapital));// 当期剩余本金
- loan.setRepaymentDate(date.plusMonths(i - 1));// 还款日
- result.put(i, loan);
- }
- // 修正最后一期的数值
- Loan lastLoan = result.get(loanPeriods);
- lastLoan.setCapital(param.getLoanAmount().subtract(monthCapital.multiply(BigDecimal.valueOf(loanPeriods - 1))));// 最后一期使用倒推法先计算本金,本金=贷款金额-前期合计本金。
- lastLoan.setInterest(calMonthInterest(lastLoan.getCapital(), monthRate));// 计算最后一期利息,利息=剩余本金*月利率。
- lastLoan.setAmount(lastLoan.getCapital().add(lastLoan.getInterest()));// 计算最后一期还款额,每月还款额=本金+利息。
- lastLoan.setCapitalBalance(BigDecimal.ZERO);// 最后一期剩余本金为零,剩余的全部加在最后一期本金计算利息
- return result;
- }
-
- /**
- * 计算等额本息还款月供
- *
- * @param param 贷款信息包含贷款金额、年利率、期限
- * @return 等额本息还款月供
- */
- private static BigDecimal calMonthRepayment(Param param) {
- BigDecimal totalRate = param.getMonthRate().add(BigDecimal.ONE);
- return fromMetadata(param.getLoanAmount().multiply((param.getMonthRate().multiply(totalRate.pow(param.getLoanPeriods()))).divide(totalRate.pow(param.getLoanPeriods()).subtract(BigDecimal.ONE), RoundingMode.HALF_EVEN)), 2);
- }
-
- /**
- * 计算等额本金每月还款本金
- *
- * @param param 贷款信息包含贷款金额、年利率
- * @return 等额本金每月还款本金
- */
- private static BigDecimal calMonthCapital(Param param) {
- return fromMetadata(param.getLoanAmount().divide(new BigDecimal(param.getLoanPeriods()), 2, RoundingMode.HALF_EVEN), 2);
- }
-
- /**
- * 计算利息
- *
- * @param restCapital 剩余本金
- * @param monthRate 月利率
- * @return 当期利息
- */
- private static BigDecimal calMonthInterest(BigDecimal restCapital, BigDecimal monthRate) {
- return fromMetadata(restCapital.multiply(monthRate), 2);
- }
-
- /**
- * 银行家算法截取指定位数
- *
- * @param bigDecimal 待格式化数据
- * @param digit 截取位数
- */
- static BigDecimal fromMetadata(BigDecimal bigDecimal, int digit) {
- return bigDecimal.setScale(digit, RoundingMode.HALF_EVEN);
- }
- }
辅助类
- /**
- * 贷款数据计算参数
- */
- @Getter
- @Setter
- public class Param {
- private final static BigDecimal monthTimes = new BigDecimal("12");
- /**
- * 贷款金额
- */
- private BigDecimal loanAmount;
- /**
- * 贷款年利率
- */
- private BigDecimal yearRate;
- /**
- * 贷款期限(月)
- */
- private int loanPeriods;
- /**
- * 首期还款日
- */
- private LocalDate startRepaymentDate = LocalDate.now();
-
- public BigDecimal getMonthRate() {
- return LoanCalculator.fromMetadata(yearRate.divide(monthTimes, 8, RoundingMode.HALF_EVEN), 8);
- }
- }
- /**
- * 贷款信息
- */
- @ToString
- @Getter
- @Setter
- @Accessors(chain = true)
- public class Loan implements Serializable {
- private static final long serialVersionUID = 1L;
- /**
- * 期数
- */
- private Integer period;
- /**
- * 还款日
- */
- private LocalDate repaymentDate;
- /**
- * 月还款金额
- */
- private BigDecimal amount;
- /**
- * 月还款本金
- */
- private BigDecimal capital;
- /**
- * 月还款利息
- */
- private BigDecimal interest;
- /**
- * 剩余应还本金
- */
- private BigDecimal capitalBalance;
- }