Advanced FIFO Calculator Exercise
Advanced FIFO Calculator Exercise
Background Part I
irrelevant - the only thing that is important is the txn_time of the transaction:
Transaction
txn_time: DATE
other_attributes: ...security, quantity, buy/sell, etc...
We will also initally model the total tax owed as a state record with a globally unique, fully orderable tax_time
attribute as well as a total_amount_owed . For a given TotalTax record, total_amount_owed represents the total tax
TotalTax
tax_time: DATE
total_amount_owed: DECIMAL
1 …
2 …
3 …
4 …
5 …
We can define a total_tax_calculator function which calculates the TotalTax record for a given tax_time by
The simplest and least efficient implementation of this is to always calculate the total_tax from scratch using
fifo_calculator :
total_tax_calculator(Date:tax_time) => {
total_amount_owed = fifo_calculator(transactions)
not familiar with financial accounting should just accept that it is possible to refactor a fifo tax calculator
implementation to be incremental by serializing and deserializng its internal state:
incremental_fifo_calculator(
old_total_amount_owed: DECIMAL,
old_tax_lots: STATE,
new_transactions: List<Transaction>
) => (new_total_amount_owed: DECIMAL, new_tax_lots: STATE)
To understand the relationship between the regular fifo_calculator and the incremental_fifo_calculator ,
// Use previous calculation as starting point and add on remaining two transactions
total_amount_owed_12345, tax_lots_12345 = incremental_fifo_calculator(
old_total_amount_owed: total_amount_owed_123,
old_tax_lots: tax_lots_123,
new_transactions: [ Txn4, Txn5 ]
)
incremental total tax calculation, let’s extend the TotalTax data structure to include it:
TotalTax
tax_time: DATE
total_amount_owed: DECIMAL
tax_lots: STATE
Furthermore, let’s imagine we also have a table/CRUD_style repository of these extended TotalTax records:
tax_time total_amount_owed tax_lots
2 … …
5 … …
In this exercise, we will psuedo-code a smarter version of total_tax_calculator that pulls as few Transaction
records as possible by first checking to see if there are any existing TotalTax records we can use as a starting point for
incremental_fifo_calculator
txn_time other_attributes
1 …
2 …
3 …
4 …
5 …
2 … …
5 … …
Then our smarter total_tax_calculator implementation should behave in the following way
total_tax_calculator(1)
Should not use any existing TotalTax records
Should only pull the txn_time=1 Transaction record
total_tax_calculator(2)
Should use existing TotalTax record for tax_time=2
Should not pull any Transaction records
total_tax_calculator(3)
Should use existing TotalTax record for tax_time=2
Should only pull the txn_time=3 Transaction record
total_tax_calculator(4)
total_tax_calculator(5)
Should use existing TotalTax record for tax_time=5
Should not pull any Transaction records
rewrite history. Unfortunately in the real world we have to deal with being notified about transactions out-of-order. To
accomodate this fact, we will extend the Transaction object with a knowledge_time which represents the actual
Transaction
txn_time: DATE
knowledge_time: DATE
other_attributes: ...security, quantity, buy/sell, etc...
To understand the relationship between txn_time and knowledge_time , consider how the Transaction
1 10 …
1 10 …
2 20 …
1 10 …
2 20 …
4 30 …
1 10 …
2 20 …
4 30 …
5 40 …
1 10 …
2 20 …
3 50 …
4 30 …
5 40 …
TotalTax data structure. Specifically, the knowledge_time of a given TotalTax record implies that it was
calculated using only Transaction records which were created at or before that knowledge_time :
TotalTax
tax_time: DATE
knowledge_time: DATE
total_amount_owed: DECIMAL
tax_lots: STATE
total_tax_calculator(
Date:tax_time,
Date:knowledge_time
) => TotalTax:total_tax
Once again, the simplest and least efficient implementation of this is to always calculate the total_tax from scratch
using fifo_calculator :
total_tax_calculator(
Date:tax_time,
Date:knowledge_time
) => {
total_amount_owed = fifo_calculator(transactions)
}
Exercise 2: Smarter temporal total_tax_calculator
function
In this exercise, we will psuedo-code a smarter version of total_tax_calculator that is knowledge_time -aware
while still pulling as few Transaction records as possible by using existing TotalTax records where possible.
1 10 …
2 20 …
3 50 …
4 30 …
5 40 …
2 20 … …
4 30 … …
Then our temporal total_tax_calculator implementation should behave in the following way
total_tax_calculator(txn_time: 5, knowledge_time: 10)
Should not use any existing TotalTax records
Should only pull the txn_time=1 Transaction record