@Test public void testGetPaymentsAmortizedWithOverPayment() { AmortizationAttributes amAttrs = generateAmortizationAttributesObjectTemplate(); amAttrs.setLoanAmount(ofUSD(10000)); amAttrs.setInterestRateAsPercent(3.); amAttrs.setInterestOnly(false); amAttrs.setRegularPayment(ofUSD(400)); amAttrs.setPaymentFrequency(TimePeriod.SemiMonthly.getPeriodsPerYear()); int termInMonths = 24; amAttrs.setTermInMonths(termInMonths); amAttrs.setAmortizationPeriodInMonths(24); amAttrs.setCompoundingPeriodsPerYear(2); List<ScheduledPayment> schedule = AmortizationCalculator.generateSchedule(amAttrs); assertEquals( "Amortized payment count", amAttrs.getPaymentFrequency() * termInMonths / 12, schedule.size()); MonetaryAmount interestTotal = schedule.stream().map(payment -> payment.getInterest()).reduce((a, b) -> a.add(b)).get(); assertEquals("Amortized Interest total", ofUSD(164.81), interestTotal); }
@Test public void testGetPaymentsAmortizedFully() { AmortizationAttributes amAttrs = generateAmortizationAttributesObjectTemplate(); MonetaryAmount loanAmount = ofUSD(10000); amAttrs.setLoanAmount(loanAmount); amAttrs.setInterestRateAsPercent(7.); amAttrs.setInterestOnly(false); amAttrs.setPaymentFrequency(TimePeriod.Monthly.getPeriodsPerYear()); int termInMonths = 12; amAttrs.setTermInMonths(termInMonths); amAttrs.setAmortizationPeriodInMonths(12); amAttrs.setCompoundingPeriodsPerYear(2); amAttrs.setRegularPayment(AmortizationCalculator.getPeriodicPayment(amAttrs)); List<ScheduledPayment> schedule = AmortizationCalculator.generateSchedule(amAttrs); MonetaryAmount interestTotal = schedule.stream().map(payment -> payment.getInterest()).reduce((a, b) -> a.add(b)).get(); assertEquals("Amortized Interest total", ofUSD(377.67), interestTotal); MonetaryAmount principalTotal = schedule.stream().map(payment -> payment.getPrincipal()).reduce((a, b) -> a.add(b)).get(); assertEquals("Amortized Principal fully paid", loanAmount, principalTotal); }
@Test public void testGenerateScheduleInterestOnlyArrayBounds() { AmortizationAttributes amAttrs = generateAmortizationAttributesObjectTemplate(); amAttrs.setLoanAmount(ofUSD(10000)); amAttrs.setInterestRateAsPercent(12.); amAttrs.setInterestOnly(true); amAttrs.setPaymentFrequency(TimePeriod.Weekly.getPeriodsPerYear()); int termInMonths = 24; amAttrs.setTermInMonths(termInMonths); amAttrs.setAdjustmentDate(LocalDate.of(2016, Month.JANUARY, 1)); List<ScheduledPayment> schedule = AmortizationCalculator.generateSchedule(amAttrs); try { schedule.get(-1); fail("Interest only schedule should not allow negative payment number"); } catch (IndexOutOfBoundsException iobe) { } int expectedPayments = (int) Math.ceil(amAttrs.getPaymentFrequency() * amAttrs.getTermInMonths() / 12.); try { schedule.get(expectedPayments); fail("Interest only schedule should not allow payments beyond schedule bound"); } catch (IndexOutOfBoundsException iobe) { } schedule.get(expectedPayments - 1); }
@Test public void testGenerateScheduleInterestOnlyMonthly() { AmortizationAttributes amAttrs = generateAmortizationAttributesObjectTemplate(); amAttrs.setLoanAmount(ofUSD(10000)); amAttrs.setInterestRateAsPercent(10.); amAttrs.setInterestOnly(true); amAttrs.setPaymentFrequency(TimePeriod.Monthly.getPeriodsPerYear()); int termInMonths = 12; amAttrs.setTermInMonths(termInMonths); amAttrs.setAdjustmentDate(LocalDate.of(2016, Month.JANUARY, 1)); amAttrs.setRegularPayment(ofUSD(0)); List<ScheduledPayment> schedule = AmortizationCalculator.generateSchedule(amAttrs); assertEquals("Interest only schedule term in months", termInMonths, schedule.size()); MonetaryAmount expectedInterest = ofUSD(83.34); MonetaryAmount expectedPrincipal = ofUSD(0); LocalDate expectedDate = amAttrs.getAdjustmentDate(); int index = 0; for (ScheduledPayment payment : schedule) { expectedDate = expectedDate.plusMonths(1L); assertEquals("Interest only schedule payment number", ++index, payment.getPaymentNumber()); assertEquals("Interest only schedule payment date", expectedDate, payment.getPaymentDate()); assertEquals( "Interest only schedule payment interest", expectedInterest, payment.getInterest()); assertEquals( "Interest only schedule payment principal", expectedPrincipal, payment.getPrincipal()); assertEquals( "Interest only schedule payment total payment", expectedInterest, payment.getPayment()); assertEquals( "Interest only schedule payment loan principal", ofUSD(10000), payment.getBalance()); } }
@Test public void testPaymentDateWeekly() { LocalDate scheduleStartDate = LocalDate.of(2015, Month.DECEMBER, 2); AmortizationAttributes amAttrs = generateAmortizationAttributesObjectTemplate(); amAttrs.setAdjustmentDate(scheduleStartDate); amAttrs.setPaymentFrequency(TimePeriod.Weekly.getPeriodsPerYear()); int termInMonths = 24; amAttrs.setTermInMonths(termInMonths); List<ScheduledPayment> schedule = AmortizationCalculator.generateSchedule(amAttrs); for (int i = 1; i <= (52 * 2); i++) { String msg = String.format("Date for weekly payment %d", i); assertEquals(msg, scheduleStartDate.plusWeeks(i), schedule.get(i - 1).getPaymentDate()); } }
private void testPaymentDatesWithMonthlyIntervals(int periodsPerYear) { LocalDate scheduleStartDate = LocalDate.of(2015, Month.DECEMBER, 2); AmortizationAttributes amAttrs = generateAmortizationAttributesObjectTemplate(); amAttrs.setAdjustmentDate(scheduleStartDate); amAttrs.setPaymentFrequency(periodsPerYear); int termInMonths = 24; amAttrs.setTermInMonths(termInMonths); List<ScheduledPayment> schedule = AmortizationCalculator.generateSchedule(amAttrs); for (int i = 1; i <= termInMonths / (12 / periodsPerYear); i++) { String msg = String.format("Date for payment %d when %d payments a year", i, periodsPerYear); assertEquals( msg, scheduleStartDate.plusMonths(i * (12 / periodsPerYear)), schedule.get(i - 1).getPaymentDate()); } }
@Test public void testGetPeriodInterest_Amortized() { AmortizationAttributes amAttrs = generateAmortizationAttributesObjectTemplate(); amAttrs.setLoanAmount(USD50000.multiply(2)); amAttrs.setInterestRateAsPercent(12.); amAttrs.setCompoundingPeriodsPerYear(2); amAttrs.setPaymentFrequency(12); List<ScheduledPayment> generatedSchedule = AmortizationCalculator.generateSchedule(amAttrs); generatedSchedule .stream() .forEachOrdered( p -> { MonetaryAmount periodInterest = AmortizationCalculator.getPeriodInterest(amAttrs); assertEquals( "Monthly amortized payment interest matches peirod interest", p.getInterest(), periodInterest); amAttrs.setLoanAmount(p.getBalance()); }); }
@Test public void testPaymentDateSemiMonthly() { LocalDate scheduleStartDate = LocalDate.of(2015, Month.DECEMBER, 2); AmortizationAttributes amAttrs = generateAmortizationAttributesObjectTemplate(); amAttrs.setAdjustmentDate(scheduleStartDate); amAttrs.setPaymentFrequency(TimePeriod.SemiMonthly.getPeriodsPerYear()); int termInMonths = 24; amAttrs.setTermInMonths(termInMonths); int dayOfMonthPayment1 = scheduleStartDate.getDayOfMonth(); int dayOfMonthPayment2 = scheduleStartDate.plusDays(14).getDayOfMonth(); List<ScheduledPayment> schedule = AmortizationCalculator.generateSchedule(amAttrs); // First payment of month for (int i = 1; i <= 48; i += 2) { String msg = String.format("First date for semi-monthly payment %d", i); assertEquals( msg, scheduleStartDate.plusMonths(i / 2).plusDays(14), schedule.get(i - 1).getPaymentDate()); assertEquals( "Semi-monthly common day of month", dayOfMonthPayment2, schedule.get(i - 1).getPaymentDate().getDayOfMonth()); } // Second payment of month for (int i = 2; i <= 48; i += 2) { String msg = String.format("Second date for semi-monthly payment %d", i); assertEquals(msg, scheduleStartDate.plusMonths(i / 2), schedule.get(i - 1).getPaymentDate()); assertEquals( "Semi-monthly common day of month", dayOfMonthPayment1, schedule.get(i - 1).getPaymentDate().getDayOfMonth()); } }