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.
lxgr 3 hours 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)
lxgr 34 minutes ago [-]
> 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?
microgpt 37 minutes ago [-]
If you do that though aren't you just reinventing floating-point?
antonymoose 2 hours 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 51 minutes 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).
DetroitThrow 51 minutes 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.
denismenace 3 hours 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.
microgpt 36 minutes ago [-]
Customer was charged $0.995 after fees, how to represent in your data model with integer cents?
xlii 2 hours ago [-]
Exactly, model is in integers and representation can be 1⃣3⃣ or whatever, that's why model-view separation exist.
lxgr 2 hours 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").
lxgr 3 hours 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 2 hours 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 2 hours 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.
gucci-on-fleek 3 hours 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 3 hours 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 2 hours ago [-]
A string type. As parent says: it completely bypasses the problem. Save the numbers between double quotes and be done with it.
portly 2 hours ago [-]
Storing numbers as arrays of u8? That doesn't make sense
ivanmontillam 1 hours 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)?
lxgr 33 minutes ago [-]
It makes a lot of sense if you value correctness over performance.
microgpt 23 minutes ago [-]
Why not store them in unary then?
KellyCriterion 2 hours 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 2 hours 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 hours 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 27 minutes ago [-]
Not at all, and thanks for writing all of this up!
necrotic_comp 2 hours 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.
belmarca 24 minutes 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.
jdw64 36 minutes 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
benashford 2 hours 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 15 minutes 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 hours ago [-]
[dead]
danielabinav160 3 hours ago [-]
The idempotency keys section alone is worth the read most devs learn that lesson the hard way.
lxgr 2 hours 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.)
__natty__ 3 hours 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.
pards 3 hours 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.
rTX5CMRXIfFG 39 minutes 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
koliber 1 hours 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__ 47 minutes 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:
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.
sdevonoes 2 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
Any good resources you would recommend to learn more about this?
dapperdrake 3 hours ago [-]
First half didn’t sound so bad.
jgalt212 1 hours 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?
weatherlight 12 minutes 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.
intelcoders 1 hours 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.
dc_giant 3 hours 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 3 hours ago [-]
Appears that the author got some help organizing the document, but wrote it all themselves.
krever 2 hours 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 hours 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! :)
thewisenerd 3 hours 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.
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 3 hours 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!
anchorapi 57 minutes ago [-]
[flagged]
ermantrout 43 minutes ago [-]
[flagged]
krever 2 hours 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.
Rendered at 14:09:22 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.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)
That’s essentially the same thing as a String-serialized big decimal, just less readable, no?
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.
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.
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.
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.
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.
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
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.
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.
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...
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.
Any good resources you would recommend to learn more about this?
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?
Its at least 80% organic artisanal writing and maybe 20% AI when I needed help with grammar, completeness, broader perspective and everything around.
[0]: https://mas.to/@krever/116814803588993437
[1]: https://github.com/Krever/fintech-engineering-handbook/commi...
P.S. I have no clue how HN works, I posted it myself yesterday and it got 6 points. ¯\_(ツ)_/¯ Anyway, glad for the reach.