借呗提前还款算法模拟

/**
* 阿里借呗计息还款规则说明实现
*
* 测试阿里案例和韩哥案例通过
* @return
*/
package jdongtech.jiebaiUtils;

import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import jdongtech.interestUtils.AverageCapitalPlusInterestUtils;

public class advanceRepayMore {
public static void main(String[] args) {

Calendar lendDay = Calendar.getInstance(); // 借款日期
Calendar rebackDay = Calendar.getInstance();// 还款日期
double rebackInvest = 0; // 还款金额
double invest = 0; // 借款本金
int month = 0; // 期数
double yearRate = 0; // 年利率
int acctOffsetDay = 15; // 平移日期
int accountDay = 25; // 账单日,蚂蚁会把账单日设置成借款当日

// 文件示例
lendDay.set(Calendar.MONTH, 9);
lendDay.set(Calendar.DAY_OF_MONTH, 13);
rebackInvest = 100.24;
// rebackInvest = 60.04;
rebackDay.set(Calendar.MONTH, 9);
rebackDay.set(Calendar.DAY_OF_MONTH, 14);
invest = 1200; // 本金
month = 12; // 期数
yearRate = 7.2 / 100; // 年利率
acctOffsetDay = 15;
accountDay = 25;

// 韩哥示例
lendDay.set(Calendar.MONTH, 4);
lendDay.set(Calendar.DAY_OF_MONTH, 13);
rebackInvest = 60.04;
rebackDay.set(Calendar.MONTH, 4);
rebackDay.set(Calendar.DAY_OF_MONTH, 13);
invest = 120; // 本金
month = 6; // 期数
yearRate = 14.4 / 100; // 年利率
acctOffsetDay = 15;
accountDay = 13; // 账单日,蚂蚁会把账单日设置成借款当日

double dateRate = yearRate / 360;
int[] daysCount = new int[month];
int IncreaseFlag = 0;
Calendar lendCalOffset = (Calendar) lendDay.clone();
lendCalOffset.add(Calendar.DATE, acctOffsetDay);
Calendar accCal = (Calendar) lendDay.clone();
accCal.set(Calendar.DAY_OF_MONTH, accountDay);
Calendar accCalBegin = (Calendar) accCal.clone();
if (lendCalOffset.before(accCal)) {
} else {
accCalBegin.add(Calendar.MONTH, 1);
IncreaseFlag = 1;
}
Calendar accCalEnd = (Calendar) accCal.clone();
accCalEnd.add(Calendar.MONTH, month - 1);

System.out.println(lendDay.getTime() + "借款日期");
System.out.println(accCalBegin.getTime() + "开始");
System.out.println(accCalEnd.getTime() + "结束");
int daysLending = RepayUtils.daysOffset(lendDay, accCalEnd);
System.out.println("借款经历" + daysLending + "天");

Calendar accCalPerEnd = (Calendar) accCalBegin.clone();
for (int i = 0; i < month; i++) {
Calendar accCalPerBeg;
if (i == 0) {
accCalPerBeg = (Calendar) lendDay.clone();
} else {
accCalPerBeg = (Calendar) accCalPerEnd.clone();
accCalPerBeg.add(Calendar.MONTH, -1);
}

int daysPer = RepayUtils.daysOffset(accCalPerBeg, accCalPerEnd);
daysCount[i] = daysPer;
accCalPerEnd.add(Calendar.MONTH, 1);
}

System.out.println("部分还款前计划:");
normalRepay.getPerMonthPrincipalInterestBig(invest, dateRate, month, daysCount, IncreaseFlag);

System.out.println("提前还款日期:" + rebackDay.getTime());
int curPeriod = 0;
int daysCurPeriod = RepayUtils.daysOffset(lendDay, rebackDay);
for (int i = 0; i < daysCount.length; i++) {
daysCurPeriod = daysCurPeriod - daysCount[i];
if (daysCurPeriod <= 0) { // 账单日算当前期
curPeriod = i;
daysCurPeriod = daysCurPeriod + daysCount[i];
i = daysCount.length;
}
}
System.out.println("提前还款当期期数:" + curPeriod);
System.out.println("提前还款当期天数:" + daysCurPeriod);
System.out.println("部分还款后计划:");
getPerMonthPrincipalInterestBigRebackSome(invest, dateRate, month, daysCount, IncreaseFlag, rebackInvest,
curPeriod, daysCurPeriod);
}

/**
* 计算实际等额本息每月额度
*
* @return
*/
public static double getPerMonthPrincipalInterestBigRebackSome(double invest, double dateRate, int totalmonth,
int[] daysCount, int IncreaseFlag, double rebackInvest, int curPeriod, int daysCurPeriod) {
IncreaseFlag = 1;
if (daysCurPeriod == 0) {
daysCurPeriod = 1;
}
double perMonthStandard = AverageCapitalPlusInterestUtils.getPerMonthPrincipalInterest(invest, dateRate * 360,
totalmonth);

double perMonthMax = perMonthStandard * 1.01;
double[] PRperMonth = new double[totalmonth];
double[] PperMonth = new double[totalmonth];
double[] RperMonth = new double[totalmonth];
double[] PLeftperMonth = new double[totalmonth];
Map<Double, Double> lastCheckMap = new HashMap<Double, Double>();
Map<Double, double[]> PLeftperMonthMap = new HashMap<Double, double[]>();
Map<Double, double[]> PRperMonthMap = new HashMap<Double, double[]>();
Map<Double, double[]> PperMonthMap = new HashMap<Double, double[]>();
Map<Double, double[]> RperMonthMap = new HashMap<Double, double[]>();
Map<Double, Double> sumPRMap = new HashMap<Double, Double>();
Map<Double, Double> sumPMap = new HashMap<Double, Double>();
Map<Double, Double> sumRMap = new HashMap<Double, Double>();

if (IncreaseFlag == 1) {
while (perMonthStandard < perMonthMax) {
PRperMonth = new double[totalmonth];
PperMonth = new double[totalmonth];
RperMonth = new double[totalmonth];
PLeftperMonth = new double[totalmonth];

PRperMonth[0] = RepayUtils.num2second(perMonthStandard);
PLeftperMonth[0] = RepayUtils.num2second(invest);
RperMonth[0] = RepayUtils.num2secondDown(PLeftperMonth[0] * daysCount[0] * dateRate);
PperMonth[0] = RepayUtils.num2second(PRperMonth[0] - RperMonth[0]);
for (int j = 1; j < totalmonth; j++) {
PRperMonth[j] = RepayUtils.num2second(perMonthStandard);
PLeftperMonth[j] = RepayUtils.num2second(PLeftperMonth[j - 1] - PperMonth[j - 1]);
RperMonth[j] = RepayUtils.num2secondDown(PLeftperMonth[j] * dateRate * daysCount[j]);
PperMonth[j] = RepayUtils.num2second(PRperMonth[j] - RperMonth[j]);
if (j == totalmonth - 1) {
PperMonth[j] = RepayUtils.num2second(PLeftperMonth[j]);
PRperMonth[j] = RepayUtils.num2second(PperMonth[j] + RperMonth[j]);
}
}
double sumP = 0;
double sumR = 0;
double sumPR = 0;
for (int i = 0; i < PLeftperMonth.length; i++) {
sumP = sumP + PperMonth[i];
sumR = sumR + RperMonth[i];
sumPR = sumPR + PRperMonth[i];
}
lastCheckMap.put(RepayUtils.num2second(perMonthStandard),
Math.abs(PRperMonth[totalmonth - 1] - PRperMonth[totalmonth - 2]));
PLeftperMonthMap.put(RepayUtils.num2second(perMonthStandard), PLeftperMonth);
PRperMonthMap.put(RepayUtils.num2second(perMonthStandard), PRperMonth);
PperMonthMap.put(RepayUtils.num2second(perMonthStandard), PperMonth);
RperMonthMap.put(RepayUtils.num2second(perMonthStandard), RperMonth);
sumPRMap.put(RepayUtils.num2second(perMonthStandard), RepayUtils.num2second(sumPR));
sumPMap.put(RepayUtils.num2second(perMonthStandard), RepayUtils.num2second(sumP));
sumRMap.put(RepayUtils.num2second(perMonthStandard), RepayUtils.num2second(sumR));

perMonthStandard = perMonthStandard + 0.01;
}
}

Double resultKey = RepayUtils.getKeyByMinValue(lastCheckMap);
// 当期剩余天数
int remainDaysCurPeriod = daysCount[curPeriod] - daysCurPeriod;
double rebackPCurPeriod = RepayUtils.num2second(
rebackInvest - RepayUtils.num2secondDown(PLeftperMonth[curPeriod] * dateRate * daysCurPeriod));

if (rebackPCurPeriod < PperMonthMap.get(resultKey)[curPeriod]) { // 还款小于当前期本金
PLeftperMonthMap.get(resultKey)[curPeriod] = RepayUtils
.num2second(PLeftperMonthMap.get(resultKey)[curPeriod] - rebackPCurPeriod);
PperMonthMap.get(resultKey)[curPeriod] = RepayUtils
.num2second(PperMonthMap.get(resultKey)[curPeriod] - rebackPCurPeriod);
RperMonthMap.get(resultKey)[curPeriod] = RepayUtils
.num2secondDown(PLeftperMonthMap.get(resultKey)[curPeriod] * dateRate * remainDaysCurPeriod);
PRperMonthMap.get(resultKey)[curPeriod] = RepayUtils
.num2second(RperMonthMap.get(resultKey)[curPeriod] + PperMonthMap.get(resultKey)[curPeriod]);

System.out.println("等额本息每月还款额:" + resultKey);
System.out.println("每期经历" + Arrays.toString(daysCount));
System.out.println("每月余本金:" + Arrays.toString(PLeftperMonthMap.get(resultKey)));
System.out.println("每月还款额:" + Arrays.toString(PRperMonthMap.get(resultKey)));
System.out.println("每月还本金:" + Arrays.toString(PperMonthMap.get(resultKey)));
System.out.println("每月还利息:" + Arrays.toString(RperMonthMap.get(resultKey)));
double sumP = 0;
double sumR = 0;
double sumPR = 0;
for (int i = 0; i < PLeftperMonth.length; i++) {
sumP = sumP + PperMonthMap.get(resultKey)[i];
sumR = sumR + RperMonthMap.get(resultKey)[i];
sumPR = sumPR + PRperMonthMap.get(resultKey)[i];
}
sumPRMap.put(RepayUtils.num2second(resultKey), RepayUtils.num2second(sumPR));
sumPMap.put(RepayUtils.num2second(resultKey), RepayUtils.num2second(sumP));
sumRMap.put(RepayUtils.num2second(resultKey), RepayUtils.num2second(sumR));

System.out.println("总还款额:" + sumPRMap.get(resultKey));
System.out.println("总还本金:" + sumPMap.get(resultKey));
System.out.println("总还利息:" + sumRMap.get(resultKey));

} else { // 还款本金大于当期本金
int[] dayCountsAfter = new int[totalmonth - curPeriod];
double[] PRperMonthAfter = new double[totalmonth - curPeriod];
double[] PperMonthAfter = new double[totalmonth - curPeriod];
double[] RperMonthAfter = new double[totalmonth - curPeriod];
double[] PLeftperMonthAfter = new double[totalmonth - curPeriod];

// P本金0的阶段 第一个月
double remainInvest = RepayUtils.num2second(PLeftperMonthMap.get(resultKey)[curPeriod] - rebackPCurPeriod);
PperMonthAfter[0] = RepayUtils.num2second(0);
PLeftperMonthAfter[0] = remainInvest;
RperMonthAfter[0] = RepayUtils.num2secondDown(PLeftperMonthAfter[0] * dateRate * remainDaysCurPeriod);
PRperMonthAfter[0] = RperMonthAfter[0];

// P本金非0的再平衡阶段
int remainMonth = totalmonth - curPeriod - 1;
double perMonthStandardRec = AverageCapitalPlusInterestUtils.getPerMonthPrincipalInterest(remainInvest,
dateRate * 360, remainMonth);
int[] daysCountRec = Arrays.copyOfRange(daysCount, curPeriod + 1, totalmonth); // 剩余天数数组
for (int i = 0; i < remainMonth; i++) {
dayCountsAfter[i + 1] = daysCountRec[i];
dayCountsAfter[0] = remainDaysCurPeriod;
}

double perMonthMaxRec = perMonthStandardRec * 1.1;
double[] PRperMonthRec = new double[remainMonth];
double[] PperMonthRec = new double[remainMonth];
double[] RperMonthRec = new double[remainMonth];
double[] PLeftperMonthRec = new double[remainMonth];
Map<Double, Double> lastCheckMapRec = new HashMap<Double, Double>();
Map<Double, double[]> PLeftperMonthMapRec = new HashMap<Double, double[]>();
Map<Double, double[]> PRperMonthMapRec = new HashMap<Double, double[]>();
Map<Double, double[]> PperMonthMapRec = new HashMap<Double, double[]>();
Map<Double, double[]> RperMonthMapRec = new HashMap<Double, double[]>();
while (perMonthStandardRec < perMonthMaxRec) {
PRperMonthRec = new double[remainMonth];
PperMonthRec = new double[remainMonth];
RperMonthRec = new double[remainMonth];
PLeftperMonthRec = new double[remainMonth];

PRperMonthRec[0] = RepayUtils.num2second(perMonthStandardRec);
PLeftperMonthRec[0] = RepayUtils.num2second(remainInvest);
RperMonthRec[0] = RepayUtils.num2secondDown(PLeftperMonthRec[0] * daysCountRec[0] * dateRate);
PperMonthRec[0] = RepayUtils.num2second(PRperMonthRec[0] - RperMonthRec[0]);
for (int j = 1; j < remainMonth; j++) {
PRperMonthRec[j] = RepayUtils.num2second(perMonthStandardRec);
PLeftperMonthRec[j] = RepayUtils.num2second(PLeftperMonthRec[j - 1] - PperMonthRec[j - 1]);
RperMonthRec[j] = RepayUtils.num2secondDown(PLeftperMonthRec[j] * dateRate * daysCountRec[j]);
PperMonthRec[j] = RepayUtils.num2second(PRperMonthRec[j] - RperMonthRec[j]);
if (j == remainMonth - 1) {
PperMonthRec[j] = RepayUtils.num2second(PLeftperMonthRec[j]);
PRperMonthRec[j] = RepayUtils.num2second(PperMonthRec[j] + RperMonthRec[j]);
}
}

lastCheckMapRec.put(RepayUtils.num2second(perMonthStandardRec),
Math.abs(PRperMonthRec[remainMonth - 1] - PRperMonthRec[remainMonth - 2]));

PLeftperMonthMapRec.put(RepayUtils.num2second(perMonthStandardRec), PLeftperMonthRec);
PRperMonthMapRec.put(RepayUtils.num2second(perMonthStandardRec), PRperMonthRec);
PperMonthMapRec.put(RepayUtils.num2second(perMonthStandardRec), PperMonthRec);
RperMonthMapRec.put(RepayUtils.num2secondDown(perMonthStandardRec), RperMonthRec);
perMonthStandardRec = perMonthStandardRec + 0.01;
}

Double resultKeyRec = RepayUtils.getKeyByMinValue(lastCheckMapRec);

for (int i = 1; i < totalmonth; i++) {
PperMonthAfter[i] = RepayUtils.num2second(PperMonthMapRec.get(resultKeyRec)[i - 1]);
PLeftperMonthAfter[i] = RepayUtils.num2second(PLeftperMonthMapRec.get(resultKeyRec)[i - 1]);
RperMonthAfter[i] = RepayUtils.num2second(RperMonthMapRec.get(resultKeyRec)[i - 1]);
PRperMonthAfter[i] = RepayUtils.num2second(PRperMonthMapRec.get(resultKeyRec)[i - 1]);
}

System.out.println("重新等额本息每月还款额:" + resultKeyRec);
System.out.println("重新每期经历" + Arrays.toString(dayCountsAfter));
System.out.println("重新每月余本金:" + Arrays.toString(PLeftperMonthAfter));
System.out.println("重新每月还款额:" + Arrays.toString(PRperMonthAfter));
System.out.println("重新每月还本金:" + Arrays.toString(PperMonthAfter));
System.out.println("重新每月还利息:" + Arrays.toString(RperMonthAfter));

double sumP = 0;
double sumR = 0;
double sumPR = 0;
for (int i = 0; i < PLeftperMonth.length; i++) {
sumP = sumP + PperMonthAfter[i];
sumR = sumR + RperMonthAfter[i];
sumPR = sumPR + PRperMonthAfter[i];
}
sumPRMap.put(RepayUtils.num2second(resultKey), RepayUtils.num2second(sumPR));
sumPMap.put(RepayUtils.num2second(resultKey), RepayUtils.num2second(sumP));
sumRMap.put(RepayUtils.num2second(resultKey), RepayUtils.num2second(sumR));

System.out.println("总还款额:" + sumPRMap.get(resultKey));
System.out.println("总还本金:" + sumPMap.get(resultKey));
System.out.println("总还利息:" + sumRMap.get(resultKey));
}
return resultKey;
}

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值