Problem to be solved
I’m not entirely sure that this subject belongs in the NosillaCast but Bart was quite insistent that I write it up, so here I go.
In Programming By Stealth we’ve been working on a little web app that will do currency conversions. Bart gives us a lot of latitude on how we solve the homework challenges, only having an end condition in the requirements. In the first iteration of our web app, the user was to choose a base currency and then choose a selection of countries to show the conversion. At this point, the conversion was simply from 1 unit of the base country to the other countries’ currencies. So for example, 1 New Zealand dollars = how many Mexican Pesos and Danish Krone? (12.08 and 4.44 respectively at this moment if you’re wondering.)
We were to display the answer to the user using what are called Bootstrap Cards. They’re nice little contained areas with the desired information, styled nicely without too much work by the developer.
Once we had that task conquered, he suggested we take it up a notch and allow the user to ask for a specific number of the base unit currency to be converted. As in our previous example to show that 5 New Zealand Dollars is 22.20 Danish Krone and 60.38 Mexican Pesos.
During his review of his solution to the challenge, we were talking about how we rounded the currency conversions to the nearest two decimals. Thinking out loud, I pondered whether all currencies actually use two decimals. Bart responded that he presumed they all did.
@lbutlr on Twitter wrote to us after the episode aired, noting two things. First of all, he found a mistake in Bart’s math on his solution, and second of all he noted that some currencies have no decimal places at all. In fact, the two currencies that showed an error in math on Bart’s solution were both without decimals: Korean Won and Japanese Yen. In both cases, their conversion rate is very high as a ratio to US dollars (1180:1 and 110:1) respectively. Bart’s method of rounding only showed the error when converting to these high ratio currencies. Bart wrote up how he figured out the problem and how he solved it in a blog post on www.bartbusschots.ie/…
@lbutlr’s comment about the decimals got me thinking about whether there’s a way I could know how many decimals each currency used, and if I could programmatically change my code to take it into account. And that’s when Bart said I owed it to the community to write it up when I figured it out. And that’s why we’re here now!
How I designed my solution
As I said, Bart gives us a lot of flexibility in how we solve the problem. He gave us a link to a website that allowed you to fetch data from it for the current exchange rates for 33 countries called api.exchangerate.io. So that’s our source data for the real-time exchange rate.
But on that site, we could only pull the rate and currency code e.g. USD ISK but it did not contain the human-readable currency name, such as US dollar and Iceland Krona. While some people solving the problem simply looked them up and added them manually to their lookup dictionary for the task, I did something slightly more clever (in my humble opinion).
I found the ISO4217 database where all of the currency names and currency codes are defined. I say I found it on my own, which is technically true, but later when I looked back at Bart’s show notes, I discovered he had actually told us about its existence.
So now I’ve got the currency codes and the currency rates in one file, and I’ve got the currency codes and currency names in another file. It took me a while, but I figured out how to manipulate them until I had all three pieces of info in one lookup table: currency name, currency code, and currency rate. That was a big achievement.
Now that I had all three in once place I could look them up and plop them into my cards, allowing me to display 1 in USD converts to Won (KRW): 1180.14. While the math is correct, we want to that to say 1180 instead of 1180.14 thanks to our little friend @lbutlr
Where I found the decimals
I opened the file I’d downloaded from the ISO4217 site to see what other fields might be available to me. I was delighted to find a field that for most currencies said, “MinorUnit”: “2”, but for Korean Won and Japanese Yen said, “MinorUnit”: “0”. I knew I was onto something. I then found that Chile’s secondary currency, Unidad de Fomento, said “MinorUnit”: “4”! I did a search of the Internets and confirmed that this currency does indeed show 4 decimal places. I won’t go through all of the countries that have a different number of decimals, because ISO4217 has 279 currencies, but I did find some with 3 decimals which was also interesting.
Unfortunately of the 33 countries in our lookup table for today’s currency rates, only Won and Yen have other than 2 decimals. I was really hoping to have more just to show off my code if I succeeded.
Since I’d already cracked the code on how to mash the ISO 4217 currency names into the file from exchangerate.io with the currency codes and rates, it was a small matter to add a few lines of code to add in the MinorUnit into and then access and display it.
But I got garbage out! Euro and other currencies incorrectly displayed with no decimals and still others correctly showed 2.
Finding the true source data at iso.org
I dug into my ISO4217 list and found that many many currencies showed a MinorUnit of “null”. The more I looked at this file, the more I realized that it had lots of weird data in it and my source of xe.com was suspect. Not sure how I got this source, but now I went to the official iso.org site (https://www.iso.org/iso-4217-currency-codes.html) and found the official data file which I could either display an XML file or download an XLS. Looking back, I really should have started with the XLS but I figured that since XML is just a text file with some delimiters, it would be easy to adapt the syntax to a JSON file.
That jargon means that the XML file put terms inside angle brackets e.g. <currencyName> instead of quotes like I needed it in JSON: “currency code”. I figured a simple search and replace would be easy. I then realized that the terminology was somewhat different as well. In the XML file it said <CtryNm> but in my JSON format it needed to be simply “name”. This would have been a LOT easier in Excel than in a text editor. Oh well, live and learn, use Excel for everything.
Once I had the data formatted correctly, my mash-sources-together code worked flawlessly, the currency lookups returned the correct answer for decimals and I am now proudly displaying Won and Yen with no decimals.
Even better, if exchangerate.io ever adds a 24th country, like Tunisian Dinars, my tables will automatically display them correctly with 3 decimals.
If you’d like to play with my currency conversion web app, you can find it at https://nosillacast-currency-conversion.glitch.me. I have a warning for you though. It’s a work-in-progress so some parts of it may not be working when you play with it. For example, as of this moment, there’s a tab called Grid that only has static data in it right now, and the toggles on that tab are adding a few things to the first tab. But play with it if you like anyway!