I glanced, and I found this handbook shallow and - in some areas - even bad advice.
E.g. If I ever see a monetary value stored in something else than integers I'm going to run away screaming (thank you Rust decimals represented as JSON floats). It's always integers unless you have a VERY good reason to do otherwise (though exported view can be in anything, even in weird bitcoded formats).
FX exchange. Resolution of FX isn't a point-in-time thing, things like buyer rate-in-time, seller rate-in-time, agreement, agreement tolerance, agreed upon resolution timestamp come in the effect.
Immutability - that's why you want to have event sourcing everywhere that touches money:
# Resolved stream
A -> B -> E
# Actual stream
A0 -> Edit(A0, A) -> B -> C -> D -> Rollback(B) -> E
Though in the end Fintech != Fintech. I worked at Fintech where money was treated like a baggage, and in other where money was a central point of everything.
oddthink 21 hours ago [-]
> E.g. If I ever see a monetary value stored in something else than integers I'm going to run away screaming (thank you Rust decimals represented as JSON floats). It's always integers unless you have a VERY good reason to do otherwise (though exported view can be in anything, even in weird bitcoded formats).
That really overstates the issue. Whole domains of finance run just fine on doubles.
If you're doing Monte Carlo options pricing over interest rate paths, and you're interested in the risk metrics, like durations, convexity, vega, and so on, no one cares what your rounding convention is. doubles are just fine, thank you. How are you going to force `exp(-rt)cashflow` to be an integer? Or the normal CDF?
Yes, there are domains where ints make sense. But it's certainly not universal, you just need to make the right engineering choice.
ViscountPenguin 18 hours ago [-]
It can be really frustrating viewing threads like this sometimes. I've not once seen an interest rate swap priced in anything other than float/double, and that's relatively simple even compared to some of the crazy instruments out there.
Like, sure, probably don't use floats for everything, but what are the odds that your greeks are gonna be nicely expressable as simple rationals?
SJC_Hacker 16 hours ago [-]
Basically whenever you are acting as a custodian e.g., a bank. Then you have to be super careful.
No one cares if you’re mortgage calculator is off by a penny
FabHK 3 hours ago [-]
> you're interested in the risk metrics, like durations, convexity, vega, and so on, no one cares what your rounding convention is. doubles are just fine, thank you.
Doubles are not just fine, but required there. If you compute risk, as you allude to, by finite differences, then you need the precision of floats rather than rounding to integer cents prematurely.
xlii 8 hours ago [-]
Quick browse over Stripe API (i.e. not a simplistic payment provider) will show exactly otherwise.
Metrics/durations/convexity/vega aren't monetary value, these are calculation values and I'm fine with them being whatever. If you're calculating averages to make decisions based on this I don't care if you're counting dolars or tomatoes.
Monetary value is $4.50 and it's representation of actual money passed through system. In practice this value is almost never undergoing any operations except for addition and subtraction. Any multiplication/divison etc. is left to specialized systems that return results wrapped in 800 pages of standarization documents, regulations and so on; systems where term "bit flip" is not a joke, but a risk.
As I wrote fintech != fintech, and I know many organizations aren't at that level of scrutiny, but a huge domain of people dealing with others' people money know that charging someone 1 cent too much is a tens of thousands of problems coming their way.
fauigerzigerk 7 hours ago [-]
What's your preferred solution to dealing with FX conversions?
My issue with using integers everywhere is that FX conversions (or other rates) always come into play, and at that point I'm forced to use something else anyway (e.g. arbitrary precision decimals).
xlii 5 hours ago [-]
I never had to deal with that. At one place it was so complicated that specialized system took reconciliation over (it got baggage full of context data including exchange agreement details, with boundaries and time-regions plan).
In not-a-fintech we just went with doubles and rounded up (worst case - we get a cent more of a customer).
Though if I had to design today for that, I'd look for non-string serializable decimal, so not "10.123 == (10, 123)" but more like (10123, 3) and serialize in JSON as a value and precision separately.
Yet that's only cause I saw Decimal(10,123) sent in JSON as "10.123" which JSON reader red as 10.122 float and inserted to "1012" to database.
quibono 20 hours ago [-]
I love how this sensible take is followed by a tornado of comments that boils down to "NEVER use floats JUST BECAUSE".
worik 20 hours ago [-]
Never use floats for financial calculations. Because hard won experience.
"Floats" are simulations of Real Numbers, and Reals are uncountable. Not what you want for finance, where everything is counted.
quibono 19 hours ago [-]
I suggest reading the comment I was replying to since it contextualises the answer quite well. Hard to find absolutes in real life outside of thermodynamics.
Onavo 16 hours ago [-]
It doesn't matter for quant finance to use floats because approximate is perfectly fine. Tracking the exact amount to accounting standards is the job of the brokerage team not the quant devs. Floats are fine for modeling as long as the numerical drift is accounted for.
rnagulapalle 19 hours ago [-]
[flagged]
dahart 1 days ago [-]
What are you referring to with the integers/floats comment? The article says clearly that the rule of thumb is not to use floats and that they’re “almost never” a good idea, that they cause unpredictable precision loss, and recommends integer or BigDecimal types in multiple places. Are you also talking about rationals? So what is the bad advice here, exactly?
For FX, it seems like you’re reinforcing what the handbook says, that there’s no canonical rate. Aside from that, it’s talking about post-resolution records and you’re talking about how to resolve, no? That’s valid nuance of a separate goal, and it’s a fine goal of yours, but doesn’t seem like a demonstration of something missing or wrong.
The article appears to make the very same point about immutability? What are you saying that’s different?
solumos 1 days ago [-]
With integers/floats, he's saying it's not opinionated enough. Anything other than integers with minor-unit precision, unless you have a very good reason, is a bad idea. So "floating point is almost a bad idea" doesn't go far enough, and the other alternatives are presented somewhat equally.
The FX critique is saying that it's glossing over a lot of the complexity. I'd say the same is true for the treatment of DE ledgers, and it borders on bad advice (e.g. "Balance is never stored. It’s derived from the movements of money.")
dahart 1 days ago [-]
> Anything other that integers with minor-unit precision, unless you have a very good reason, is a bad idea.
The article clearly communicates this sentiment, no? What else needs to be said? How much further does it need to go, and why?
It might be a mistake for either us or the handbook to be absolute or dogmatic about floats. It’s not a sin to mention that they exist, and it’s a fact that some people in fintech use them for some reasons that have a defensible engineering position and well considered tradeoffs. I’ve been on the side of assuming people don’t use floats for money and then been surprised when I bumped into people here on HN who report using floats in finance routinely.
BTW, is your quote “almost a bad idea” a typo? There’s a world of difference between ‘almost a bad idea’ and ‘almost always a bad idea’. The actual words in the article, if we’re quoting the article, are: “almost never a good idea” in reference to using floating point types.
> it’s glossing over a lot of the complexity.
Of course it is, that’s a good thing. It’s not pretending to be a spec or rules, it’s an introduction and general principles. The article is already introducing new complexities that people outside of fintech might not be aware of. But do we really have to mention ALL complexity? The biggest problem with Wikipedia is that it’s overrun by nuance and complexity, so much that you often can’t read an article on a topic without already being an expert on that topic. This is why experts are often bad teachers. Being unable to gloss over some complexity is not good for learning and doesn’t make a good environment for newcomers. Let’s allow people to write for non-experts and make room for learning. We don’t have to avoid glossing over some of the complexity; it’s useful to get the general direction and gist correct while leaving out some of the detail.
> it borders on bad advice
Be specific. What’s wrong? Note that contributions are invited.
fragmede 23 hours ago [-]
"Monetary value must be stored in integers" is the much stronger statement that the article doesn't make. Obviously there are exceptions, but you're going to need a much longer side discussion in order to justify why you're using floats.
It's like saying "don't write your own crypto algorithm". Of course write your own crypto algorithm, that's how you learn about cryptography. But you'd never put your homegrown cryptographic algorithm into production until after several PhDs worth of understanding of cryptography has been put into it by many other people.
fauigerzigerk 6 hours ago [-]
>"Monetary value must be stored in integers" is the much stronger statement that the article doesn't make. Obviously there are exceptions, but you're going to need a much longer side discussion in order to justify why you're using floats.
It doesn't make that statement because arbitrary precision decimals exist. Binary float is not the only and not the most plausible alternative to using integers.
Erem 17 hours ago [-]
If you render a number using JavaScript it has been temporarily stored as a doublr. The article was likely allowing for that common use case.
FabHK 3 hours ago [-]
[dead]
3uler 1 days ago [-]
For me quickly scanning over the article, the fact that floating points were even presented as a possibility was an immediate red flag. And I pretty much stopped taking the rest of it seriously.
FabHK 3 hours ago [-]
> it borders on bad advice (e.g. "Balance is never stored. It’s derived from the movements of money.")
Don't think that's bad advice, in particular as the article clarifies:
> Derived state can be cached. Balances and projections can be cached or snapshotted for performance.
Of course you can cache or snapshot. But don't mistake that with storing the golden source.
sho 11 hours ago [-]
> It's always integers unless you have a VERY good reason to do otherwise
I don't really agree. This seems like one of those outdated "greybeard rules" which people love to cargo cult, but to me it just comes with its own set of trade-offs, like now you have to think about exponents everywhere and getting them wrong comes with orders-of-magnitude consequences.
If you have a modern DB and your languages handle its decimals well then I'd use them. You can translate as needed for imports and exports, but the core of your system is always sound. Switch to the more basic formats if and only if there was some perf problem with decimals, which for most fintechs will be a VERY long time with modern DBs.
What really pushes me towards decimals is the consequence of getting something wrong. Relying on comparing raw ints, with variable exponents baked in, can lead to catastrophic errors with multi-order-of-magnitude gaps if that implicit exponent isn't carried along correctly. It's a massive footgun always waiting to happen. Decimals avoid that whole class of problem. So the goal is to maximise the "safe" decimals as source of truth everywhere you can, and have very well-tested "in and out" paths for any producers or consumers with different representation preferences. To me, that's good system design. And when, not if, you're manually inspecting DB records to track down a bug, having everything normalized in a glanceable, obvious format like decimals will let you recognise errors faster and more intuitively.
This goes extra for crypto, especially stablecoins, where one USD stablecoin might be exp-6 and another might be exp-9. And you're representing them in the same DB! Off by a factor of a thousand if you miss that exponent! Decimalize that immediately says I.
6 hours ago [-]
advertum 6 hours ago [-]
[flagged]
lxgr 1 days ago [-]
> thank you Rust decimals represented as JSON floats
What do you mean? JSON doesn’t have floats, it has numbers, and how they’re used after being parsed is not part of the spec.
> If I ever see a monetary value stored in something else than integers I'm going to run away screaming
That’s good, then we’ll likely not be working on the same system :) I consider running from “amounts as integer” systems these days (but usually unfortunately can’t). In an idealized codebase that only seasoned financial programmers are allowed to touch, it can go well, but such a system is usually either overly exclusive or risks becoming brittle.
zdragnar 1 days ago [-]
> JSON doesn’t have floats, it has numbers, and how they’re used after being parsed is not part of the spec.
I think that's the problem they were trying to describe. Without a formal spec, systems won't agree on how to handle floats. JS engines treat numbers as 53 bit signed floats, so passing a well defined decimal there through JSON means losing precision at the edges.
Money stored in integers gets around the issue by simple virtue of not really needing more than 53 bits to accurately represent the values anyone is going to encounter.
There are downsides like all the extra math or functions to handle doing the math everywhere money is manipulated or displayed, but this is the sort of thing where static typing is really helpful, and isn't too hard for juniors to understand that they should always use money functions to work with money data.
dotancohen 22 hours ago [-]
With I need to represent monetary amounts through JSON, I encode it as a base 10 string and wrap it in quotes so that the JavaScript engines treat it as a string. Conversion back to int happens after the string has been parsed and validated.
I do this with HTTP GET and POST form requests as well. In HTTP, everything is a string (even if that string is JSON).
worik 20 hours ago [-]
> JS engines treat numbers as 53 bit signed floats
Please do not use Javascript for finance applications. Just do not do it
Save it for user interface elements and dancing whizzimagigs, where it will do less harm.
zdragnar 19 hours ago [-]
Excel does the same thing, and has been used to track money for decades. Somehow, we're all still alive.
morpheuskafka 1 days ago [-]
I'm sure there is something I don't know here, but how is working with integers "brittle"? The only issue I see is rounding down by default, not sure if that is even an issue or not. At any rate, it seems a lot less brittle than floats or bigdecimal style number classes.
lxgr 1 days ago [-]
The brittleness comes from the fact that the number of implied decimal digits per currency isn't always well-defined across all stakeholders and systems.
If you're only working in a single currency, there's usually no issue.
foresterre 1 days ago [-]
As a general rule, you always include the currency code (EUR, SEK, USD etc.) and if possible also the amount of decimals, when using minor units.
Currency codes can be found in ISO 4217.
lxgr 1 days ago [-]
Yes, definitely always include the number of digits, but at your system boundary you still have to pray that whoever you're working with isn't silently dropping that number and re-deriving it from their own, almost-4217-compliant currency database.
Redundancy can be great, but it's not a panacea, since it's not guaranteed to be used in an optimal way.
jyounker 22 hours ago [-]
How you expose you present your data to third parties is not how you represent it internally.
lxgr 20 hours ago [-]
Ideally it’s not, but I’ve seen it leak so often that I’d rather be safe than sorry.
0xffff2 1 days ago [-]
ISO 4217 also defines the number of significant digits after the decimal separator if Wikipedia is to be believed.
lawlorino 1 days ago [-]
> I consider running from “amounts as integer” systems these days (but usually unfortunately can’t).
In the context of Fintech, how do you otherwise resolve floating point rounding issues if not representing amounts with integers?
lxgr 1 days ago [-]
Native decimal types, if your system has them. Many languages and databases used in financial contexts do.
Maxatar 1 days ago [-]
But native decimal libraries are almost always floating point.
Do people not know what a floating point number is?
lxgr 24 hours ago [-]
That’s alright, the important part here is that they’re decimal, not binary. You don’t want 0.1 + 0.2 to equal 0.300…004.
Maxatar 23 hours ago [-]
There are pretty trivial ways to use binary floating point values that don't result in 0.1 + 0.2 producing 0.30000...4 and it saddens me when this topic comes up and people go to such extreme lengths to recreate a second hand buggy reimplementation of a subset of floating point numbers to do it.
FabHK 3 hours ago [-]
What are those pretty trivial ways? And how are they better than storing 10 cents + 20 cents = 30 cents?
Maxatar 34 minutes ago [-]
By not thinking in terms of strict rules and dogmas and instead focusing on the actual problem you want to solve.
If you want to guarantee that adding cents together results in an exact value without any loss of precision, and you also want a tiny memory footprint and very high performance, then use a binary floating point to represent cents, just as you would use an int.
Also the question of how it's better depends on your use case and my argument is not that one representation is universally better than another, it's that money is used for such a diverse range of use cases that you need to actually understand what you're doing, what the goal is, what the potential issues are etc... in order to pick the right representation for your use case. At my trading firm we have three different Money classes optimized for three different use-cases (with functions to allow interoperability between them).
For the use case where the representation needs to use little memory, is fast, and needs to be used to perform complex financial calculations at an enormous scale, then you use binary floating point where a value of 1.0d = 0.000001 dollars. This gives you exact precision when working with cents, and lets you perform all of the usual financial computations that most quantitative applications need to perform with excellent performance.
We also have a use case optimized for I/O, where no calculations are expected to be performed but the data will be transmitted over a network or to/from a database etc...
If this isn't your domain, maybe you're just writing a GUI application/web app, then by all means use a big decimal or use an integer... I don't know, but it's very sad seeing how many people who are presumably professionals don't take just the bare minimum amount of time to think things through and instead just reason in terms of strict dogmas.
worik 19 hours ago [-]
> There are pretty trivial ways to use binary floating point values that don't result in 0.1 + 0.2 producing 0.30000...4
Not across all architectures and operating systems there are not
Listen to those who have done this. Use integers for finance.
Maxatar 18 hours ago [-]
Yes across all architectures and OS's that use IEEE 754 floating points.
ktimespi 19 hours ago [-]
Aren't decimal types BCD coded?
dgunay 20 hours ago [-]
All of the data we control (in the database, in our apis, etc) is integer cents. When we have to interface with a system that represents money using JSON numbers as dollars.cents, we parse or serialize it into an arbitrary precision decimal type. Hasn't been much of a problem.
foobarian 16 hours ago [-]
This started out fine for us except that int32s were a bad idea and upgrading was painful
dgunay 13 hours ago [-]
That's definitely valid, for b2c applications though a lot of the time you will never deal with numbers of that magnitude.
simpsond 1 days ago [-]
An integer for the value (scaled by number of decimals) and an integer value for the number of decimals. Different systems may use different values, even for the same currency or asset.
Maxatar 1 days ago [-]
What exactly do you think a floating point number is?
lxgr 20 hours ago [-]
Usually that, but in binary, which causes lots of headaches for financial math.
Maxatar 18 hours ago [-]
For those who don't understand what they're doing, yes. But those people end up having headaches and causing trouble no matter what.
m00x 23 hours ago [-]
You can't do everything you need with an integer. There are values you might want to display or calculate with that are smaller than cents. In some places you'll need things like BigDecimal, which are immune to floating point errors in most cases.
It's also safe to return decimal values for displaying values.
FabHK 3 hours ago [-]
But it's a good idea to keep those values distinct from actual money. You can't pay a fraction of a cent to anyone.
fauigerzigerk 2 hours ago [-]
But the price of some unit of a commodity may well be expressed in smaller fractions to allow for small price changes.
You could argue that a price is not really an amount that anyone can actually pay and that's true. But it seems complex and error prone to store unit prices and amounts using different scaling factors.
solomonb 20 hours ago [-]
The integer `1` can mean whatever you want, it doesn't need to be a cent. Haskell's `Fixed` type is a good example of this:
Its a wrapper around an `Integer` where you declare the scale in the type. So if you use `Fixed E2` as your type then `MkFixed 1` is 1 cent. If you did `Fixed E3` as your type then `MkFixed 1` is 0.1 cent. In both cases it is entirely an integer encoding.
22 hours ago [-]
skipants 1 days ago [-]
That was the first thing that popped out and made me distrust the whole wiki; there's only One Right Way to store money (as integers[1], as you said) and it should have been explicit about that.
You can also use fixed-point if whatever you're using supports it but it's still technically integers.
lxgr 1 days ago [-]
Word of advice to anyone considering the "minor-units precision" strategy for representing monetary amounts: Don't (or at least, don't use it as an interchange/API data format).
It seems like a clever idea (fast integer math, no rounding problems for addition and subtraction), but it'll bite you incredibly hard if you ever stumble upon an edge case such as working with a partner that has a different implied number of digits for a given currency. This is especially relevant for stablecoins, which often have a different number of implied decimal digits than the "fiat" currency they represent.
Also, consider representing amounts as a string type in JSON-based APIs. JSON does not specify decimal precision, so you (and all your users/vendors) will always have to make sure your parser/serializer doesn't internally lose precision by going via floating point. This can get ugly fast, and while a string seems conceptually less neat, it completely bypasses that problem. (Some will call this an anti-pattern [1], but I'd rather not fight this particular battle for ideological purity on the shoulders of my users or shareholders.)
The only real correct solution here is to send mantissa and exponent as two separate integers. It's trivial to convert between exponents for whatever math you want, it can be as correct as you want, and is unambiguous.
In the HFT space you save some wire space if you can commit to a consistent exponent for some {slice} up front (think instrument/tick-size/asset-class/exchange/feed/server/whatever/...) such that you only need to send the mantissa and your clients can have a hard coded exponent. However, in similar spaces it's often worth the extra uint32 to send a on-the-wire exponent such that things _can_ change and you aren't hamstrung later by earlier "we only need cents now!" design choices when, e.g., you suddenly need to support bitcoin/... prices to full precision. (your users will thank you when they don't have to coordinate a breaking change when you want to adjust your fixed exponent)
microgpt 1 days ago [-]
If you do that though aren't you just reinventing floating-point?
OtherShrezzing 23 hours ago [-]
No, standard floating point implementations have higher precision for smaller numbers than larger. So for example, in a 32bit float, there are far more numbers between 0-1 than there are between 1,000,000 and 1,000,001. For 32bit floats, you start lowing whole integers with relatively small numbers.
Integers have a consistent precision across the entire number line.
jjmarr 1 days ago [-]
No, because you're doing decimal floating point, which eliminates the rounding errors of binary floating point.
> The only real correct solution here is to send mantissa and exponent as two separate integers.
That’s essentially the same thing as a String-serialized big decimal, just less readable, no?
gmm1990 1 days ago [-]
That’s quite a bit slower to process. At least if you’re converting to integers to do the calculations and the calculations would be quite a bit slower if you kept the big decimal type
lxgr 1 days ago [-]
True, but this is usually your least concern when you're dealing with monetary amounts/math.
gmm1990 22 hours ago [-]
I guess I’m coming at it from an optimizing market data provider perspective once you preallocate memory the next thing to optimize is the string decimal conversion if the feed isnt binary encoded
Maxatar 22 hours ago [-]
It might be your least concern, and that's fine but it's not the least concern for many people who need to process large volumes of transactions.
Money, even within fintech, is a concept used across a wide variety of domains, and you can't assume that what concerns you is what concerns everyone else relying on it elsewhere.
mnahkies 1 days ago [-]
They specifically mentioned HFT so I suspect they care a lot about processing speed
antonymoose 1 days ago [-]
Having done HFT / low-latency in C++ with a browser based (read: JavaScript) management front-end: Go ahead and use integer cents everyone. It’s practically an industry standard and it works just fine. Anything else is a worse compromise.
notpushkin 1 days ago [-]
It is fine as long as you don’t cross any edge cases (crypto, or more recently stuff like AI token pricing) and don’t forget to account for third party quirks (e.g. Stripe’s zero-decimal currencies: https://docs.stripe.com/currencies#zero-decimal).
lxgr 1 days ago [-]
JPY not having any minor units is arguably not a “third party quirk” but just how the currency works. The same goes for various three decimal digit currencies.
amluto 1 days ago [-]
If someone sells you 12345.55 EUR vs USD at a rate of 1.12345, how many EUR do you think you end up with? Do you think all market participants even agree? What if the rate is 1.123456?
For added fun, you can introduce division. Some systems will allow you to sell 12345.55 USD to buy EUR at a rate of 1.12345.
The article’s “no lost data” tenet is not really viable when this sort of division is involved. Are you going to track your account balance is a rational number with an absolutely immense denominator forever?
FabHK 3 hours ago [-]
> If someone sells you 12345.55 EUR vs USD at a rate of 1.12345, how many EUR do you think you end up with?
1. If someone sells me 12345.55 EUR, I hope to end up with 12345.55 EUR.
2. That's the point though. They will sell you a certain amount of EUR at a certain dollar price. This, in turn, implies a rate (which might well have more than 5 digits behind the decimal). This is ideally close to the quoted rate, sure. But what counts is the actual EUR amount and the actual USD amount, not what rate was quoted or with how many digits.
dumah 22 hours ago [-]
Of course market participants agree?
Exchanges have calculation rules for every type of mark and payment and will always specify rounding.
SJC_Hacker 12 hours ago [-]
The only one who has to “agree” is the exchange. And it should be covered by the TOS
antonymoose 23 hours ago [-]
You store the sums on either end, the currencies, the exchange rate and the final sum? No one has .0000145 cents in their account. Rounding occurs in the real world.
amluto 22 hours ago [-]
> You store the sums on either end, the currencies, the exchange rate and the final sum?
There is a remarkable amount of disagreement as to whether one should do one’s back office work based on the price or based on the quantity of the counter currency.
> No one has .0000145 cents in their account. Rounding occurs in the real world.
Indeed. But you either need to convince all parties to agree to round the same way or you need to accept small errors
jyounker 22 hours ago [-]
My experience in consumer banking says that every instrument specifies the precision of the calculation, how and when rounding happens, and slew of
little details.
So, yes, everyone has to understand how all their partners are doing rounding and summing.
amluto 19 hours ago [-]
In certain areas of the institutional finance world, everyone seems to accept that everyone's math is allowed to differ by a few cents, and they tally up the errors and move on with their lives.
I would, however, by quite surprised if my personal bank account did this.
SJC_Hacker 12 hours ago [-]
When the bank owes you money, they round down.
When you owe the bank money, they round up.
walthamstow 11 hours ago [-]
Unless you work for the bank, in which case your annual salary is divided by 12 and rounded up for a monthly figure.
lxgr 1 days ago [-]
If you’re only trading in USD and other two-decimal currencies it can work fine, yes. For anything else, it’s much worse as also detailed in TFA.
antonymoose 23 hours ago [-]
You provide different handling strategies for different currencies. You also sort currency data alongside your amount. There is nothing complicated or edge-case here.
This works for USD, JPY or $MEMECOIN and it scales very well.
DetroitThrow 1 days ago [-]
Agree with this, working from HFT to payments to account management in the past.
You can have the blockchain team be an expert in converting integer cents, or the forex team be an expert in sub-cent conversions. You don't want to require _every team_ to have expertise in float math, by default.
lxgr 1 days ago [-]
Big decimals are widely available and don’t require any expertise but avoid many of the footguns of implied decimal integers.
m00x 22 hours ago [-]
BigDecimal should be used by almost everyone except for HFT since they're really slow.
Maxatar 22 hours ago [-]
Imagine advising someone who explicitly said they work in HFT to use big decimals.
denismenace 1 days ago [-]
> but it'll bite you incredibly hard if you ever stumble upon an edge case such as working with a partner that has a different implied number of digits for a given currency
Why would that be a problem? You just transform the values when interacting with their API.
xlii 1 days ago [-]
Exactly, model is in integers and representation can be 1⃣3⃣ or whatever, that's why model-view separation exist.
lxgr 1 days ago [-]
Sure, you can do that if you can absolutely guarantee that everyone will always respect that separation and there will never be ambiguity between your internal and some partner's representation – even during incidents, even during low-level CSV-to-DB ETLs during incidents ("just one time, I promise, we don't have time to build the proper adapter, but look how similar their and our formats are").
afavour 1 days ago [-]
Because a lot of the time there won’t be any error when you’re wrong, just silent data loss.
andylynch 1 days ago [-]
I’ve seen bugs like this in prod systems. The notional value of the error tends to make the people concerned anything but silent.
microgpt 1 days ago [-]
Customer was charged $0.995 after fees, how to represent in your data model with integer cents?
lxgr 1 days ago [-]
You'll have to decide when and how to round. Keeping individual billing items at high precision and rounding after summing them up can work; defining and documenting a rounding policy (or complying with whatever's legally required in your jurisdiction/domain) and rounding each individual billed item can as well.
FabHK 3 hours ago [-]
How is the client going to pay that? They can't be charged half a cent.
snsnsjjsjsiisa 1 days ago [-]
You use 1/1000th or 1/10000th or whatever you need. You do not need “cents”.
denismenace 1 days ago [-]
Currency: USD
Amount: 99500
Decimals: 5
microgpt 9 hours ago [-]
Congrats m8 you invented floating point
denismenace 3 hours ago [-]
Then you have no idea how floating point works. (Hint: its in the name)
xprnio 1 days ago [-]
Round it up
microgpt 1 days ago [-]
Charge $0.995
Refund $1.00
Repeat
SJC_Hacker 12 hours ago [-]
Charge $0.995
Charge Actual $1.00
Refund $1.000
Alternately
Charge $0.995
ERROR CHARGE AMOUNT MUST BE ROUNDED TO NEAREST CENT
microgpt 9 hours ago [-]
In my scenario your payment gateway added a $0.005 fee. You told it $0.99.
lxgr 1 days ago [-]
Sure, but are all your (and your users' and vendors') engineers and LLM agents going to remember that? When in doubt, always be explicit.
makeitdouble 1 days ago [-]
I'm curious how you handle that.
Let's say I operate with a 4 decimal expectation and your API expects 6, is there any way to reconcile that outside of documentation and or metadata ? (which would be the same issue I guess whatever representation is used ?)
lxgr 1 days ago [-]
Yeah, you need to document it.
Still, even if you do: Chances that your users are just going to assume you're conforming to ISO 4217, some national standard, or your competitor that they're already integrated with are pretty high, so I wouldn't take the chance. Pick something that doesn't have to be documented instead.
dahart 1 days ago [-]
I think I’m agreeing with you whole-heartedly if I say that article’s conclusion is at best extreme and unrealistic when it says “the parsers need to be fixed. They should support extracting any numeric type we want from JSON numbers and at any precision.”
This sounds like an unreasonable position to take. “Any” is an unachievable standard that could require an unlimited engineering budget with no demonstrable value in practice.
It is good to identify the lack of a standard, and to talk about what parsers do in practice, and good to discuss the gaps and unmet use-cases. It would be a good idea to suggest that there should be a more reasonable standard, perhaps. It’s just not a good idea to demand that everyone support “any” possibility when no one really needs that, no one knows what it means, and it’s not actually possible to achieve.
gucci-on-fleek 1 days ago [-]
What do you recommend instead? Standard floating-point ("float"/"double"), fixed-point arithmetic with thousandths (or smaller) of the minor unit, arbitrary-precision decimal numbers, or something else entirely?
lxgr 1 days ago [-]
I think what matters most is your database and API representation, as well as having consistent and well-defined rounding rules.
I largely agree with TFA: Round explicitly and consistently whenever you cross a boundary, i.e. database persistence and internal API calls.
Use whatever works for your required business case internally (i.e. inside of procedures calculating some function of one or more input amounts). This can be regular old floats/doubles if you absolutely know what you're doing, or BigDecimal if you aren't and would rather suffer slightly slower performance than having to talk to an auditor about IEEE 754 rounding modes, or even minor-amount integers (yes, even though I just said to not use them – but you'll want to ABSOLUTELY NEVER leak them outside of your system, including your data/analytics pipeline, which might have different ideas about financial amounts than your business logic implementing a nice custom monetary type).
ivanmontillam 1 days ago [-]
A string type. As parent says: it completely bypasses the problem. Save the numbers between double quotes and be done with it.
portly 1 days ago [-]
Storing numbers as arrays of u8? That doesn't make sense
ivanmontillam 1 days ago [-]
For JSON serialization, which doesn't support fixed-point precision it does.
Floating-point precision has too many gotchas for being suitable to store Decimal types, especially for the Currency use case.
How is that better than {“amount”: “10.00”} (which also bypasses all potential floating point parsing issues that your or your counterparty’s JSON library might have)?
jameshart 1 days ago [-]
It is explicit about the fact that that number of decimal places is part of the data.
The semantics for your string “10.00” are complex - is it considered equal to “10”? To “10.000”? To “10.001”?
A user interacting with an API that uses such a string might make all sorts of assumptions about what it supports.
A user interacting with an API that has an explicit decimal places concept is being told ‘decimals matter! They can vary! Here be dragons!’
lxgr 1 days ago [-]
> The semantics for your string “10.00” are complex - is it considered equal to “10”?
Yes, but "10 USD" would be a non-canonical representation and you probably serialized incorrectly.
> To “10.000”?
Yes, but same caveat as above applies.
> To “10.001”?
Obviously not, and any system you'd ever want to use in a financial context will tell you so.
lxgr 1 days ago [-]
It makes a lot of sense if you value correctness over performance.
microgpt 1 days ago [-]
Why not store them in unary then?
lxgr 1 days ago [-]
Unary is exactly as expressive as decimal or binary for integers, but somewhat less efficient, so why would you?
microgpt 1 days ago [-]
idk, why would you store integers as ASCII strings? It's somewhat less efficient.
lxgr 1 days ago [-]
Because it's much more explicit. Computers are fast, engineering is expensive. You usually never want to optimize prematurely when dealing with monetary amounts.
microgpt 9 hours ago [-]
Even more explicit would be a PNG of the dollar bills. I suggest that.
lxgr 1 days ago [-]
Except that now you have a new problem: Opinionated theorists that haven’t been part of a nasty “oh no, we accidentally considered some amounts as 10x/100x/1000x larger/smaller than expected” incident in their career yet…
KellyCriterion 1 days ago [-]
Do not throw away any precision in finance/money computation, regardless what/ how you are doing it.
In C# e.g., there is type decimal for those computations.
lxgr 1 days ago [-]
You'll definitely have to throw it away at some point.
The art is in making those points well-defined and rare enough to not cause large discrepancies, but frequent enough to avoid ballooning arbitrary-precision numbers across databases and services that might not be able to handle them.
krever 1 days ago [-]
I really like that phrasing!
Would you mind if I steal in some form if I decide to review this part of the book?
lxgr 1 days ago [-]
Not at all, and thanks for writing all of this up!
necrotic_comp 1 days ago [-]
Floating point value stored multiplied by 10^8. That gives you a huge integer, but it's extremely accurate, especially for US denominated currencies. Easily transformed into floating point numbers for reporting/etc.
1 days ago [-]
gib444 1 days ago [-]
What is with this Twitter esque style of discussion? Post some vague comment with no real stake in the ground, but just reply to follow ups asking for clarifications about the right way. It's exhausting. Why not put all that effort into the initial comment?
Vague-posting seems to becoming more popular
lxgr 1 days ago [-]
If there were a simple one-size-fits-all solution to these problems, there wouldn't be a need for a handbook, nor for a discussion, would there?
I can't design everybody's systems here, but I was hoping that sharing some war stories that have cost me days or weeks of work might sensitize somebody to a few non-obvious footguns.
gib444 1 days ago [-]
That strawman is so large it would even scare away a human
jdw64 1 days ago [-]
As a programmer, what I feel when I see fintech programmers each speaking from their own different experiences and perspectives is that it makes me wonder what it really means to be good at programming.
What user xlii said about not storing monetary amounts as floats is a common IEEE 754 issue. And while it's true that financial tracking should be done through immutable logs or event-based records, I don't think every surrounding service needs to be built with event sourcing. I think it's enough to apply it only to core logic like ledgers, settlements, orders, and executions. Looking at xlii's comment, it seems like a technique that only becomes viable when the modeling is successful.
User lxgr's comment points out that it's a minor-unit issue. If JSON numbers are parsed as floats by the language or parser, precision can be lost. Usually people send values with a separate decimal places field. However, I've heard that in HFT, they don't do that because the overhead itself is too costly.
And antonymoose's comment aligns with what many books say. That's why designs like this are common in FX or API contexts. It feels like protocol design, doesn't it?
Putting it all together, everyone's right within their own domain. While I think it'd be great to have someone like xlii as my senior programmer, I also feel like I wouldn't be able to design such a complex system myself. In that sense, everyone's statements are valid, and it's interesting to see how opinions diverge depending on the domain. Is this what expertise looks like
Looking at all this, it seems like you can roughly infer where a programmer is coming from based on their experience. Sometimes programming doesn't feel like finding the right answer, but more like choosing a worldview
Watching how programmers model their domains on HN is always fascinating. Sometimes I click on their profiles and add their domain knowledge to my own personal wiki, thinking I might use it someday
zackwu 18 hours ago [-]
Fintech/finance is a very big industry and there are a lot of sub-domains. A HFT system programmer thinks about how to colocate their prod machines in NYSE and use zero alloc techniques to ingest marketdata as fast as possible, while a crypto wallet app developer spend more time designing cool UI to attract users and working out all the L1/L2 quirks. And I'm sure they have very different answers to whether to use integers and how many digits to preserve
argee 20 hours ago [-]
A good programmer is just a bad programmer who’s learned not to make the same mistake twice. That’s part of expertise and why it differs too, everyone has made a different set of mistakes, domain-coded.
Fordec 23 hours ago [-]
I would like to hear more about this wiki you have.
belmarca 1 days ago [-]
Nice. The book contains a bunch of good information that could already be found elsewhere but collecting it is quite practical. I highly suggest to read Kleppmann's Designing Data-Intensive Applications. The first edition was very good, a second one came out recently.
I was CTO of a FinTech where I built the whole software stack from scratch: the lessons in the book are mostly correct. I say mostly, because as always, there is a lot of "it depends" to take into consideration for your particular project. For example, I chose to not use event-sourcing to avoid the whole state computation issue. A standard append-only audit trail can do the job.
You can't guarantee exactly-once delivery but you can construct effectively-once processing, and that is what you really want.
Store every request and response : absolutely, and not only when consuming APIs, but when collecting any information from the outside world (and, if you can, also log every intermediate transformation step within your perimeter). Content-adressed buckets + a relational table are great for this.
The text also does not mention anything about data lineage. What happens if a vendor updates some data mid-day that you absolutely need to be aware of? You need to be able to account for that, while also re-playing computations that used the old values and get the same result. It's not a particularly hard problem to solve, but it takes some thought.
potamic 13 hours ago [-]
Why content-addressed storage? I'm assuming this is mostly for auditability after the fact? Wouldn't it make sense to use some business identifier to be able to refer it back easily?
trixn 7 hours ago [-]
> Money can’t be created out of nowhere
Well, in case of a bank it can. And it happens on a daily basis. In fact thats how most private bank money enters the system in the first place either when a bank makes a loan or when it buys any other asset like e.g. a corporate bond (you can conceptualize a loan as an asset purchase as well, the bank buys a promise to pay from the borrower which is recorded as an asset of the bank). Both are a balance sheet extension from a double-entry bookkeeping point of view.
The 4 operations double-entry bookkeeping allows are:
1. balance sheet extension (e.g. making a loan)
2. balance sheet reduction (e.g. loan repayment)
3. asset swap (e.g. a bank buying a government bond with central bank reserves)
4. liability swap (e.g. transferring money from one account to another)
So it may be more accurate to just say that every event that affects the balance sheet must be one of those 4 operations.
Also see "Money creation in the modern economy" - Bank of England Quarterly Bulletin 2014 Q1
FabHK 3 hours ago [-]
Well, that's not money created out of nowhere. The balance sheet extension creates money and an equivalent liability. That's the point of the statement, not money supply and its regulation.
trixn 2 hours ago [-]
Fair enough, just wanted to point out that banks originate money as part of the lending process. You could maybe call that "money out of asset purchases" whatever that means and yes its a valid balance sheet operation. I guess you would agree that a bank needs no prior savings or deposits in order to make a loan, i.e. it doesn't need to have money that it "lends out"?
Or let me ask you this: What would in your opinion be a valid example of "money out of nowhere"?
red_trumpet 6 hours ago [-]
> Well, in case of a bank it can. And it happens on a daily basis.
You mean it happens when a bank borrows money from a central bank, right?
Not every balance sheet expansion constitutes the creation of money, e.g. when you put money on your bank account, the bank's balance sheet grows, but the money is not newly created.
trixn 6 hours ago [-]
> You mean it happens when a bank borrows money from a central bank, right?
No I mean in the moment the bank grants a loan. The money the borrower receives is new money, its not taken from anywhere else. But at the same time the bank records the credit as an asset which makes it a balance sheet extension.
> when you put money on your bank account, the bank's balance sheet grows
That's true, you hand over cash to the bank which becomes its asset and your account balance is marked up for the same amount. Not all money in circulation is accounted on a bank balance sheet, but most of it is bank deposits. cash is an exception, it's public money, not private bank money. When you "put money in a bank account", i.e. you bring cash to the bank you are essentially selling your public government money to the bank and it pays you with its own private bank money (which it "creates" as well).
But this is only a micro-view of a single event. In the aggregate money is created when either the government runs a deficit or when banks make loans and money is destroyed when taxes are paid or loans are repaid.
kingleopold 6 hours ago [-]
some engineers and average person sees the entire fiat money as something that needs to be "earn" or get returns from investments only. they dont see how it's literally created as free and out of nothing.
trixn 6 hours ago [-]
Very true but also understandable because that's how most households perceive it from their micro-economic standpoint. But its very deceptive because it suffers from a fallacy of composition. If households want to earn more than they spend (i.e. save), some other entity must spend more than they earn. This can be somebody taking a mortgage or the government running a deficit. Debt and savings are mirror images of the same thing, two sides of the same coin and we use double-entry book keeping to track them.
It is very insightful to view money as a creature of accounting for debtor-creditor relations rather than thinking of it as some kind of commodity.
benashford 1 days ago [-]
I think most of this applies to software engineering generally, not just fintech.
For example the parts talking of retries, idempotency, event ordering, etc. This applies to all systems that require any degree of accuracy, even if no money is directly involved. I've seen so many systems built on the assumption that "we can always retry", but you can only retry if you fail cleanly in the first place, and if the downstream system offers the same level of idempotency that you think it does. Quite often these are not put to the test.
jappgar 1 days ago [-]
I agree. Very little in here specifically applies to fintech except the ledgering and rounding parts, which are pretty light.
I would prefer to read a defense of something more radical like "database per account." Something that has unique tradeoffs within fintech.
Also, the main advice I would give to fintech engineers/founders is to take risk and compliance seriously from day one.
Financial systems are based around trust. If you don't provably mitigate risks you will lose trust and, eventually, your entire business.
jimmypk 1 days ago [-]
[dead]
traceroute66 1 days ago [-]
> even bad advice
That's putting it politely. Honestly, I think this "handbook" was mostly written by an LLM.
For example, in the immutability section we have this:
"Separating PII from financial data lets you honor erasure without losing the financial history you’re obliged to keep."
In a financial organisation the two go hand-in-hand for obvious KYC/AML reasons.
Keeping the financial data whilst trashing the customer names, addresses etc. instantly on-demand before the expiry of the relevant time periods is going to leave your entire organisation with a very bad day in the office if a $lawful_body comes knocking for the data to trace a crime.
People going to work in a Fintech should not be relying on a random "Handbook" written by an unknown person in an unknown jurisdiction.
People going to work in a Fintech should only ever work in accordance with their employer's internal handbooks/guidelines/etc which will have been written in conjunction with their firm's lawyers and compliance people to ensure it complies with the laws and reporting requirements in the jurisdiction(s) in which their employer operates.
lxgr 1 days ago [-]
> Keeping the financial data whilst trashing the customer names, addresses etc. instantly on-demand before the expiry of the relevant time periods [...]
Where does TFA recommend that?
As I see it, it recommends separating PII data you'll eventually have to delete from that you'd probably want to keep forever (including data factoring into your accounting equations/invariants), so that you can delete the former after the relevant recordkeeping periods have elapsed.
> People going to work in a Fintech should not be relying on a "Handbook" written by an unknown person in an unknown jurisdiction.
Sure, but they should also not blindly ignore any ideas and practices presented, or avoid looking beyond their own organization. Ideally, they'll then try to reconcile what they saw with their own knowledge and local regulations etc.
> People going to work in a Fintech should only ever work in accordance with their employer's internal handbooks/guidelines/etc which will have been written in conjunction with their firm's lawyers and compliance people to ensure it complies with the laws and reporting requirements in the jurisdiction(s) in which their employer operates.
Sure, in a world in with only perfect and error-free organizations, that seems like a reasonable approach. But how does one get there without having a conversation such as this one?
traceroute66 1 days ago [-]
> any ideas and practices presented
Unless its your job to architect stuff, in a financial firm you don't go looking around for ideas and practices.
You comply with your employer's practices end of story.
If you like looking up ideas and other people's practices then a heavily regulated environment is probably not the place for you.
> how does one get there without having a conversation
"having a conversation" about new ideas/practices in a regulated firm will involve lawyers and the compliance department.
More than likely that "conversation" will be above most people's pay grade. So you're better off just not wasting your time and adhering to your employer's existing practices.
And for everyone else, its an expensive and high-friction conversation to have if you want to change existing practices.
lxgr 1 days ago [-]
"Not thinking, just complying" isn't the panacea for good outcomes you make it out to be. You definitely want to limit the amount of excitement, but I've seen many issues caused by legacy formats and practices as well.
> You comply with your employer's practices end of story.
What if you're the employer ("first engineer" etc.), and there are no practices yet? Fintech almost by definition sometimes includes doing things from scratch because some existing solution or incumbent organization isn't working that well anymore.
> Unless its your job to architect stuff
Which seems to be the target audience/scenario for TFA.
traceroute66 1 days ago [-]
> What if you're the employer ("first engineer" etc.), and there are no practices yet?
In that scenario the practices will still come first. You're not going to be doing any coding or systems engineering until you've got compliance signed off. You're going to be spending lots of time with lawyers and compliance people.
> Fintech almost by definition sometimes includes doing things from scratch
Yes, but cut through the noise of the typical Fintech fancy website and app and you're still staring straight down the barrel of spending 80% of your time on regulatory compliance.
Try as you might there are only so many ways you can re-invent the wheel for dealing with hard-facts legislation.
lxgr 1 days ago [-]
Please show me the regulation that tells me whether to use big decimals or integers in my internal monetary amount representation. Regulations usually care about outcomes (sometimes high, sometimes low level); they often don't tell you how to technically achieve them.
And if your lawyers and compliance people are actually telling you that you can absolutely not do any financial processing yourself, that the only possible way to be compliant is to license <incumbent product xyz> (unfortunately only available in COBOL) etc., you might not actually be working in a fintech, or at least not in the kind this guide seems to be targeted to.
Frankly, this kind of attitude is exactly why banking and payments is as fossilized as it is in some countries, and why fintech is eating their lunch in many cases. There has to be a balance between trying new things and doing what everybody else is already doing.
Scubabear68 21 hours ago [-]
This sounds great until your counterparties, banks, the government, customers and others complain bitterly that your monetary amounts are off.
Your expectations of course are not unusual because so many developers work on systems where users are not the customers, but the product.
Facebook, Insta, Google all fuck up results very regularly, but what are you gonna do when they do?
Now imagine your bank occasionally losing deposits, your account balance going up and down a percent or two every day, the IRS fining you for tax evasion because your Cool Fintech Rounding does not match generally accepted accounting rules.
danielabinav160 1 days ago [-]
The idempotency keys section alone is worth the read most devs learn that lesson the hard way.
lxgr 1 days ago [-]
I just wish the financial industry itself had known about these when the core banking systems and financial communication protocols of the 60s and 70s were invented that are still being used to this day...
Many of these predate the widespread knowledge of idempotency, so often idempotency keys are hacked together by joining various, hopefully globally unique fields, except that they never quite are. (You can look behind the curtain sometimes, e.g. when your bank does not let you transfer the same amount to the same recipient account on the same calendar day.)
pards 1 days ago [-]
100%. It deserves more detail, too.
I've spent many hours explaining how idempotency is supposed to work, and why it's important. Most teams understand the need for it, but very few thought about it up front.
__natty__ 1 days ago [-]
Also audit trails. Good audit trail can save company (and you) in emergency as well. Useful for debugging and last resort of compliance data source.
mrkeen 1 days ago [-]
I just build the audit trails and skip the non audit trails.
That way I can debug and have a last resort of compliance, but also save time by not building the first resort of compliance.
lanstin 16 hours ago [-]
All this debate about floats or ints or decimals, obscures the fact “reconciliation” is an essential part of dealing with money - essentially some separate implementation of the money movement that detects when your rounding strategy or floats end up creating or destroying money, but all the accounts balance at then of the day.
morpheuskafka 1 days ago [-]
A Plaid balance check is NOT a guarantee that the ACH debit you're about to submit will go through.
I don't care if the balance is one million, before that ACH can process, every single dollar can be (a) wired out, (b) cleared out by yesterday's ACHs (bills, autopay, whatever) and checks, or (c) spent at debit/ATM.
I probably shouldn't tell you why I know that some fintechs don't address this.
krackers 19 hours ago [-]
I think this is covered by the "overdraft" section, if the only way to know for sure is to just submit it.
m00x 22 hours ago [-]
It's a good indicator but absolutely no guarantee. I've had to tell project managers this because they didn't understand this concept.
jvuygbbkuurx 9 hours ago [-]
I wanted to say thanks for this resource.
I'm founding a fintech startup and have been thinking about these things a lot. It is very helpful to have some general validation and guidance to make sure I'm not making huge mistakes.
I really wanted event sourcing, but thought it gets complicated when events have complex validation rules. I ended up with a mix of state and audit logs which works ok for now.
cirrhosis 1 days ago [-]
I have just left a fintech company after 5 years and I can say after reading this, it looks legit to me (not AI slop as someone asked). These are the same sort of lessons I learned during my time in the industry.
I would recommend anyone starting in fintech to take some time to understand accounting principles and the ledger in a bit more depth than just debits vs credits - this is likely what is most unfamiliar to programmers.
Also financial software is very data-heavy and I learned more about databases in my time working in fintech than the 15 years before that. I think going into a bit more detail about even the basics (indexes) will save a lot of headaches.
bayarearefugee 20 hours ago [-]
> I would recommend anyone starting in fintech to take some time to understand accounting principles and the ledger in a bit more depth than just debits vs credits
Probably good advice (for everyone in fintech, not just programmers) considering the absolute disaster that happened at Synapse. Kind of wild nobody has gone to jail for that.
emiraga 3 hours ago [-]
is there any technical article that describes shortfalls and mistakes made in Synapse?
I am curious as I had a bit of money in Yotta.
sdevonoes 1 days ago [-]
> I would recommend anyone starting in fintech to take some time to understand accounting principles and the ledger in a bit more depth than just debits vs credits
Any good resources you would recommend to learn more about this?
cirrhosis 23 hours ago [-]
I've seen a few attempts at "accounting for programmers" guides, some of which I came across while browsing HN (if you search you'll find plenty). The one I used to send new developers was one such guide[1]. They also have another on building a ledger[2]. These are a good start and I wish I could recommend a proper textbook that goes into more detail - detail that I wish I had known early on - but I learned mostly as I went along.
Chunks of good advice, tossed and blended into a soup of verbiage generated by a helpful LLM. It sounds smooth and resists being read at the same time. I hope we can get to the point where actually good, helpful prose is generated more often than not.
koliber 1 days ago [-]
Anyone know of resources like this but for capital markets? Things that would allow engineers new to trading equities, options, FX, bonds, and commodities to learn about different flows, market structure, common architectures, and other things that normally you learn from years of experience.
mhh__ 1 days ago [-]
Equities and (listed) commodities are relatively easy to get a handle on but it genuinely takes months / years even at the frontline to understand how fixed income and FX works because its still almost entirely an OTC market. There is more central clearing than ever before but e.g. if I (say) buy a bond, fund it using a repo, swap my loot back some other currency, quite a lot of this could easily still be relying on humans pressing buttons and wiring money around.
To learn how and why these things are traded, however, read this book, the only (good) truly beginners guide to fixed income:
Even with equities, things are not entirely trivial.
A few examples: Some stocks trade in one currency, but pay dividends in a different currency. Some stocks go ex-div before the dividend amount has been determined (e.g. in Japan). Stocks trade on certain days, and trades settle on certain days, and they might be subject to different holiday calendars. Corporate actions are not entirely trivial, either (with rights issues, you need to issue two temporary securities for accounting purposes, etc.).
mhh__ 1 days ago [-]
"Trading and exchanges" is the classic one everyone reads for listed markets, I should add.
ricardobayes 1 days ago [-]
Does anyone have more learning resources in this field? Any model implementations, pet projects, anything to get going?
nvlled 5 hours ago [-]
Huh, that's strange, where did all comments to this post go? I remember seeing three, then a few more the day after. Were they bots? They seemed legit recommendations, like the Pricing Money book.
wavemode 1 days ago [-]
"Fintech" is extremely broad, and most of what gets called "Fintech" is really communication. Communication between firms, between traders, between systems, between ledgers, etc. There is no industry-wide "right" way to program anything, because the right way is ultimately whatever way the other party you're communicating with will understand.
If you're dealing with a party who tracks currency in cents, then tracking currency with more precision than that is going to lead to rounding disagreements. Vice versa if you deal in cents but they deal in tenths of cents. And so on for all the other advice in this document.
rTX5CMRXIfFG 1 days ago [-]
I don’t work in fintech (yet) but I’ve studied finance recently and quite a lot of these pieces of advice are just intuitive when you know the business domain. Learning the “customer” of your software helps too
senthil_rajasek 1 days ago [-]
Does fintech here mean "crypto" and central bank currencies transactions?
Ajpop3y 1 days ago [-]
Thank you. It came at a much needed time.
penguin_booze 24 hours ago [-]
> For whom?
It's refreshing to see someone using the correct phrasing.
The often-seen, stupid way is 'who is this book for'.
dapperdrake 1 days ago [-]
First half didn’t sound so bad.
Ajpop3y 1 days ago [-]
Thank you so much for this. It came at the needed time
jgalt212 1 days ago [-]
> Webhooks are the most common way to receive signals from external systems, but processing them safely is not trivial
I see webhooks documented all the time, but I have yet to use them in practice, nor have my customers requested them. Is the above not true, or are they widely used in some sectors and not others?
intelcoders 1 days ago [-]
In payment gateway integration, webhooks are usually considered a single source of truth for updating the payment status, with status check api as a fallback.
f3408fh 1 days ago [-]
They are indeed everywhere, but it's possible you don't have a need for them. For example, every time you buy something online using Stripe, the seller receives a webhook indicating that a purchase was completed.
weatherlight 1 days ago [-]
I receive webhooks all the time as ack that something was processed/ or a notification of the status of some sort of thing in an external system that we don't control.
6 hours ago [-]
vshulcz 23 hours ago [-]
[flagged]
anchorapi 1 days ago [-]
[flagged]
ermantrout 1 days ago [-]
[flagged]
krever 1 days ago [-]
Hey, author here. Happy to take feedback or answer questions.
P.S. I have no clue how HN works, I posted it myself yesterday and it got 6 points. ¯\_(ツ)_/¯
Anyway, glad for the reach.
kevinten10 16 hours ago [-]
[dead]
dc_giant 1 days ago [-]
Sorry have to ask these days. Is this carefully written down information from years of experience in the field or AI slop?
jagged-chisel 1 days ago [-]
Appears that the author got some help organizing the document, but wrote it all themselves.
krever 1 days ago [-]
Hey, author here :)
Its at least 80% organic artisanal writing and maybe 20% AI when I needed help with grammar, completeness, broader perspective and everything around.
logdahl 1 days ago [-]
It may be a good idea to start the book with a really short "About the author" to state exactly this and your work experience. Otherwise looks well written to me, good job! :)
gib444 1 days ago [-]
Native English speaker. I scanned it and IMO there's a slight overuse/misuse of hyphens. Maybe the AI tool could be asked to identify and correct? (The hyphens might be triggering people to think it's AI, too).
They mostly need replacing with a full stop or a colon.
E.g.
"In practice this means storing the amount as an integer in its smallest unit - €12.34 becomes 1234"
->
"In practice, this means storing the amount as an integer in its smallest unit: €12.34 becomes 1234."
or
"In practice, this means storing the amount as an integer in its smallest unit (e.g., €12.34 becomes 1234)"
m00x 22 hours ago [-]
Hyphens here are meant to be formatting. You would be correct if this was a literary piece, but handbooks and sheets don't need to use these rules.
jyounker 22 hours ago [-]
It's a misuse because in this context the hyphen could be mis-construed as a negative amount, and this causes the reader to stop and carefully re-read the content to ensure that they're not misinterpreting it. That's not where you want to be spending your reader's attention.
gib444 12 hours ago [-]
Spelling, grammar and punctuation matter everywhere, in my opinion.
I wouldn't have read your comment if it were all lowercase and used zero punctuation, for example.
jyounker 22 hours ago [-]
I worked for a few years in consumer banking, and this looks like solid advice.
zipy124 1 days ago [-]
Whilst I wouldn't say anything in it requires years of experience to know, this would be helpful for someone who hasn't considered anything about monetary systems. It doesn't read like slop, but I could be wrong but even so it all seems fairly reasonable (I've only fully read about 50% before realising there's nothing new here for me, and then skimmed to rest).
manwithopinions 1 days ago [-]
Skimmed it and based on my experience in fintech, it looks good, accurately represents the real world. I guess there’s still a chance it is AI generated but it doesn’t seem like vacuous slop, it has substance!
thewisenerd 1 days ago [-]
from the author's mastodon post [0]
I just published Fintech Engineering Handbook distilled from 6 years of tears, sweat and swears.
It’s a free ~25-page resource with various hints and patterns around handling money.
Tell me what you think!
other than that, peruse the commits on the source [1], or wait for the author to respond.
The whole avoid floats thing just isn't true. I have 20years experience in fintech and most of it used doubles. Excel uses doubles. Your frontend will use doubles. All your db supports doubles. Your stdlib knows how to parse doubles. Json uses doubles (not in theory but in practice). Many ERP system uses doubles
The thing for working with currency with doubles is that you have to keep in mind that it can hold 15 digits of precision in total. As long as your numbers don't use more digits than that, like 123456789.01 or 123.456789, you can have perfect decimal precision in your financial math. You just have to always round the result to within 15 digits of precision after each computation, and before each comparison. That's what excel does.
The biggest advantage of doubles is that 1) they're widely supported and 2) you can mix different precision in your system, which will appear if you do international finance or advanced financial products. Some accounting require precision up to the thousandth, some need to be rounded to multiples of 0.25. So at the end of the day you'll never use basic math but some specialised accounting math library and that library can perfectly use float as a backend.
tukantje 9 hours ago [-]
I think his experience in the crypto space is part of the reason why he is against it.
Rendered at 18:27:32 GMT+0000 (Coordinated Universal Time) with Vercel.
E.g. If I ever see a monetary value stored in something else than integers I'm going to run away screaming (thank you Rust decimals represented as JSON floats). It's always integers unless you have a VERY good reason to do otherwise (though exported view can be in anything, even in weird bitcoded formats).
FX exchange. Resolution of FX isn't a point-in-time thing, things like buyer rate-in-time, seller rate-in-time, agreement, agreement tolerance, agreed upon resolution timestamp come in the effect.
Immutability - that's why you want to have event sourcing everywhere that touches money:
Though in the end Fintech != Fintech. I worked at Fintech where money was treated like a baggage, and in other where money was a central point of everything.That really overstates the issue. Whole domains of finance run just fine on doubles.
If you're doing Monte Carlo options pricing over interest rate paths, and you're interested in the risk metrics, like durations, convexity, vega, and so on, no one cares what your rounding convention is. doubles are just fine, thank you. How are you going to force `exp(-rt)cashflow` to be an integer? Or the normal CDF?
Yes, there are domains where ints make sense. But it's certainly not universal, you just need to make the right engineering choice.
Like, sure, probably don't use floats for everything, but what are the odds that your greeks are gonna be nicely expressable as simple rationals?
No one cares if you’re mortgage calculator is off by a penny
Doubles are not just fine, but required there. If you compute risk, as you allude to, by finite differences, then you need the precision of floats rather than rounding to integer cents prematurely.
Metrics/durations/convexity/vega aren't monetary value, these are calculation values and I'm fine with them being whatever. If you're calculating averages to make decisions based on this I don't care if you're counting dolars or tomatoes.
Monetary value is $4.50 and it's representation of actual money passed through system. In practice this value is almost never undergoing any operations except for addition and subtraction. Any multiplication/divison etc. is left to specialized systems that return results wrapped in 800 pages of standarization documents, regulations and so on; systems where term "bit flip" is not a joke, but a risk.
As I wrote fintech != fintech, and I know many organizations aren't at that level of scrutiny, but a huge domain of people dealing with others' people money know that charging someone 1 cent too much is a tens of thousands of problems coming their way.
My issue with using integers everywhere is that FX conversions (or other rates) always come into play, and at that point I'm forced to use something else anyway (e.g. arbitrary precision decimals).
In not-a-fintech we just went with doubles and rounded up (worst case - we get a cent more of a customer).
Though if I had to design today for that, I'd look for non-string serializable decimal, so not "10.123 == (10, 123)" but more like (10123, 3) and serialize in JSON as a value and precision separately.
Yet that's only cause I saw Decimal(10,123) sent in JSON as "10.123" which JSON reader red as 10.122 float and inserted to "1012" to database.
"Floats" are simulations of Real Numbers, and Reals are uncountable. Not what you want for finance, where everything is counted.
For FX, it seems like you’re reinforcing what the handbook says, that there’s no canonical rate. Aside from that, it’s talking about post-resolution records and you’re talking about how to resolve, no? That’s valid nuance of a separate goal, and it’s a fine goal of yours, but doesn’t seem like a demonstration of something missing or wrong.
The article appears to make the very same point about immutability? What are you saying that’s different?
The FX critique is saying that it's glossing over a lot of the complexity. I'd say the same is true for the treatment of DE ledgers, and it borders on bad advice (e.g. "Balance is never stored. It’s derived from the movements of money.")
The article clearly communicates this sentiment, no? What else needs to be said? How much further does it need to go, and why?
It might be a mistake for either us or the handbook to be absolute or dogmatic about floats. It’s not a sin to mention that they exist, and it’s a fact that some people in fintech use them for some reasons that have a defensible engineering position and well considered tradeoffs. I’ve been on the side of assuming people don’t use floats for money and then been surprised when I bumped into people here on HN who report using floats in finance routinely.
BTW, is your quote “almost a bad idea” a typo? There’s a world of difference between ‘almost a bad idea’ and ‘almost always a bad idea’. The actual words in the article, if we’re quoting the article, are: “almost never a good idea” in reference to using floating point types.
> it’s glossing over a lot of the complexity.
Of course it is, that’s a good thing. It’s not pretending to be a spec or rules, it’s an introduction and general principles. The article is already introducing new complexities that people outside of fintech might not be aware of. But do we really have to mention ALL complexity? The biggest problem with Wikipedia is that it’s overrun by nuance and complexity, so much that you often can’t read an article on a topic without already being an expert on that topic. This is why experts are often bad teachers. Being unable to gloss over some complexity is not good for learning and doesn’t make a good environment for newcomers. Let’s allow people to write for non-experts and make room for learning. We don’t have to avoid glossing over some of the complexity; it’s useful to get the general direction and gist correct while leaving out some of the detail.
> it borders on bad advice
Be specific. What’s wrong? Note that contributions are invited.
It's like saying "don't write your own crypto algorithm". Of course write your own crypto algorithm, that's how you learn about cryptography. But you'd never put your homegrown cryptographic algorithm into production until after several PhDs worth of understanding of cryptography has been put into it by many other people.
It doesn't make that statement because arbitrary precision decimals exist. Binary float is not the only and not the most plausible alternative to using integers.
Don't think that's bad advice, in particular as the article clarifies:
> Derived state can be cached. Balances and projections can be cached or snapshotted for performance.
Of course you can cache or snapshot. But don't mistake that with storing the golden source.
I don't really agree. This seems like one of those outdated "greybeard rules" which people love to cargo cult, but to me it just comes with its own set of trade-offs, like now you have to think about exponents everywhere and getting them wrong comes with orders-of-magnitude consequences.
If you have a modern DB and your languages handle its decimals well then I'd use them. You can translate as needed for imports and exports, but the core of your system is always sound. Switch to the more basic formats if and only if there was some perf problem with decimals, which for most fintechs will be a VERY long time with modern DBs.
What really pushes me towards decimals is the consequence of getting something wrong. Relying on comparing raw ints, with variable exponents baked in, can lead to catastrophic errors with multi-order-of-magnitude gaps if that implicit exponent isn't carried along correctly. It's a massive footgun always waiting to happen. Decimals avoid that whole class of problem. So the goal is to maximise the "safe" decimals as source of truth everywhere you can, and have very well-tested "in and out" paths for any producers or consumers with different representation preferences. To me, that's good system design. And when, not if, you're manually inspecting DB records to track down a bug, having everything normalized in a glanceable, obvious format like decimals will let you recognise errors faster and more intuitively.
This goes extra for crypto, especially stablecoins, where one USD stablecoin might be exp-6 and another might be exp-9. And you're representing them in the same DB! Off by a factor of a thousand if you miss that exponent! Decimalize that immediately says I.
What do you mean? JSON doesn’t have floats, it has numbers, and how they’re used after being parsed is not part of the spec.
> If I ever see a monetary value stored in something else than integers I'm going to run away screaming
That’s good, then we’ll likely not be working on the same system :) I consider running from “amounts as integer” systems these days (but usually unfortunately can’t). In an idealized codebase that only seasoned financial programmers are allowed to touch, it can go well, but such a system is usually either overly exclusive or risks becoming brittle.
I think that's the problem they were trying to describe. Without a formal spec, systems won't agree on how to handle floats. JS engines treat numbers as 53 bit signed floats, so passing a well defined decimal there through JSON means losing precision at the edges.
Money stored in integers gets around the issue by simple virtue of not really needing more than 53 bits to accurately represent the values anyone is going to encounter.
There are downsides like all the extra math or functions to handle doing the math everywhere money is manipulated or displayed, but this is the sort of thing where static typing is really helpful, and isn't too hard for juniors to understand that they should always use money functions to work with money data.
I do this with HTTP GET and POST form requests as well. In HTTP, everything is a string (even if that string is JSON).
Please do not use Javascript for finance applications. Just do not do it
Save it for user interface elements and dancing whizzimagigs, where it will do less harm.
If you're only working in a single currency, there's usually no issue.
Currency codes can be found in ISO 4217.
Redundancy can be great, but it's not a panacea, since it's not guaranteed to be used in an optimal way.
In the context of Fintech, how do you otherwise resolve floating point rounding issues if not representing amounts with integers?
Do people not know what a floating point number is?
If you want to guarantee that adding cents together results in an exact value without any loss of precision, and you also want a tiny memory footprint and very high performance, then use a binary floating point to represent cents, just as you would use an int.
Also the question of how it's better depends on your use case and my argument is not that one representation is universally better than another, it's that money is used for such a diverse range of use cases that you need to actually understand what you're doing, what the goal is, what the potential issues are etc... in order to pick the right representation for your use case. At my trading firm we have three different Money classes optimized for three different use-cases (with functions to allow interoperability between them).
For the use case where the representation needs to use little memory, is fast, and needs to be used to perform complex financial calculations at an enormous scale, then you use binary floating point where a value of 1.0d = 0.000001 dollars. This gives you exact precision when working with cents, and lets you perform all of the usual financial computations that most quantitative applications need to perform with excellent performance.
We also have a use case optimized for I/O, where no calculations are expected to be performed but the data will be transmitted over a network or to/from a database etc...
If this isn't your domain, maybe you're just writing a GUI application/web app, then by all means use a big decimal or use an integer... I don't know, but it's very sad seeing how many people who are presumably professionals don't take just the bare minimum amount of time to think things through and instead just reason in terms of strict dogmas.
Not across all architectures and operating systems there are not
Listen to those who have done this. Use integers for finance.
It's also safe to return decimal values for displaying values.
You could argue that a price is not really an amount that anyone can actually pay and that's true. But it seems complex and error prone to store unit prices and amounts using different scaling factors.
https://hackage-content.haskell.org/package/base-4.22.0.0/do...
Its a wrapper around an `Integer` where you declare the scale in the type. So if you use `Fixed E2` as your type then `MkFixed 1` is 1 cent. If you did `Fixed E3` as your type then `MkFixed 1` is 0.1 cent. In both cases it is entirely an integer encoding.
You can also use fixed-point if whatever you're using supports it but it's still technically integers.
It seems like a clever idea (fast integer math, no rounding problems for addition and subtraction), but it'll bite you incredibly hard if you ever stumble upon an edge case such as working with a partner that has a different implied number of digits for a given currency. This is especially relevant for stablecoins, which often have a different number of implied decimal digits than the "fiat" currency they represent.
Also, consider representing amounts as a string type in JSON-based APIs. JSON does not specify decimal precision, so you (and all your users/vendors) will always have to make sure your parser/serializer doesn't internally lose precision by going via floating point. This can get ugly fast, and while a string seems conceptually less neat, it completely bypasses that problem. (Some will call this an anti-pattern [1], but I'd rather not fight this particular battle for ideological purity on the shoulders of my users or shareholders.)
[1] https://blog.json-everything.net/posts/numbers-are-numbers-n...
In the HFT space you save some wire space if you can commit to a consistent exponent for some {slice} up front (think instrument/tick-size/asset-class/exchange/feed/server/whatever/...) such that you only need to send the mantissa and your clients can have a hard coded exponent. However, in similar spaces it's often worth the extra uint32 to send a on-the-wire exponent such that things _can_ change and you aren't hamstrung later by earlier "we only need cents now!" design choices when, e.g., you suddenly need to support bitcoin/... prices to full precision. (your users will thank you when they don't have to coordinate a breaking change when you want to adjust your fixed exponent)
Integers have a consistent precision across the entire number line.
https://en.wikipedia.org/wiki/Decimal128_floating-point_form...
What noitpmeder described is just floating point.
That’s essentially the same thing as a String-serialized big decimal, just less readable, no?
Money, even within fintech, is a concept used across a wide variety of domains, and you can't assume that what concerns you is what concerns everyone else relying on it elsewhere.
For added fun, you can introduce division. Some systems will allow you to sell 12345.55 USD to buy EUR at a rate of 1.12345.
The article’s “no lost data” tenet is not really viable when this sort of division is involved. Are you going to track your account balance is a rational number with an absolutely immense denominator forever?
1. If someone sells me 12345.55 EUR, I hope to end up with 12345.55 EUR.
2. That's the point though. They will sell you a certain amount of EUR at a certain dollar price. This, in turn, implies a rate (which might well have more than 5 digits behind the decimal). This is ideally close to the quoted rate, sure. But what counts is the actual EUR amount and the actual USD amount, not what rate was quoted or with how many digits.
Exchanges have calculation rules for every type of mark and payment and will always specify rounding.
There is a remarkable amount of disagreement as to whether one should do one’s back office work based on the price or based on the quantity of the counter currency.
> No one has .0000145 cents in their account. Rounding occurs in the real world.
Indeed. But you either need to convince all parties to agree to round the same way or you need to accept small errors
So, yes, everyone has to understand how all their partners are doing rounding and summing.
I would, however, by quite surprised if my personal bank account did this.
When you owe the bank money, they round up.
This works for USD, JPY or $MEMECOIN and it scales very well.
You can have the blockchain team be an expert in converting integer cents, or the forex team be an expert in sub-cent conversions. You don't want to require _every team_ to have expertise in float math, by default.
Why would that be a problem? You just transform the values when interacting with their API.
Refund $1.00
Repeat
Charge Actual $1.00
Refund $1.000
Alternately
Charge $0.995
ERROR CHARGE AMOUNT MUST BE ROUNDED TO NEAREST CENT
Let's say I operate with a 4 decimal expectation and your API expects 6, is there any way to reconcile that outside of documentation and or metadata ? (which would be the same issue I guess whatever representation is used ?)
Still, even if you do: Chances that your users are just going to assume you're conforming to ISO 4217, some national standard, or your competitor that they're already integrated with are pretty high, so I wouldn't take the chance. Pick something that doesn't have to be documented instead.
This sounds like an unreasonable position to take. “Any” is an unachievable standard that could require an unlimited engineering budget with no demonstrable value in practice.
It is good to identify the lack of a standard, and to talk about what parsers do in practice, and good to discuss the gaps and unmet use-cases. It would be a good idea to suggest that there should be a more reasonable standard, perhaps. It’s just not a good idea to demand that everyone support “any” possibility when no one really needs that, no one knows what it means, and it’s not actually possible to achieve.
I largely agree with TFA: Round explicitly and consistently whenever you cross a boundary, i.e. database persistence and internal API calls.
Use whatever works for your required business case internally (i.e. inside of procedures calculating some function of one or more input amounts). This can be regular old floats/doubles if you absolutely know what you're doing, or BigDecimal if you aren't and would rather suffer slightly slower performance than having to talk to an auditor about IEEE 754 rounding modes, or even minor-amount integers (yes, even though I just said to not use them – but you'll want to ABSOLUTELY NEVER leak them outside of your system, including your data/analytics pipeline, which might have different ideas about financial amounts than your business logic implementing a nice custom monetary type).
Floating-point precision has too many gotchas for being suitable to store Decimal types, especially for the Currency use case.
The semantics for your string “10.00” are complex - is it considered equal to “10”? To “10.000”? To “10.001”?
A user interacting with an API that uses such a string might make all sorts of assumptions about what it supports.
A user interacting with an API that has an explicit decimal places concept is being told ‘decimals matter! They can vary! Here be dragons!’
Yes, but "10 USD" would be a non-canonical representation and you probably serialized incorrectly.
> To “10.000”?
Yes, but same caveat as above applies.
> To “10.001”?
Obviously not, and any system you'd ever want to use in a financial context will tell you so.
In C# e.g., there is type decimal for those computations.
The art is in making those points well-defined and rare enough to not cause large discrepancies, but frequent enough to avoid ballooning arbitrary-precision numbers across databases and services that might not be able to handle them.
Vague-posting seems to becoming more popular
I can't design everybody's systems here, but I was hoping that sharing some war stories that have cost me days or weeks of work might sensitize somebody to a few non-obvious footguns.
What user xlii said about not storing monetary amounts as floats is a common IEEE 754 issue. And while it's true that financial tracking should be done through immutable logs or event-based records, I don't think every surrounding service needs to be built with event sourcing. I think it's enough to apply it only to core logic like ledgers, settlements, orders, and executions. Looking at xlii's comment, it seems like a technique that only becomes viable when the modeling is successful.
User lxgr's comment points out that it's a minor-unit issue. If JSON numbers are parsed as floats by the language or parser, precision can be lost. Usually people send values with a separate decimal places field. However, I've heard that in HFT, they don't do that because the overhead itself is too costly.
And antonymoose's comment aligns with what many books say. That's why designs like this are common in FX or API contexts. It feels like protocol design, doesn't it?
Putting it all together, everyone's right within their own domain. While I think it'd be great to have someone like xlii as my senior programmer, I also feel like I wouldn't be able to design such a complex system myself. In that sense, everyone's statements are valid, and it's interesting to see how opinions diverge depending on the domain. Is this what expertise looks like
Looking at all this, it seems like you can roughly infer where a programmer is coming from based on their experience. Sometimes programming doesn't feel like finding the right answer, but more like choosing a worldview
Watching how programmers model their domains on HN is always fascinating. Sometimes I click on their profiles and add their domain knowledge to my own personal wiki, thinking I might use it someday
I was CTO of a FinTech where I built the whole software stack from scratch: the lessons in the book are mostly correct. I say mostly, because as always, there is a lot of "it depends" to take into consideration for your particular project. For example, I chose to not use event-sourcing to avoid the whole state computation issue. A standard append-only audit trail can do the job.
You can't guarantee exactly-once delivery but you can construct effectively-once processing, and that is what you really want.
Store every request and response : absolutely, and not only when consuming APIs, but when collecting any information from the outside world (and, if you can, also log every intermediate transformation step within your perimeter). Content-adressed buckets + a relational table are great for this.
The text also does not mention anything about data lineage. What happens if a vendor updates some data mid-day that you absolutely need to be aware of? You need to be able to account for that, while also re-playing computations that used the old values and get the same result. It's not a particularly hard problem to solve, but it takes some thought.
Well, in case of a bank it can. And it happens on a daily basis. In fact thats how most private bank money enters the system in the first place either when a bank makes a loan or when it buys any other asset like e.g. a corporate bond (you can conceptualize a loan as an asset purchase as well, the bank buys a promise to pay from the borrower which is recorded as an asset of the bank). Both are a balance sheet extension from a double-entry bookkeeping point of view.
The 4 operations double-entry bookkeeping allows are:
1. balance sheet extension (e.g. making a loan) 2. balance sheet reduction (e.g. loan repayment) 3. asset swap (e.g. a bank buying a government bond with central bank reserves) 4. liability swap (e.g. transferring money from one account to another)
So it may be more accurate to just say that every event that affects the balance sheet must be one of those 4 operations.
Also see "Money creation in the modern economy" - Bank of England Quarterly Bulletin 2014 Q1
Or let me ask you this: What would in your opinion be a valid example of "money out of nowhere"?
You mean it happens when a bank borrows money from a central bank, right?
Not every balance sheet expansion constitutes the creation of money, e.g. when you put money on your bank account, the bank's balance sheet grows, but the money is not newly created.
No I mean in the moment the bank grants a loan. The money the borrower receives is new money, its not taken from anywhere else. But at the same time the bank records the credit as an asset which makes it a balance sheet extension.
> when you put money on your bank account, the bank's balance sheet grows
That's true, you hand over cash to the bank which becomes its asset and your account balance is marked up for the same amount. Not all money in circulation is accounted on a bank balance sheet, but most of it is bank deposits. cash is an exception, it's public money, not private bank money. When you "put money in a bank account", i.e. you bring cash to the bank you are essentially selling your public government money to the bank and it pays you with its own private bank money (which it "creates" as well).
But this is only a micro-view of a single event. In the aggregate money is created when either the government runs a deficit or when banks make loans and money is destroyed when taxes are paid or loans are repaid.
It is very insightful to view money as a creature of accounting for debtor-creditor relations rather than thinking of it as some kind of commodity.
For example the parts talking of retries, idempotency, event ordering, etc. This applies to all systems that require any degree of accuracy, even if no money is directly involved. I've seen so many systems built on the assumption that "we can always retry", but you can only retry if you fail cleanly in the first place, and if the downstream system offers the same level of idempotency that you think it does. Quite often these are not put to the test.
I would prefer to read a defense of something more radical like "database per account." Something that has unique tradeoffs within fintech.
Also, the main advice I would give to fintech engineers/founders is to take risk and compliance seriously from day one.
Financial systems are based around trust. If you don't provably mitigate risks you will lose trust and, eventually, your entire business.
That's putting it politely. Honestly, I think this "handbook" was mostly written by an LLM.
For example, in the immutability section we have this:
In a financial organisation the two go hand-in-hand for obvious KYC/AML reasons.Keeping the financial data whilst trashing the customer names, addresses etc. instantly on-demand before the expiry of the relevant time periods is going to leave your entire organisation with a very bad day in the office if a $lawful_body comes knocking for the data to trace a crime.
People going to work in a Fintech should not be relying on a random "Handbook" written by an unknown person in an unknown jurisdiction.
People going to work in a Fintech should only ever work in accordance with their employer's internal handbooks/guidelines/etc which will have been written in conjunction with their firm's lawyers and compliance people to ensure it complies with the laws and reporting requirements in the jurisdiction(s) in which their employer operates.
Where does TFA recommend that?
As I see it, it recommends separating PII data you'll eventually have to delete from that you'd probably want to keep forever (including data factoring into your accounting equations/invariants), so that you can delete the former after the relevant recordkeeping periods have elapsed.
> People going to work in a Fintech should not be relying on a "Handbook" written by an unknown person in an unknown jurisdiction.
Sure, but they should also not blindly ignore any ideas and practices presented, or avoid looking beyond their own organization. Ideally, they'll then try to reconcile what they saw with their own knowledge and local regulations etc.
> People going to work in a Fintech should only ever work in accordance with their employer's internal handbooks/guidelines/etc which will have been written in conjunction with their firm's lawyers and compliance people to ensure it complies with the laws and reporting requirements in the jurisdiction(s) in which their employer operates.
Sure, in a world in with only perfect and error-free organizations, that seems like a reasonable approach. But how does one get there without having a conversation such as this one?
Unless its your job to architect stuff, in a financial firm you don't go looking around for ideas and practices.
You comply with your employer's practices end of story.
If you like looking up ideas and other people's practices then a heavily regulated environment is probably not the place for you.
> how does one get there without having a conversation
"having a conversation" about new ideas/practices in a regulated firm will involve lawyers and the compliance department.
More than likely that "conversation" will be above most people's pay grade. So you're better off just not wasting your time and adhering to your employer's existing practices.
And for everyone else, its an expensive and high-friction conversation to have if you want to change existing practices.
> You comply with your employer's practices end of story.
What if you're the employer ("first engineer" etc.), and there are no practices yet? Fintech almost by definition sometimes includes doing things from scratch because some existing solution or incumbent organization isn't working that well anymore.
> Unless its your job to architect stuff
Which seems to be the target audience/scenario for TFA.
In that scenario the practices will still come first. You're not going to be doing any coding or systems engineering until you've got compliance signed off. You're going to be spending lots of time with lawyers and compliance people.
> Fintech almost by definition sometimes includes doing things from scratch
Yes, but cut through the noise of the typical Fintech fancy website and app and you're still staring straight down the barrel of spending 80% of your time on regulatory compliance.
Try as you might there are only so many ways you can re-invent the wheel for dealing with hard-facts legislation.
And if your lawyers and compliance people are actually telling you that you can absolutely not do any financial processing yourself, that the only possible way to be compliant is to license <incumbent product xyz> (unfortunately only available in COBOL) etc., you might not actually be working in a fintech, or at least not in the kind this guide seems to be targeted to.
Frankly, this kind of attitude is exactly why banking and payments is as fossilized as it is in some countries, and why fintech is eating their lunch in many cases. There has to be a balance between trying new things and doing what everybody else is already doing.
Your expectations of course are not unusual because so many developers work on systems where users are not the customers, but the product.
Facebook, Insta, Google all fuck up results very regularly, but what are you gonna do when they do?
Now imagine your bank occasionally losing deposits, your account balance going up and down a percent or two every day, the IRS fining you for tax evasion because your Cool Fintech Rounding does not match generally accepted accounting rules.
Many of these predate the widespread knowledge of idempotency, so often idempotency keys are hacked together by joining various, hopefully globally unique fields, except that they never quite are. (You can look behind the curtain sometimes, e.g. when your bank does not let you transfer the same amount to the same recipient account on the same calendar day.)
I've spent many hours explaining how idempotency is supposed to work, and why it's important. Most teams understand the need for it, but very few thought about it up front.
That way I can debug and have a last resort of compliance, but also save time by not building the first resort of compliance.
I don't care if the balance is one million, before that ACH can process, every single dollar can be (a) wired out, (b) cleared out by yesterday's ACHs (bills, autopay, whatever) and checks, or (c) spent at debit/ATM.
I probably shouldn't tell you why I know that some fintechs don't address this.
I'm founding a fintech startup and have been thinking about these things a lot. It is very helpful to have some general validation and guidance to make sure I'm not making huge mistakes.
I really wanted event sourcing, but thought it gets complicated when events have complex validation rules. I ended up with a mix of state and audit logs which works ok for now.
I would recommend anyone starting in fintech to take some time to understand accounting principles and the ledger in a bit more depth than just debits vs credits - this is likely what is most unfamiliar to programmers.
Also financial software is very data-heavy and I learned more about databases in my time working in fintech than the 15 years before that. I think going into a bit more detail about even the basics (indexes) will save a lot of headaches.
Probably good advice (for everyone in fintech, not just programmers) considering the absolute disaster that happened at Synapse. Kind of wild nobody has gone to jail for that.
I am curious as I had a bit of money in Yotta.
Any good resources you would recommend to learn more about this?
[1] https://www.moderntreasury.com/journal/accounting-for-develo...
[2] https://www.moderntreasury.com/journal/how-to-scale-a-ledger...
To learn how and why these things are traded, however, read this book, the only (good) truly beginners guide to fixed income:
https://www.jdawiseman.com/books/pricing-money/Pricing_Money...
A few examples: Some stocks trade in one currency, but pay dividends in a different currency. Some stocks go ex-div before the dividend amount has been determined (e.g. in Japan). Stocks trade on certain days, and trades settle on certain days, and they might be subject to different holiday calendars. Corporate actions are not entirely trivial, either (with rights issues, you need to issue two temporary securities for accounting purposes, etc.).
If you're dealing with a party who tracks currency in cents, then tracking currency with more precision than that is going to lead to rounding disagreements. Vice versa if you deal in cents but they deal in tenths of cents. And so on for all the other advice in this document.
It's refreshing to see someone using the correct phrasing.
The often-seen, stupid way is 'who is this book for'.
I see webhooks documented all the time, but I have yet to use them in practice, nor have my customers requested them. Is the above not true, or are they widely used in some sectors and not others?
P.S. I have no clue how HN works, I posted it myself yesterday and it got 6 points. ¯\_(ツ)_/¯ Anyway, glad for the reach.
Its at least 80% organic artisanal writing and maybe 20% AI when I needed help with grammar, completeness, broader perspective and everything around.
They mostly need replacing with a full stop or a colon.
E.g.
"In practice this means storing the amount as an integer in its smallest unit - €12.34 becomes 1234"
->
"In practice, this means storing the amount as an integer in its smallest unit: €12.34 becomes 1234."
or
"In practice, this means storing the amount as an integer in its smallest unit (e.g., €12.34 becomes 1234)"
I wouldn't have read your comment if it were all lowercase and used zero punctuation, for example.
[0]: https://mas.to/@krever/116814803588993437
[1]: https://github.com/Krever/fintech-engineering-handbook/commi...
The thing for working with currency with doubles is that you have to keep in mind that it can hold 15 digits of precision in total. As long as your numbers don't use more digits than that, like 123456789.01 or 123.456789, you can have perfect decimal precision in your financial math. You just have to always round the result to within 15 digits of precision after each computation, and before each comparison. That's what excel does.
The biggest advantage of doubles is that 1) they're widely supported and 2) you can mix different precision in your system, which will appear if you do international finance or advanced financial products. Some accounting require precision up to the thousandth, some need to be rounded to multiples of 0.25. So at the end of the day you'll never use basic math but some specialised accounting math library and that library can perfectly use float as a backend.