Whenever I log into Coinbase I am greeted with a dashboard showing the latest prices for Bitcoin/Ethereum.
Even though knowing the latest price is useful, the question I often ask myself is “What would be my gains/losses if I were to sell now?”. For example the BTC price might be 600€ and that might be a 10% increase from the previous day, but if I bought BTC a month ago for 660€ then I might consider not selling, due to a 10% portfolio loss, even though the currency price has recently increased.
Coinbase has a comprehensive API so I set out to build a little library to address this question. I think it is important that products have such extensive APIs, because it gives me the ability to extend a product to address my needs without asking anybody for permission. With cryptocurrencies besides this application level API we also get a data level API (i.e. programmable money) which allows for more complex customization use cases than the one I am exploring here.
I wanted to share a couple of things I learned/observed while implementing this library.
FIFO Accounting
The formula to calculate the percentage change looks like: (current portfolio value – portfolio cost) / portfolio cost. The tricky part about calculating the portfolio cost is that I might hold coins which were bought at different prices, and that I might have sold a couple in the meantime as well.
One of the methods to calculate the portfolio cost given these constraints is to use FIFO accounting. In this scenario, FIFO accounting works by assuming that the first coins bought are the first ones sold, and that the coins bought later are bought later.
An example:
Transactions:
Day 1: Buy 5 BTC at 600€
Day 2: Buy 8 BTC at 660€
Day 3: Sell 3 BTC at 700€
Portfolio inventory on day 4:
2 BTC bought at 600€ (we used to have 5 but 3 were sold on day 3)
8 BTC bought at 660€
Portfolio cost on day 4:
2×600€ + 8×660€ = 6480€
ImmutableStruct
My most common use for immutable-struct is to create value objects.
In this library I also used it while I was still discovering the object collaborators of a given method. Occasionally instead of using a RSpec stub, I will just create the type using immutable-struct and then upgrade it to a class when I start adding more behaviour to that type.
This is effectively what happened in this commit, I first created Transaction
as a ImmutableStruct
so I could test AssetConverter
but while implementing AssetConverter#convert
I noticed it would be useful if Transaction
had a price
method, so it got “upgraded” to a normal class.
Figuring things along the way
When I started working on this I had a general idea that I would have transactions, and a “liquidation” object that would implement the FIFO accounting procedure and calculate the gains/losses.
As I started adding test cases to Liquidation
I noticed that its tests were getting complicated because I was testing entirely different things, so I started extracting this unrelated behaviour to separate objects. For example, liquidation became a class that operated on the processed inventory of coins instead of a class that operated on the coin transactions.
Potentially I could have thought of all these issues up front, and come up with the final design. I find it easier and more productive to have a general sense of the main behaviour I need, and then evolve design as I get a better understanding of the problem, and that tends to happen when I add test cases through TDD.
Naming
Naming is always hard. Most of the inspiration for the terms used came from reading the API documentation, reading about multiple accounting methods and reading about multiple ways to calculate stock portfolio returns – so getting acquainted with the domain. The dictionary and its thesaurus section always come handy as well.
While I really like to get the terms right, early in the process my main goal is to get the tests and behaviour right because after I have good tests, changing names is easy. Also it is easier to notice inconsistencies after I get a clear big picture.
That is probably why I have a couple commits renaming a ton of things at the end. If the commit history ends up getting confusing, it can always be rewritten.
Private attr_reader
I have this habit of using private attr_reader
so I can access instance variables using a method instead of with the @
prefix (i.e. @transaction
vs. transaction
). I probably discovered this in a book or screencast (but can’t remember which).
I probably prefer seeing everything as methods due to syntax highlighting or fewer characters to type, but I don’t have a strong opinion on the topic.
Closing thoughts
Over time as we start getting more experienced within a particular subject we start to develop an inclination towards certain processes and tools. I wanted to share some of the programming tendencies I have by looking into a specific example. These are usually things I take for granted and are really “simple things” but they vary from person to person so, I figured it would be fun to share them.