我想创建一个Amortisation calculator来获取贷款人数 N 的报价36个月贷款,其中每个贷款人的利率不同。目标是提供尽可能低的费率,并提供每月还款金额和总还款金额。我的代码的结果是关闭但不完全。
我正在使用公式
将i
(利率)计算为total amount lended / requested amount
,其中,每个贷方的借出金额乘以贷方的利率。
BigDecimal requestedAmountP = new BigDecimal("" + requestedAmount);
BigDecimal minLendersRate = calculateRate(requestedAmount, lenders);
// https://en.wikipedia.org/wiki/Mortgage_calculator#Monthly_payment_formula
// r*P/(1 - (1+r)^(-N)) if r != 0
// P/N if r == 0
BigDecimal monthlyRepayment;
if (minLendersRate.compareTo(BigDecimal.ZERO) == 0) {
monthlyRepayment = requestedAmountP.divide(DURATION_MONTHS, MathContext.DECIMAL128);
} else {
BigDecimal r = calculateEffectiveInterestInMonths(minLendersRate);
BigDecimal tmp = r.add(BigDecimal.ONE).pow(-DURATION_MONTHS.intValue(), MathContext.DECIMAL128);
BigDecimal dividend = BigDecimal.ONE.subtract(tmp);
monthlyRepayment = r.multiply(requestedAmountP).divide(dividend, MathContext.DECIMAL128);
}
BigDecimal totalRepayment = monthlyRepayment.multiply(DURATION_MONTHS);
计算费率:
private BigDecimal calculateRate(double requestedAmount, List<Lender> lenders) {
List<Lender> sortedLenders = lenders.stream().sorted(Comparator.comparing(Lender::getRate)).collect(toList());
List<BigDecimal> moneyLended = moneyLended(requestedAmount, sortedLenders);
BigDecimal totalMoneyLended = IntStream.range(0, moneyLended.size())
.mapToObj(index -> moneyLended.get(index).multiply(sortedLenders.get(index).getRate()))
.reduce(BigDecimal.ZERO, BigDecimal::add);
return totalMoneyLended.divide(new BigDecimal("" + requestedAmount), MathContext.DECIMAL128);
}
private List<BigDecimal> moneyLended(double requestedAmount, List<Lender> sortedLenders) {
List<BigDecimal> moneyLended = new ArrayList<>(sortedLenders.size());
int i = 0;
Double remaining = requestedAmount;
while (remaining > 0) {
if (remaining - sortedLenders.get(i).getAvailable().doubleValue() >= 0) {
remaining = remaining - sortedLenders.get(i).getAvailable().doubleValue();
} else {
remaining = 0d;
}
moneyLended.add(sortedLenders.get(i).getAvailable());
i++;
}
return moneyLended;
}
计算Effective Interest in Months
private BigDecimal calculateEffectiveInterestInMonths(BigDecimal nominalInterest) {
// Formula: ((1+nominalInterest)^(1/12))-1
BigDecimal exp = BigDecimal.ONE.divide(new BigDecimal("12"), MathContext.DECIMAL128);
return BigDecimalMath.pow(BigDecimal.ONE.add(nominalInterest), exp, MathContext.DECIMAL128)
.subtract(BigDecimal.ONE);
}
似乎十进制操作存在问题,但我无法找到位置。