借呗提前还款算法模拟

/**
 * 阿里借呗计息还款规则说明实现
 * 
 * 测试阿里案例和韩哥案例通过
 * @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;
	}

}

猜你喜欢

转载自huluyisheng.iteye.com/blog/2374727
今日推荐