住房贷款等额本息(等额本金)还款计划计算

一、等额本息

也就是本金+利息每月是相等的,即每月还款额是等额的。

随着占用资金成本的减少所产生的每月利息也会对应减少,在每月还款额不变的情况下,每月需还款本金是递增的。

计算步骤如下:

1.按照推导公式优先计算每月还款额。

每月还款额=(贷款本金月利率*(1+月利率)^还款月数))/((1+月利率)^还款月数-1)

2.根据剩余本金计算当期利息。

利息=剩余本金*月利率

3.计算当期本金。

本金=每月还款额-利息。

4.最后一期使用倒推法先计算本金。

本金=贷款金额-前期合计本金

二、等额本金

本金每月是等额的,随着占用资金成本的减少所产生的每月利息也会对应减少,在本金不变的情况下,每月还款额是逐月递减的。

计算步骤如下:
1.按照推导公式优先计算每月本金。
本金=贷款金额/贷款期数
2.根据剩余本金计算当期利息。
利息=剩余本金*月利率
3.计算每月还款额。
每月还款额=本金+利息
4.最后一期使用倒推法先计算本金。
本金=贷款金额-前期合计本金
5.计算最后一期利息。
利息=剩余本金*月利率
6.计算最后一期还款额。
每月还款额=本金+利息

三、代码实现

计算工具类

public class LoanCalculator {

    /**
     * 等额本息计算公式
     *
     * @param param - 贷款信息
     */
    public static Map<Integer, Loan> calcEqCapitalAndInterest(Param param) {
        Map<Integer, Loan> 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<Integer, Loan> calcEqCapital(Param param) {
        Map<Integer, Loan> 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;
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流沙QS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值