Beispiel #1
0
        public void GenerateAmSchedule_ShouldAccrueInterestFromStartDate(
            int loanLength
            )
        {
            //Assemble
            var interestStartDate = new LocalDate(2001, 1, 1);
            var paymentStartDate  = new DateTime(2001 + loanLength, 1, 1);
            var loan = GetTestLoan(
                amount: 1000,
                interestRate: 0.5m,
                interestAccrualStartDate:
                interestStartDate.ToDateTimeUnspecified(),
                maturityDate: new DateTime(2001 + loanLength + 1, 1, 1)
                );;
            var yearlyInterest  = loan.Amount * loan.InterestRate;
            var paymentSchedule = new List <PaymentSchedule>
            {
                GetTestPaymentSchedule(
                    endDate: paymentStartDate,
                    paymentFrequency: PaymentFrequency.Annual,
                    startDate: paymentStartDate
                    )
            };

            //Act
            var actual = AmortizationCalculator.GenerateAmortizationSchedule(
                loan,
                paymentSchedule
                );

            //Assert
            actual[0].Interest.Should().Be(yearlyInterest * loanLength);
        }
Beispiel #2
0
        public void GenerateAmSchedule_PaymentTypeIsBullet_ShouldPayOffEntireLoan()
        {
            var loanAmount = 10000;
            var loan       = GetTestLoan(
                amount: loanAmount,
                interestRate: 0.1m,
                interestAccrualStartDate: new DateTime(2001, 1, 1)
                );
            var paymentSchedule = new List <PaymentSchedule>
            {
                GetTestPaymentSchedule(
                    paymentFrequency: PaymentFrequency.Bullet,
                    paymentType: PaymentType.Bullet,
                    startDate: new DateTime(2001, 2, 1)
                    )
            };
            var expected = new List <AmortizationScheduleItem>
            {
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 2, 1),
                    Interest         = 84.93151m,
                    Principal        = loanAmount,
                    RemainingBalance = 0
                },
            };

            //Act
            var actual = AmortizationCalculator.GenerateAmortizationSchedule(
                loan,
                paymentSchedule
                );

            //Assert
            actual
            .Select(x => new AmortizationScheduleItem
            {
                Date             = x.Date,
                Interest         = TestUtils.RoundDecimal(x.Interest),
                Principal        = TestUtils.RoundDecimal(x.Principal),
                RemainingBalance =
                    TestUtils.RoundDecimal(x.RemainingBalance),
            })
            .Should()
            .BeEquivalentTo(expected, x => x.Excluding(x => x.Schedule));
        }
Beispiel #3
0
        public void GenerateAmSchedule_MultiplePaymentSchedules_ShouldOrderByDate()
        {
            //Assemble
            var annualStartDate     = new LocalDate(2001, 1, 1);
            var semiAnnualStartDate = new LocalDate(2001, 3, 1);
            var expected            = new List <DateTime>
            {
                annualStartDate.ToDateTimeUnspecified(),
                semiAnnualStartDate.ToDateTimeUnspecified(),
                semiAnnualStartDate.PlusMonths(6).ToDateTimeUnspecified(),
                annualStartDate.PlusYears(1).ToDateTimeUnspecified(),
                semiAnnualStartDate.PlusYears(1).ToDateTimeUnspecified(),
            };

            //Act
            var actual = AmortizationCalculator.GenerateAmortizationSchedule(
                GetTestLoan(maturityDate: new DateTime(2002, 4, 1)),
                new List <PaymentSchedule>
            {
                GetTestPaymentSchedule(
                    endDate:
                    annualStartDate.PlusYears(1).ToDateTimeUnspecified(),
                    paymentFrequency: PaymentFrequency.Annual,
                    startDate: annualStartDate.ToDateTimeUnspecified()
                    ),
                GetTestPaymentSchedule(
                    endDate: semiAnnualStartDate
                    .PlusYears(1)
                    .ToDateTimeUnspecified(),
                    paymentFrequency: PaymentFrequency.SemiAnnual,
                    startDate: semiAnnualStartDate.ToDateTimeUnspecified()
                    )
            }
                );

            //Assert
            actual.Select(x => x.Date).Should().Equal(expected);
        }
Beispiel #4
0
        private static void RunFrequencyTest(
            List <DateTime> expected,
            LocalDate endDate,
            PaymentFrequency frequency
            )
        {
            //Act
            var actual = AmortizationCalculator.GenerateAmortizationSchedule(
                GetTestLoan(
                    amount: 1000,
                    maturityDate: endDate.ToDateTimeUnspecified()
                    ),
                new List <PaymentSchedule>
            {
                GetTestPaymentSchedule(
                    endDate: endDate.ToDateTimeUnspecified(),
                    paymentFrequency: frequency
                    )
            }
                );

            //Assert
            actual.Select(x => x.Date).Should().Equal(expected);
        }
Beispiel #5
0
 public Handler(AmortizationCalculator amortizationCalculator)
 {
     _amortizationCalculator = amortizationCalculator;
 }
Beispiel #6
0
        public void GenerateAmSchedule_ScheduleListContainsBulletPayment_AllPaymentsAtAndAfterBulletDateShouldBeRemoved()
        {
            var loanStartDate = new LocalDate(2001, 1, 1);
            var loan          = GetTestLoan(
                amount: 3000,
                interestAccrualStartDate: loanStartDate.ToDateTimeUnspecified(),
                interestRate: 0.1m
                );
            var paymentSchedules = new List <PaymentSchedule>
            {
                GetTestPaymentSchedule(
                    endDate:
                    loanStartDate.PlusMonths(5).ToDateTimeUnspecified(),
                    paymentFrequency: PaymentFrequency.Monthly,
                    paymentAmount: 100,
                    paymentType: PaymentType.LevelPayment,
                    startDate:
                    loanStartDate.PlusMonths(1).ToDateTimeUnspecified()
                    ),
                GetTestPaymentSchedule(
                    paymentAmount: 0.1m,
                    paymentType: PaymentType.Bullet,
                    startDate:
                    loanStartDate.PlusMonths(2).ToDateTimeUnspecified()
                    ),
            };
            var expected = new List <AmortizationScheduleItem>
            {
                new AmortizationScheduleItem
                {
                    Date             = loanStartDate.PlusMonths(1).ToDateTimeUnspecified(),
                    Interest         = 25.47945m,
                    Principal        = 74.52055m,
                    RemainingBalance = 2925.47945m,
                },
                new AmortizationScheduleItem
                {
                    Date             = loanStartDate.PlusMonths(2).ToDateTimeUnspecified(),
                    Interest         = 22.44203m,
                    Principal        = 2925.47945m,
                    RemainingBalance = 0m,
                },
            };

            //Act
            var actual = AmortizationCalculator.GenerateAmortizationSchedule(
                loan,
                paymentSchedules
                );

            //Assert
            actual
            .Select(x => new AmortizationScheduleItem
            {
                Date             = x.Date,
                Interest         = TestUtils.RoundDecimal(x.Interest),
                Principal        = TestUtils.RoundDecimal(x.Principal),
                RemainingBalance =
                    TestUtils.RoundDecimal(x.RemainingBalance),
            })
            .Should()
            .BeEquivalentTo(expected, x => x.Excluding(x => x.Schedule));
        }
Beispiel #7
0
        public void GenerateAmSchedule_MultiplePaymentSchedulesProvided_ShouldCalculatePaymentsCorrectly()
        {
            //Assemble
            var loanStartDate = new LocalDate(2001, 1, 1);
            var percentagePaymentsStartDate =
                loanStartDate.PlusMonths(1).PlusDays(15);
            var loan = GetTestLoan(
                amount: 3000,
                interestAccrualStartDate: loanStartDate.ToDateTimeUnspecified(),
                interestRate: 0.1m,
                maturityDate: new DateTime(2001, 5, 1)
                );
            var paymentSchedules = new List <PaymentSchedule>
            {
                GetTestPaymentSchedule(
                    endDate:
                    loanStartDate.PlusMonths(2).ToDateTimeUnspecified(),
                    paymentFrequency: PaymentFrequency.Monthly,
                    paymentAmount: 100,
                    paymentType: PaymentType.LevelPayment,
                    startDate:
                    loanStartDate.PlusMonths(1).ToDateTimeUnspecified()
                    ),
                GetTestPaymentSchedule(
                    endDate: percentagePaymentsStartDate
                    .PlusMonths(1)
                    .ToDateTimeUnspecified(),
                    paymentFrequency: PaymentFrequency.Monthly,
                    paymentAmount: 0.1m,
                    paymentType: PaymentType.PrincipalPercentage,
                    startDate:
                    percentagePaymentsStartDate.ToDateTimeUnspecified()
                    ),
            };
            var expected = new List <AmortizationScheduleItem>
            {
                new AmortizationScheduleItem
                {
                    Date             = loanStartDate.PlusMonths(1).ToDateTimeUnspecified(),
                    Interest         = 25.47945m,
                    Principal        = 74.52055m,
                    RemainingBalance = 2925.47945m,
                },
                new AmortizationScheduleItem
                {
                    Date             = percentagePaymentsStartDate.ToDateTimeUnspecified(),
                    Interest         = 12.02252m,
                    Principal        = 292.54795m,
                    RemainingBalance = 2632.93151m,
                },
                new AmortizationScheduleItem
                {
                    Date             = loanStartDate.PlusMonths(2).ToDateTimeUnspecified(),
                    Interest         = 9.37756m,
                    Principal        = 90.62244m,
                    RemainingBalance = 2542.30907m,
                },
                new AmortizationScheduleItem
                {
                    Date = percentagePaymentsStartDate
                           .PlusMonths(1)
                           .ToDateTimeUnspecified(),
                    Interest         = 10.44785m,
                    Principal        = 254.23091m,
                    RemainingBalance = 2288.07816m,
                },
                //Automatic bullet payment
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 5, 1),
                    Interest         = 28.83605m,
                    Principal        = 2288.07816m,
                    RemainingBalance = 0m,
                },
            };

            //Act
            var actual = AmortizationCalculator.GenerateAmortizationSchedule(
                loan,
                paymentSchedules
                );

            //Assert
            actual
            .Select(x => new AmortizationScheduleItem
            {
                Date             = x.Date,
                Interest         = TestUtils.RoundDecimal(x.Interest),
                Principal        = TestUtils.RoundDecimal(x.Principal),
                RemainingBalance =
                    TestUtils.RoundDecimal(x.RemainingBalance),
            })
            .Should()
            .BeEquivalentTo(expected, x => x.Excluding(x => x.Schedule));
        }
Beispiel #8
0
        public void GenerateAmSchedule_PaymentTypeIsPrincipalOnly_ShouldGenerateAmSchedule()
        {
            //Assemble
            var levelPrincipalAmount = 300;
            var numberOfPayments     = 3;
            var loan = GetTestLoan(
                amount: levelPrincipalAmount * numberOfPayments,
                interestRate: 0m,
                maturityDate: new DateTime(2001, 5, 1)
                );
            var paymentSchedule = new List <PaymentSchedule>
            {
                GetTestPaymentSchedule(
                    endDate: new DateTime(2001, 4, 1),
                    paymentAmount: levelPrincipalAmount,
                    paymentFrequency: PaymentFrequency.Monthly,
                    paymentType: PaymentType.PrincipalOnly,
                    startDate: new DateTime(2001, 2, 1)
                    )
            };
            var expected = new List <AmortizationScheduleItem>
            {
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 2, 1),
                    Interest         = 0,
                    Principal        = levelPrincipalAmount,
                    RemainingBalance = 600
                },
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 3, 1),
                    Interest         = 0,
                    Principal        = levelPrincipalAmount,
                    RemainingBalance = 300
                },
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 4, 1),
                    Interest         = 0,
                    Principal        = levelPrincipalAmount,
                    RemainingBalance = 0
                },
            };

            //Act
            var actual = AmortizationCalculator.GenerateAmortizationSchedule(
                loan,
                paymentSchedule
                );

            //Assert
            actual
            .Select(x => new AmortizationScheduleItem
            {
                Date             = x.Date,
                Interest         = TestUtils.RoundDecimal(x.Interest),
                Principal        = TestUtils.RoundDecimal(x.Principal),
                RemainingBalance =
                    TestUtils.RoundDecimal(x.RemainingBalance),
            })
            .Should()
            .BeEquivalentTo(expected, x => x.Excluding(x => x.Schedule));
        }
Beispiel #9
0
        public void GenerateAmSchedule_PaymentTypeIsPrincipalPercentage_ShouldGenerateAmSchedule()
        {
            //Assemble
            var loan = GetTestLoan(
                amount: 1000,
                interestRate: 0.1m,
                maturityDate: new DateTime(2001, 5, 1)
                );
            var paymentSchedule = new List <PaymentSchedule>
            {
                GetTestPaymentSchedule(
                    endDate: new DateTime(2001, 4, 1),
                    paymentAmount: 0.2m,
                    paymentFrequency: PaymentFrequency.Monthly,
                    paymentType: PaymentType.PrincipalPercentage,
                    startDate: new DateTime(2001, 2, 1)
                    )
            };
            var expected = new List <AmortizationScheduleItem>
            {
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 2, 1),
                    Interest         = 8.49315m,
                    Principal        = 200,
                    RemainingBalance = 800
                },
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 3, 1),
                    Interest         = 6.13699m,
                    Principal        = 160,
                    RemainingBalance = 640
                },
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 4, 1),
                    Interest         = 5.43562m,
                    Principal        = 128,
                    RemainingBalance = 512
                },
                //Automatic bullet payment
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 5, 1),
                    Interest         = 4.20822m,
                    Principal        = 512,
                    RemainingBalance = 0
                }
            };

            //Act
            var actual = AmortizationCalculator.GenerateAmortizationSchedule(
                loan,
                paymentSchedule
                );

            //Assert
            actual
            .Select(x => new AmortizationScheduleItem
            {
                Date             = x.Date,
                Interest         = TestUtils.RoundDecimal(x.Interest),
                Principal        = TestUtils.RoundDecimal(x.Principal),
                RemainingBalance =
                    TestUtils.RoundDecimal(x.RemainingBalance),
            })
            .Should()
            .BeEquivalentTo(expected, x => x.Excluding(x => x.Schedule));
        }
Beispiel #10
0
        public void GenerateAmSchedule_LevelPaymentIsLessThanInterest_ShouldPayAsMuchInterestAsPossible()
        {
            //Assemble
            var loan = GetTestLoan(
                amount: 1000000,
                interestRate: 0.5m,
                maturityDate: new DateTime(2001, 5, 1)
                );
            var paymentSchedule = new List <PaymentSchedule>
            {
                GetTestPaymentSchedule(
                    endDate: new DateTime(2001, 4, 1),
                    paymentAmount: 500m,
                    paymentFrequency: PaymentFrequency.Monthly,
                    paymentType: PaymentType.LevelPayment,
                    startDate: new DateTime(2001, 2, 1)
                    )
            };
            var expected = new List <AmortizationScheduleItem>
            {
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 2, 1),
                    Interest         = 500,
                    Principal        = 0,
                    RemainingBalance = 1000000
                },
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 3, 1),
                    Interest         = 500,
                    Principal        = 0,
                    RemainingBalance = 1000000
                },
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 4, 1),
                    Interest         = 500,
                    Principal        = 0,
                    RemainingBalance = 1000000
                },
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 5, 1),
                    Interest         = 162883.56164m,
                    Principal        = 1000000,
                    RemainingBalance = 0m
                },
            };

            //Act
            var actual = AmortizationCalculator.GenerateAmortizationSchedule(
                loan,
                paymentSchedule
                );

            //Assert
            actual
            .Select(x => new AmortizationScheduleItem
            {
                Date             = x.Date,
                Interest         = TestUtils.RoundDecimal(x.Interest),
                Principal        = TestUtils.RoundDecimal(x.Principal),
                RemainingBalance =
                    TestUtils.RoundDecimal(x.RemainingBalance),
            })
            .Should()
            .BeEquivalentTo(expected, x => x.Excluding(x => x.Schedule));
        }
Beispiel #11
0
        public void GenerateAmSchedule_PaymentTypeIsLevelPayment_ShouldGenerateAmSchedule()
        {
            //Assemble
            var loan = GetTestLoan(
                amount: 1000,
                interestRate: 0.1m
                );
            var paymentSchedule = new List <PaymentSchedule>
            {
                GetTestPaymentSchedule(
                    endDate: new DateTime(2001, 4, 1),
                    paymentAmount: 338.9m,
                    paymentFrequency: PaymentFrequency.Monthly,
                    paymentType: PaymentType.LevelPayment,
                    startDate: new DateTime(2001, 2, 1)
                    )
            };
            var expected = new List <AmortizationScheduleItem>
            {
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 2, 1),
                    Interest         = 8.49315m,
                    Principal        = 330.40685m,
                    RemainingBalance = 669.59315m
                },
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 3, 1),
                    Interest         = 5.13660m,
                    Principal        = 333.76340m,
                    RemainingBalance = 335.82976m
                },
                new AmortizationScheduleItem
                {
                    Date             = new DateTime(2001, 4, 1),
                    Interest         = 2.85225m,
                    Principal        = 335.82976m,
                    RemainingBalance = 0m
                }
            };

            //Act
            var actual = AmortizationCalculator.GenerateAmortizationSchedule(
                loan,
                paymentSchedule
                );

            //Assert
            actual
            .Select(x => new AmortizationScheduleItem
            {
                Date             = x.Date,
                Interest         = TestUtils.RoundDecimal(x.Interest),
                Principal        = TestUtils.RoundDecimal(x.Principal),
                RemainingBalance =
                    TestUtils.RoundDecimal(x.RemainingBalance),
            })
            .Should()
            .BeEquivalentTo(expected, x => x.Excluding(x => x.Schedule));
        }
Beispiel #12
0
        public void GenerateAmSchedule_PaymentTypeIsInterestOnly_ShouldGenerateAmSchedule()
        {
            //Assemble
            var startDate = new LocalDate(2001, 1, 1);
            var loan      = GetTestLoan(
                accrualBasis: AccrualBasis.Thirty360,
                amount: 1000,
                interestRate: 0.5m,
                interestAccrualStartDate: startDate.ToDateTimeUnspecified()
                );
            var monthlyDate   = startDate.PlusMonths(1).ToDateTimeUnspecified();
            var quarterlyDate = startDate.PlusMonths(3).ToDateTimeUnspecified();
            var semiDate      = startDate.PlusMonths(6).ToDateTimeUnspecified();
            var annualDate    = startDate.PlusYears(1).ToDateTimeUnspecified();
            var expected      = new List <AmortizationScheduleItem>
            {
                new AmortizationScheduleItem
                {
                    Date = monthlyDate,
                    //1 month of interest
                    Interest = loan.Amount * loan.InterestRate / 12
                },
                new AmortizationScheduleItem
                {
                    Date = quarterlyDate,
                    //2 months of interest
                    Interest = loan.Amount * loan.InterestRate / 6
                },
                new AmortizationScheduleItem
                {
                    Date = semiDate,
                    //3 months of interest
                    Interest = loan.Amount * loan.InterestRate / 4
                },
                new AmortizationScheduleItem
                {
                    Date = annualDate,
                    //6 months of interest
                    Interest = loan.Amount * loan.InterestRate / 2
                }
            };
            var paymentSchedules = new List <PaymentSchedule>
            {
                GetTestPaymentSchedule(
                    endDate: monthlyDate,
                    paymentFrequency: PaymentFrequency.Monthly,
                    startDate: monthlyDate
                    ),
                GetTestPaymentSchedule(
                    endDate: quarterlyDate,
                    paymentFrequency: PaymentFrequency.Quarterly,
                    startDate: quarterlyDate
                    ),
                GetTestPaymentSchedule(
                    endDate: semiDate,
                    paymentFrequency: PaymentFrequency.SemiAnnual,
                    startDate: semiDate
                    ),
                GetTestPaymentSchedule(
                    endDate: annualDate,
                    paymentFrequency: PaymentFrequency.Annual,
                    startDate: annualDate
                    )
            };

            //Act
            var actual = AmortizationCalculator.GenerateAmortizationSchedule(
                loan,
                paymentSchedules
                );

            //Assert
            actual
            .Select(x => x.Date)
            .Should()
            .Equal(expected.Select(x => x.Date));
            actual
            .Select(x => TestUtils.RoundDecimal(x.Interest))
            .Should()
            .Equal(expected.Select(x => TestUtils.RoundDecimal(x.Interest)));
        }