I have had many requests for a Visual Studio solution project with the APR code and unit tests in. I have open sourced the code and put it onto Codeplex to make it easy for you to access.
In this article I want to discuss Annual Percentage Rates (APR) and how you calculate them including some sample code. APR is a term you will see on several different lending products including loans, overdrafts, credit cards and mortgages. It is a legal requirement to show the APR on products where you borrow money, (certainly in the UK). The APR is meant to make it easier to make fairer comparisons of different products. To make things even more confusing there are 2 types of APR, Personal APR and Typical APR.
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 interestoninterest 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, depending on installment lending options you use. 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. Advance means this is money being paid out on the loan and Payment is a payment being made to pay down your loan.
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.

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

 SinglePaymentCalculation – This method is the simple calculation usable when there is only one advance and one payment. The payment is the total amount to pay in a single instalment. The DaysAfterAdvance 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.

 Calculate – Once you have added any payments and additional advances you call this method. As this is an iterative method, adding a guess 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.

 AddInstalment – The AddInstalment() method is used to add an instalment to the loan. An instalment can either be an additional advance or a payment. The amount 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 InstalmentType parameter identifies whether this is an advance or a payment against the loan.

 AddRegularInstalments – The AddRegularInstalments() method is used if you want to add multiple payments of the same amount at regular intervals. The amount parameter is the amount of the regular payment. The numberOfInstalments parameter is the total number of instalments required. The instalmentFrequency parameter is an enumeration of the most regularly used payment frequencies. It bases the split on a 365.25 day year. The daysAfterFirstAdvancefirstInstalment 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.
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.
For anyone reading this article in a country other than the UK, it would be interesting to hear if there are any differences in how you have to calculate APR’s.
If you want to download the source code and unit tests (tests cover each of the examples in this article) then you can grab the code from here.
Very useful article. I have a slight confusion over one thing and I’d be interested to know your thoughts.
I came across your article after doing this myself. I was trying to understand the values in the formula. In the FCA formula (shown in the little extract above) the bottom two items in the ‘where’ part don’t actually seem to appear in the equations. The two values referred to as tK and tK’, looking at your code it looks like these are actually used as the powers in the equation. Can you clarify ?
You are quite right. For some reason the t is missing from the graphic which has been taken directly from the source page.
Thanks for the reply, did you find a definition of ‘relevant date’ which seems also a bit vague. I’m also curious about your successive approximation algorithm. I note you mention that starting with a guess just below the correct answer will make it works fast. How did you arrive at halving or doubling the ‘amountToAdd’ depending on whether your ‘rateToTry’ is too high or too low ? Most simple successive approximations work by moving in ever decreasing steps.
‘Relevant date’ is the date of the first advance or day zero as it is sometimes called.
The code will work without the guess being added by starting at zero, if it was to use the ‘ever decreasing steps’ method what would be default first value of movement? If the guess passed in was actually above the correct answer and it used the ‘ever decreasing steps’ method it would never end. The ‘halving or doubling method’ covers both these scenarios.
Calculating the apr seems impossiblle for an average intelligence person like me.. Is there no simple way to work it out? My brain hurts…
Depends what you mean. If you are just struggling to understand the equation it can be explained in steps. But if you are hoping for a simple formula that you could put into a calculator then, yes, you are right, if the APR is the unknown value the formula would be next to impossible to do by hand, it requires a computer solution. It is a bit simpler if you know the APR and want, say, the amount of the monthly repayment but even then it is still a computer job really.
Thanks for this, it was really helpful. The only thing is, I’m getting weird results on loan terms other than 12 months. Can you confirm the calculator handles them correctly? Cheers
It should do yeah. This was written by one of my developers when I worked at Dollar Financial and we had loan terms from 1 week upwards. Have you tried the test cases that were in the article?
I managed to get it working by dividing the advance and payment totals by the number of payments and multiplying by 12. This solution works for monthly repayments. Thanks
You don’t need to modify any values to make it work for longer terms as demonstrated by the examples. In fact, modifying any original values before using the calculator may have adverse affects.
Sent from my iPhone
>
In my early tests I was modifying values BEFORE the calculation was run, and as you said it was incorrect. Instead I change them after summing the totals (line 36 of APRCalculator.Calculate())
10.3.5 specifies that if time between the relevant date and the event is even months, it’s counted in twelfths of a year. I see that you use 365.25/12 as days between for monthly. While this might work when it’s one month to the first payment, I think it fails otherwise. Let me offer a simple twopayment loan, advancing 200 on Jan 1 2011, with first payment of 125 on Feb 11 and second on Mar 11. Then the equation to be solved is: 200 = 125 * ((1 + r)^41/365.25 + (1 + r)^69/365.25). It appears your code would use 71.4375 instead of 69 for the numerator in the time to the second payment.
It gets worse if I move the payments to the 12th: With 42 and 70 days respectively, those are even weeks, so the times become 6/52 and 10/52. Have I read the regulation incorrectly?
Here’s where I got the reg: http://fshandbook.info/FS/html/FCA/MCOB/10/3