Emilyjones
Could OTP handle the latency demands of a crypto order matching engine?
Been thinking about this after seeing a few concurrency and distributed-systems threads pop up here lately. Curious what the more systems-minded folks in this community think.
An order matching engine is the part of a crypto exchange that pairs buy and sell orders and decides who trades with whom, all in real time, under serious load. The two things that matter most are correctness and latency. You need every order processed in the right sequence, with zero room for race conditions, while still handling tens of thousands of orders per second without falling behind.
On paper, that sounds like exactly the kind of problem OTP was built for. Model the order book as a GenServer or a set of processes per trading pair, lean on message passing instead of shared mutable state, and you get a natural way to serialize order processing without hand-rolled locking. The BEAM’s preemptive scheduling also means one heavy computation on the matching side shouldn’t be able to stall the whole system the way it might in a single-threaded event loop.
Where I’m less sure is whether the GC pauses or process messaging overhead become a real bottleneck once you’re chasing the microsecond-level latency that serious matching engines aim for. Most production write-ups I’ve come across take a more traditional low-level approach for the actual matching logic. There’s a decent technical breakdown of how a matching engine is typically architected here if anyone wants the non-Elixir baseline to compare against: order matching engine in crypto exchange development.
Has anyone here actually built or benchmarked something matching-engine-adjacent in Elixir, even a toy version? Would love to know where it started to strain, whether that was GC, messaging overhead, or something else entirely.
First Post!
ausimian
You will have to measure on your intended hardware. You should consider that 1-3micros is probably best-in-class for pure ‘software’ based trading engines (tick-to-order), or at least was when I worked in this space, admittedly over 6 years ago now.
This relies on full ethernet kernel offload to userspace, and then fast (e.g. c++ with typically little allocation / arena allocation) single-threaded engines running in a hot loop, pinned to a physical core and the kernel told to ignore that core for scheduling purposes. There are a number of things here that make it unlikely that you’ll compete successfully with engines like these, before you even get into GC, cache-unfriendly data structures (pointer chasing), branch mis-prediction etc.
That said, if you can successfully trade via a strategy that is not so latency focused then I think the beam would make a pretty great starting point. GC is per-process and generally constrained. Process isolation gives you some reliability guarantees.
I would probably run each instance of a strategy (e.g. per instrument ) in its own process. If you have multiple strategies trading the same instrument, you may need some way to amortize their orders, if you’re not allowed to cross yourself in the markets you trade.
Importantly, I would have your data feeds (e.g. order-book) update ETS tables and then just ‘ping’ your strategy to wake up and re-evaluate the data inside them. Sending market data as messages into the mailbox of your strategy risks you trading on out-of-date information.
As background, I was working on FPGA based trading engines over a decade ago where latencies were around 250ns from memory, some of this was simply bounded by how quickly you could clock in bits off the wire, make a decision and start clocking bits out. I believe we may even have had a version that started clocking bits out before the full packet had been ingested, with ip-checksum poisoning used to ‘abandon’ the packet if there was no good order to be sent. Fun times.
Popular in Discussions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









