How we built interest
Explore the concept of interest, the technicalities in building accurate interest calculation on our banking platform, and how cross-functional collaboration is important for successful product builds.
Money doesn’t grow on trees—but it does grow in bank accounts that pay interest.
In our blog on client money accounts, we explained that not all financial institutions are authorised to pay interest to their customers. But as a bank, we are allowed to do so. Since we built our own ledger and banking infrastructure from the ground up, we also had to build our own interest capability so we can pay interest on the funds our customers hold with us.
Let’s take a look at what interest is, why it makes money grow, and how our teams worked together to build interest on our platform.
What is interest?
Interest is the price we pay when we borrow money (like when we take out a mortgage), or the price we are paid when we lend it out (like when we put it in a savings account, which is essentially “lending” it to our bank). This price is a function of both the amount of money we lend or borrow, as well as the duration of the loan.
But why do we have to pay this price? The answer is time preference: the idea that we generally prefer to get things sooner rather than later. Most people take out loans because they would prefer not to wait till they’ve saved enough money to pay upfront for what they want. The same is true for money that people expect to be paid back: receiving £100 today is more valuable than receiving £100 in a year's time (this is the time value of money).
So simply put, interest is “the price of time”— and as Edward Chancellor writes in his book of the same title:
“Interest is a charge for the use of money over a certain period of time [because] lending takes place across time”.
Why money grows
Long before the invention of paper money and metal coins, loans were denominated in commodities like silver and barley, and both principal (the amount borrowed) and interest had to be repaid in kind. One reason why interest was charged on these loans was the assumed productivity of nature: cattle produce more cattle, seeds produce more seeds, crops yield more crops. If I loan you a bag of seeds, and you use those seeds to grow a bountiful field of barley, I expect to reap a portion of that bounty when the time comes to repay me. The passage of time—from offspring to livestock, from seeds to harvest—has always been an essential component for pricing loans.
Although interest has now been abstracted away from its roots in the natural world, nature still shapes our understanding of production and the opportunity cost of loans. It is no coincidence that many financial terms, such as yield and capital, originally come from farming. Money might have never grown on trees, but the idea of interest itself seems to come from how plants and animals reproduce over time.
Fast forward to the present: money and interest now grow in computer systems. The passage of time is now measured using synchronised digital clocks, and no longer by tracking the moon and the sun. Yet, the relationship between time and growth remains the same: interest accrual (interest earned but not yet paid) is analogous to letting a crop grow; interest capitalisation (interest added back to the principal) is like harvest time.
When you open an account at Griffin, we accrue interest daily and pay interest monthly into that account. Every night, we calculate how much interest you earned during the previous day by checking your account balance at a specific point in time. Much like a crop will grow when it gets enough water, sunlight and nutrients from the soil, your money at Griffin will grow when you hold a positive balance.
How we worked together
Griffin is both a technology company and a bank—a hybrid organisation that blends engineering and finance into delightful products. We always strive to mix the right elements to turn domain knowledge into code, this time to build what sits at the core of the alchemy of banking.
Leaving chemical metaphors aside, we built our interest capability in roughly three stages:
- writing an engineering Request for Comments (RFC)
- writing layers of code to implement business processes
- running user acceptance tests against financial requirements
Before the first-ever line of code is written on any project, we write an RFC—a document and process that reflects our writing culture and core value of thoughtfulness. On this project, we spent around four weeks analysing interest accrual and capitalisation as business processes, designing a layered architecture, researching alternative rounding methods, comparing ways to calculate daily rates, and agreeing on key definitions.
Layers below the soil
We followed the philosophy of stratified design to plan the development process and organise our interest capability as a layered architecture. Much like soil is made of horizontal layers that support the growth of roots and crops, we designed our interest subsystem in layers of varying complexity and aggregation—from standalone balances and interest rates to end-of-day scheduled jobs and monthly capitalisation processes. We’ll describe these layers top-down but we actually developed them bottom-up, in the best spirit of our programming language.
The topmost layer is in charge of listing and paginating all interest-bearing accounts in the system and instructing each of them to initiate daily processing. Intermediate layers are responsible for fetching overnight balances and related interest rates, orchestrating accrual and capitalisation at the end of each day or month, handling errors and exceptions, and deduplicating requests to facilitate idempotent retries.
The bedrock of it all is the interest calculation logic that computes daily accruals for individual accounts—multiplying the daily rate by its overnight balance (among other things covered later). While we got feedback from engineers on the RFC’s implementation alternatives, we used spreadsheets to prototype examples of interest accrual, capitalisation and compounding to verify our calculations with the Finance team. This helped us build confidence in our maths, and agree on a testing strategy to prove that our design was correct.
Getting the numbers right
Rounding is the process of turning a numeric value into a less precise value by approximating its decimal places (e.g. 3.14159 → 3.1416) or whole digits (e.g. 99 → 100). For bank accounts, rounding is necessary because customers’ balances must always be in proper denominations that can be withdrawn in cash (e.g. whole pounds and pence in the UK). This means that interest accruals must be rounded before they are recorded in our ledger or paid into a customer’s account.
This may sound straightforward, but when it comes to accurately calculating interest, there are several ways to approach rounding. If we chose to always round up or always round down to the nearest proper denomination, we would always end up paying more or less than we should have. And while the difference may seem miniscule, over time and depending on the individual balances and interest rates, that difference could add up to tangible losses for our customers or for us.
That’s why we decided to round accruals using a method called “half to even” or “bankers’ rounding”. Using this method, our system rounds up or down depending on what the nearest even penny is. For example, if a customer accrues a daily interest of 20.5p, we round it down to 20p—because 20 is the nearest even number to 20.5. But if instead a customer accrues 19.5p, we round it up to 20p. This eliminates the bias present in other methods.
Be deserving of trust
We chose this rounding method because we believe it delivers the fairest outcome for both our customers and Griffin. But you may wonder, what happens to the difference between the accrued amount and its rounded approximation? When we round numbers, we lose information; but when we round money, we can’t lose even a fraction of a penny.
So what happens to that fraction after rounding? The answer is that we save it as a “carry forward” to the next day. You can think of the carry forward as a tiny coin purse in which we keep up to half a penny next to your total accrued amount. The next day, we take the contents of the purse out, add them to that day’s interest amount, and round the result again to determine the day’s accrual in pounds and pence. The amount that remains after rounding goes back into the purse to be used again on the next day.
For example, when we round 20.5p down to 20p, we save 1/2p and add it to the next day’s accrual. Likewise, when we round 19.5p up to 20p, we save -1/2p and deduct it from the next day’s accrual. That way we make sure that, as days pass, our customers always get the exact amount they have earned.
Keeping things rational
You may have noticed that we expressed half a penny as 1/2 instead of 0.5 in the example above. Although these amounts are essentially the same and behave similarly when adding things up, using decimals can produce different results when doing multiplication or division. For example, turning 1/3 into a decimal number results in a non-terminating decimal expansion (0.3333…), an infinite number of decimal places that must be truncated to a finite approximation. (The same is true when dividing an annual rate of 5.25% by 365 to get a daily rate).
The need for truncation is similar to the problem of rounding to whole pounds and pence (i.e. two decimal places), but is more consequential because it applies to the carry forward amounts that we save from one day to the next. If we tracked fractions of a penny using decimal numbers, we would have to choose a number of significant figures to keep (i.e. how many “3”s in 0.3333…) and then ignore the rest. This would imply a lower accuracy in our calculations, and even though the amounts in question seem tiny, tiny inaccuracies compounding every day can lead to large errors over time.
So, what if we didn’t use decimal numbers at all and kept all fractions of pennies as fractions instead? This was one of the key insights that came out of the RFC process and showcased the value of getting feedback from different teams that might not be involved in the development stage. Using Clojure’s built-in Ratio type—one of the superpowers of the programming language we use at Griffin—we were able to achieve lossless accuracy in tracking fractions of pennies, and avoided the cumulative errors that would have come with decimal rounding.
Testing before the harvest
A fun side effect of deciding to express carry forwards as fractions was that we had to write our own rounding function for fractional numbers, because the Clojure programming language and underlying Java platform don’t have built-in support for that. We used a combination of quotients and remainders alongside the absolute value function to achieve the same behaviour as the “half_even” rounding mode for big integers.
To ensure the mathematical correctness of our custom rounding method, we wrote a comprehensive suite of example-based and property-based tests against the default rounding mode supported in Clojure. We started with simple hardcoded scenarios calculated manually using spreadsheets, which were shared with the Finance team and verified in multiple rounds of feedback. Then we moved to designing random scenarios to assert a wide range of properties and invariants in generative tests—such as “carry forwards must always be between -1/2 and 1/2”.
But as much as automated tests help us engineers build confidence in our technical solution, we believe the best form of confidence comes from multiple disciplines working together. We shaped our initial understanding and reference models of accrual and compounding by working together with the Finance team, and ultimately verified that everything worked as expected when they gave Product and Engineering the thumbs up during user acceptance testing. No automated testing suite could have achieved that level of confidence and quality on its own—this is the value of a culture that places a premium on cross-team collaboration.
Wrapping it up
Now that interest is up and running on our platform, we can confidently say this build was successful because of the depth of research, planning and documentation that went into our Request for Comments (RFC) and the deep collaboration with our Product and Finance teams.
If you are interested in joining a culture that values thoughtful writing and collaboration across different disciplines, check out our careers page for open roles.