CodePlexProject Hosting for Open Source Software

**Project Description**

This project contains code to calculate the Annual Percentage Rate for a loan and it's Instalments.

The APR is essentially how much your borrowing will cost over the period of an average year, over the term of your debt. It takes into account interest charged as well as any additional fees (such as arrangement fees, or annual fees) you’ll have to pay. It also considers the frequency with which interest is charged on your borrowing, as this as an impact on how much you will pay as well.

*Personal APR*

As mentioned above, there are 2 types of APR, Personal and Typical. The personal APR is quite straight forward as this is the percentage ** you will actually pay **in your own circumstance. For a
product like a mortgage this will generally be the same as the APR that is advertised as with a mortgage you are either accepted at that rate or not as the rate doesn't change along with your risk profile, which may happen with a loan or credit card where
you may be subject to risk based pricing.

When you take a loan or credit card though you should check the personal APR as this may be different to the rate advertised.

*Typical / Representative APR*

The typical (representative) APR is the rate of interest you will pay on some forms of borrowing like a credit card or loan. In order that these products can be compared prior to you applying for them (as you will never know what rate you are going to pay until you are accepted), they are required to display a “Representative APR” in any advertising material.

The typical APR is an advertised APR that a minimum percentage of customers (who are accepted) will pay. Under the current EU rules this minimum percentage is at 51%. The APR may also differ depending on the size of the loan. So for example a loan between £1000 and £3999 may be charged at 15% APR where a loan from £4000 to £6999 may be charged at 10%. Your personal APR may differ to this Typical APR based on your credit rating.

*Short Term Loans*

APR is all well and good but it starts to trip up for loans which are paid over very short payment terms and are charged based on fees instead of interest. This is why when you see adverts for payday loans they show a typical APR of anything from 200%-4000% based on how long the loan is for, and these loans can be as short as 7 days.

Naturally, no one will ever pay 4000% on one of these loans that just would not be fair; these loans are designed to be short term, as in a week to a month, not paid over a year.

The APR equation not only multiplies the actual period of interest up to a year’s duration, but also compounds it, assuming interest-on-interest many times over. The result is a grossly distorted number that bears no relation to the actual interest involved. This, I find, makes it quite confusing to a customer. But the rules are the rules. So in a nutshell, as the length of the loan decreases, the actual APR goes up.

**Calculating APR**

The process for calculating an APR, in the UK certainly, is regulated by the Financial Conduct Authority (the replacement for the FSA). So, I would like to introduce the **FCA MCOB
10.3 Formula for calculating APR.**

YOWSERS, MATHS!! Run Away!! For anyone not comfortable with formulas that can be a little intimidating but what I want to do is go over an implementation of this formula written in C#. I would like to say I wrote this bit of code myself, but it was actually developed by a developer on my team, Graham, and it is quite a nice solution.

Before we get to the bit that does all the work we have a few supporting classes/objects.

`using` `System;` `using` `System.Collections.Generic;` `using` `System.Linq;` `namespace` `Finance` `{` ` ` `internal` `class`
`Instalment` ` ` `{` ` ` `public`
`double` `Amount { ` `get` `; ` `set` `; }` ` ` `public`
`double` `DaysAfterFirstAdvance { ` `get` `; `
`set` `; }` ` ` `internal`
`double` `Calculate(` `double` `APR)` ` ` `{` ` ` `double`
`divisor = Math.Pow(1 + APR, DaysToYears);` ` ` `var`
`sum = Amount / divisor;` ` ` `return`
`sum;` ` ` `}` ` ` `private`
`double` `DaysToYears` ` ` `{` ` ` `get` ` ` `{` ` ` `return`
`DaysAfterFirstAdvance / 365.25d;` ` ` `}` ` ` `}` ` ` `}` `}` |

This ** Instalment** class represents a payment or advance on your loan including an amount and the number of days after your first payment advance.

`using` `System;` `using` `System.Collections.Generic;` `using` `System.Linq;` `namespace` `Finance` `{` ` ` `public` `enum` ```
InstalmentFrequency
``` ` ` `{` ` ` `Daily = 0,` ` ` `Weekly = 1,` ` ` `Fortnightly = 2,` ` ` `FourWeekly = 3,` ` ` `Monthly = 4,` ` ` `Quarterly = 5,` ` ` `Annually = 6` ` ` `}` `}` |

This ** InstalmentFrequency** enumeration represents an instalment frequency. That is the frequency that you are going to make payments on your loan. In a lot of traditional loans this would
be a monthly instalment.

`using` `System;` `using` `System.Collections.Generic;` `using` `System.Linq;` `namespace` `Finance` `{` ` ` `public` `enum` ```
InstalmentType
``` ` ` `{` ` ` `Payment = 0,` ` ` `Advance = 1` ` ` `}` `}` |

** InstalmentType** represents the type of instalment that this is.

`using` `System;` `using` `System.Collections.Generic;` `using` `System.Linq;` `namespace` `Finance` `{` ` ` `public` `class` ```
APRCalculator
``` ` ` `{` ` ` `public`
`APRCalculator(` `double` `firstAdvance)` ` ` ```
:
``` `this` `(firstAdvance, ` `new` ```
List<Instalment>(),
``` `new` `List<Instalment>())` ` ` `{` ` ` `}` ` ` `internal`
`APRCalculator(` `double` `firstAdvance, List<Instalment> advances, List<Instalment> payments)` ` ` `{` ` ` `_Advances = advances;` ` ` `_Payments = payments;` ` ` `_Advances.Add(` `new`
`Instalment() { Amount = firstAdvance, DaysAfterFirstAdvance = 0 });` ` ` `}` ` ` `public`
`double` `SinglePaymentCalculation(` `double` ```
payment,
``` `int` `DaysAfterAdvance)` ` ` `{` ` ` `return`
`Math.Round((Math.Pow(_Advances[0].Amount / payment, (-365.25 / DaysAfterAdvance)) - 1) * 100, 1, MidpointRounding.AwayFromZero);` ` ` `}` ` ` `public`
`double` `Calculate(` `double` `guess = 0)` ` ` `{` ` ` `double`
`rateToTry = guess / 100;` ` ` `double`
`difference = 1;` ` ` `double`
`amountToAdd = 0.0001d;` ` ` `while`
`(difference != 0)` ` ` `{` ` ` `double`
`advances = _Advances.Sum(a => a.Calculate(rateToTry));` ` ` `double`
`payments = _Payments.Sum(p => p.Calculate(rateToTry));` ` ` `difference = payments - advances;` ` ` `if`
`(difference <= 0.0000001 && difference >= -0.0000001)` ` ` `{` ` ` `break` `;` ` ` `}` ` ` `if`
`(difference > 0)` ` ` `{` ` ` `amountToAdd = amountToAdd * 2;` ` ` `rateToTry = rateToTry + amountToAdd;` ` ` `}` ` ` `else` ` ` `{` ` ` `amountToAdd = amountToAdd / 2;` ` ` `rateToTry = rateToTry - amountToAdd;` ` ` `}` ` ` `}` ` ` `return`
`Math.Round(rateToTry * 100, 1, MidpointRounding.AwayFromZero);` ` ` `}` ` ` `public`
`void` `AddInstalment(` `double` `amount, `
`double` `daysAfterFirstAdvance, InstalmentType instalmentType = InstalmentType.Payment)` ` ` `{` ` ` `var`
`instalment = ` `new` `Instalment() { Amount = amount, DaysAfterFirstAdvance = daysAfterFirstAdvance };` ` ` `switch`
`(instalmentType)` ` ` `{` ` ` `case`
`InstalmentType.Payment:` ` ` `_Payments.Add(instalment);` ` ` `break` `;` ` ` `case`
`InstalmentType.Advance:` ` ` `_Advances.Add(instalment);` ` ` `break` `;` ` ` `}` ` ` `}` ` ` `private`
`static` `double` `getDaysBewteenInstalments(InstalmentFrequency instalmentFrequency)` ` ` `{` ` ` `switch`
`(instalmentFrequency)` ` ` `{` ` ` `case`
`InstalmentFrequency.Daily:` ` ` `return`
`1;` ` ` `case`
`InstalmentFrequency.Weekly:` ` ` `return`
`7;` ` ` `case`
`InstalmentFrequency.Fortnightly:` ` ` `return`
`14;` ` ` `case`
`InstalmentFrequency.FourWeekly:` ` ` `return`
`28;` ` ` `case`
`InstalmentFrequency.Monthly:` ` ` `return`
`365.25 / 12;` ` ` `case`
`InstalmentFrequency.Quarterly:` ` ` `return`
`365.25 / 4;` ` ` `case`
`InstalmentFrequency.Annually:` ` ` `return`
`365.25;` ` ` `}` ` ` `return`
`1;` ` ` `}` ` ` `public`
`void` `AddRegularInstalments(` `double` ```
amount,
``` `int` ```
numberOfInstalments, InstalmentFrequency instalmentFrequency,
``` `double` `daysAfterFirstAdvancefirstInstalment = 0)` ` ` `{` ` ` `double`
`daysBetweenInstalments = getDaysBewteenInstalments(instalmentFrequency);` ` ` `if`
`(daysAfterFirstAdvancefirstInstalment == 0)` ` ` `{` ` ` `daysAfterFirstAdvancefirstInstalment = daysBetweenInstalments;` ` ` `}` ` ` `for`
`(` `int` `i = 0; i < numberOfInstalments; i++)` ` ` `{` ` ` `_Payments.Add(` `new`
`Instalment() { Amount = amount, DaysAfterFirstAdvance = daysAfterFirstAdvancefirstInstalment + (daysBetweenInstalments * i) });` ` ` `}` ` ` `}` ` ` `private`
`readonly` `List<Instalment> _Advances;` ` ` `private`
`readonly` `List<Instalment> _Payments;` ` ` `}` `}` |

This ** APRCalculator** class is quite long. I won’t go through it line by line, but I will cover the basic usage and then show some different test cases taken from our unit tests to show how
it works.

This class is very easy to use, but I will reinforce the usage through some worked examples in a bit. The method contains 4 public methods.

– The constructor takes in an amount for the initial payment advance.*APRCalculator Constructor*

This method is the simple calculation usable when there is only one advance and one payment. The*SinglePaymentCalculation*–is the total amount to pay in a single instalment. The*payment*parameter is the number of days between the advance and the payment. The APR returned is to one decimal place (The FCA Standard) in an easy to read format so an APR of 37.20% will return as 37.2.*DaysAfterAdvance*

– Once you have added any payments and additional advances you call this method. As this is an iterative method, adding a*Calculate*slightly below what you think the actual APR will be will speed up the process. If it returns the same amount then the guess is either exactly right or too high. The APR returned is to one decimal place (The FCA Standard) in an easy to read format so an APR of 37.20% will return as 37.2.*guess*

The*AddInstalment*–method is used to add an instalment to the loan. An instalment can either be an additional advance or a payment. The*AddInstalment()*parameter is how much is being advanced or paid on the day given. The daysAfterFirstAdvance parameter is the number of days after the first advance based on the first advance day being day zero. The*amount*parameter identifies whether this is an advance or a payment against the loan.*InstalmentType*

*AddRegularInstalments**–*Themethod is used if you want to add multiple payments of the same amount at regular intervals. The*AddRegularInstalments()*parameter is the amount of the regular payment. The*amount*parameter is the total number of instalments required. The*numberOfInstalments*parameter is an enumeration of the most regularly used payment frequencies. It bases the split on a 365.25 day year. The*instalmentFrequency*parameter is the number of days before the first payment. It defaults to 0 which will set the first payment the same number of days as the frequency sets.*daysAfterFirstAdvancefirstInstalment*

**Examples of Usage**

Now that we have gone over the public interface to the APR Calculator, let’s look at a few examples of its usage. These are taken from our unit tests. Some of these examples are test cases provided by the Consumer Finance Association.

*One Advance with One Payment for One Year Returns One Percent*

var calculator = new APRCalculator(100);

calculator.AddInstalment(101, 365);

var apr = calculator.Calculate();

Assert.AreEqual(1.0d, apr);

Here we have a loan where there is advance of £100 and one instalment for £101 where the payment is made 365 days after the first advance. This gives an APR of 1%

*One Advance with One Payment of Same Returns Zero*

var calculator = new APRCalculator(100);

calculator.AddInstalment(100, 1);

var apr = calculator.Calculate();

Assert.AreEqual(0.0d, apr);

Here we have a cash advance of £100 and a payment of £100 paid the day after the cash advance. This gives an APR of 0%

*Advance £100 with One £125 Payment after 31 Days*

var calculator = new APRCalculator(100);

var apr = calculator.SinglePaymentCalculation(125, 31);

Assert.AreEqual(1286.2d, apr);

Here we have an initial advance of £100, and we add a payment instalment of £125 paid after 31 days. This gives an APR or 1286.2%

*CFA Bank Overdraft Example*

var calculator = new APRCalculator(200);

calculator.AddInstalment(350, 365.25 / 12);

var apr = calculator.Calculate();

Assert.AreEqual(82400.5d, apr);

Here we have an initial advance of £200 and a payment of 350 made one month later. This comes out at an APR of 82400.5%. This is a sobering example before you decide to use an unauthorised overdraft on your bank account.

*CFA Example of a Personal Loan*

var calculator = new APRCalculator(10000);

calculator.AddRegularInstalments(222.44, 60, InstalmentFrequency.Monthly);

var apr = calculator.Calculate();

Assert.AreEqual(12.7d, apr);

In this example we have an initial advance of £10,000. We then have 60 monthly instalments (5 year loan) set up for £222.44 each. This gives an APR of 12.7%. This is most likely what people are used to seeing.

*CFA example of a Short Term Loan*

var calculator = new APRCalculator(200);

calculator.AddInstalment(250, 365.25/12);

var apr = calculator.Calculate();

Assert.AreEqual(1355.2d, apr);

This is the final example I will walk through, but this is for a short term loan. Here the initial advance is £200 and the payment is for £250 paid one month after the advance. For most short term loans, they deal with one off fees and not interest. So in this case the fee is £50 (25%). As the payment term is one month after the initial advance, this makes the APR 1355.2%. This is why I said earlier that the APR for this type of loan is a bit misleading.

I won’t walk through any more specific examples, but the table below shows some other examples.

That concludes this article on APR. I hope you have found it useful. I have first tried to explain in laymen terms what APR is all about and then show a sample implementation of the Financial Conduct Authorities official APR Calculation. The code in this article was written by my colleague Graham who also proof read this article for me.

Last edited Oct 17, 2014 at 8:03 AM by stephenhaunts, version 4