Keeping a Prediction-Market Book Fresh, Quickly
Two questions decide how fresh a consolidated prediction-market book can be: where each byte originates, and what that byte costs once it lands. Distance answers the first and no software repeals it. Parser and decimal arithmetic answer the second, and those answer to engineering. This post measures both on Kalshi and Polymarket: a network probe from two continents, and a twelve-entrant ingest race across nine languages that all reconstruct the identical book.
Start with the second question, because it renders as motion. Each lane below is one entrant, a language at its idiomatic best or a hand-tuned build of it. Its speed is that entrant's ingest throughput on the shared corpus, so a faster entrant is a faster ball. Toggle the market to re-set every speed to the numbers measured on that venue's wire format.
C and tuned Rust streak across their lanes while Java barely moves. First, the wire.
1. Pipeline and its ledger
A single update travels a fixed sequence of stages. A matching engine emits an event; it serialises to JSON; it crosses a TLS WebSocket through a content-delivery edge; it lands in the client kernel; userspace unmasks the frame, parses the JSON, applies the delta to a book, and folds the book into a fingerprint. The diagram below runs one packet through that path. Toggle the venue and the propagate leg re-times itself to the measured wire latency, and the readout swaps to that venue's numbers.
One property of the parse stage carries through the whole post: it reads bytes that arrived from outside, over a socket an external venue controls, so whatever language runs there runs on untrusted input. Section 4 returns to what that costs when the language is memory-unsafe.
The fingerprint is the correctness check. Across all books, let be the count of price levels, the sum of resting quantity, and the sum of notional,
with prices and quantities held as exact integers on a fixed scale. The triple is a trial balance: every entrant, in every language, must reproduce it bit for bit before its throughput counts. A parser that drops a level or rounds a price fails the balance and is disqualified, whatever its speed. Every number in this post clears that check first.
2. Origin of the bytes
2.1. Two probes, two continents
Two probes ran from a residential connection in Kuwait and from a throwaway instance in AWS us-east-1, within the same minute. A bare TCP connect to port 443 needs no authentication and terminates wherever the socket terminates. A WebSocket ping, timed to its pong, is a round-trip immune to clock skew. Both ran against Kalshi and Polymarket.

2.2. Edge hides the handshake, never the origin
Kalshi sits behind a CloudFront edge in Ashburn and answers from an origin in us-east. A bare connect is 0.73 ms in region, and its public status endpoint returns a first byte at 21 ms, so the origin rests about 9 ms behind the edge. Kalshi is native to us-east, engine and all.
Polymarket reads differently. TLS terminates at a Cloudflare edge close to every client, 1.4 ms in us-east and 2.4 ms in Kuwait, yet the WebSocket ping travels end to end and returns at 87.6 ms from us-east and 91.8 ms from Kuwait. Near-identical, from two points 180 ms apart, with a tight distribution that reads as fixed propagation.

A second measurement agrees from a separate protocol. The order-book REST endpoint returns its first byte at 114 ms while TLS completes at 16 ms, placing the origin about 98 ms behind the same Ashburn edge. An origin roughly equidistant from Ashburn and Kuwait sits in the European region and lies an ocean away from us-east.

One consequence carries. A consolidated book's Polymarket leg is floored near 44 ms one-way from anywhere in the United States. Colocation buys single-digit legs to a us-east-native venue and buys nothing against a venue whose origin lives across the Atlantic.
3. What a frame costs
3.1. Method
Nine languages, twelve entrants counting the tuned variants, each reconstruct the same corpus of two million book deltas. Every entrant ran alone on a core-pinned c7i.large, best of seven, with the page cache dropped before each run and stray processes swept after. Every one produced the identical fingerprint, so the throughput numbers stand on equal correctness.

3.2. Two orders across languages
Cost per frame spans two orders of magnitude, from 358 ns to 23.6 microseconds. The gap is parser strategy first and language second. It is also a safety split: C and tuned C++ carry no bounds or aliasing checks, the absence that makes them memory-unsafe, while the tuned Rust matches their class with both kept.


PyPy earns almost nothing over CPython, because the hot path is Decimal arithmetic and a C-level parser, and a tracing JIT accelerates neither. orjson lifts CPython above Go and both stdlib variants. Node's V8 leads the managed runtimes. Java through Gson and BigDecimal is the outlier, carried down by object churn and boxed decimals; a fixed-integer rewrite would lift it the way it lifts every other language.
Wire format moves these numbers as much as language does. Kalshi ships each delta as one signed increment; Polymarket ships a full ladder as an absolute-size set. So Java, whose cost lives in boxed-decimal churn, runs seventeen times faster on Kalshi than on Polymarket, 1.4 microseconds against 23.6, and the Python entrants re-rank between the venues. Toggle the market on the first figure to watch the field reorder.
3.3. Measurement quality

4. Both axes together
Wire and core are two segments of one path, and they live in different regimes.

Wire time is milliseconds and geography fixes it; per-frame time is nanoseconds and the language fixes it. The edge terminates TLS close to every client and hides the handshake, never the tunnel back to a distant origin, which the interactive byte path at the top traces one packet at a time.
A broker folding many venues pays the worst wire leg once and the per-frame cost on every update of every market. At 358 ns a core absorbs 2.8 million frames a second; at 764 ns idiomatic Rust absorbs 1.3 million. Four of the entrants run on a managed runtime, and each carries an allocation or compilation pause in its tail that the compiled, non-collected entrants never show. When the wire already spends 44 ms reaching a venue across the Atlantic, a garbage-collection pause added at the core is the one avoidable latency on the whole path.
Memory safety is the second half of the case, and it turns on the same hot path.
4.1. Memory safety at the trust boundary
The parse stage sits where untrusted bytes meet a privileged process. The wire arrives over a socket that a compromised feed, an intermediary, or a market maker shaping frames can influence, and the book it builds drives order entry. A memory fault in that parser is a security exposure as well as a reliability one.
The faults have names, and each fits this workload. A truncated or malformed frame can walk a C parser past the end of its input and read adjacent memory. An attacker-sized level count can write past a book buffer and corrupt the heap. A price scaled to an integer can overflow and wrap, corrupting a control total. A book that grows and reallocates can leave a live pointer to a freed level.

Each fault has a worst case. The mild one is a crash: the ingest dies mid-session, the book freezes, and downstream quotes run off stale prices at the moment a volatility spike lifts the message rate that triggered the fault. The expensive one is silent corruption: no crash, a wrong book, and a strategy trading a phantom price with real money, caught only when the fingerprint happens to diverge. The severe one is remote code execution: a buffer overflow driven by attacker-shaped wire hands control of the trading process, with its credentials and its order entry, to whoever shaped the bytes.
The map above sorts every entrant by two properties: whether a collector runs, and whether memory safety holds. Three corners are occupied. C and C++ sit in the unsafe, collector-free corner, fast and exposed. Go, Node, Java, and the Python interpreters sit in the safe, collected corner, out of danger and carrying the pause. The safe, collector-free corner is the one the hot path wants, and Rust holds it. The fourth corner, unsafe and collected, stays empty, because nobody adds a collector and keeps the unsafety.
4.2. Retrofitted safety and native safety
C and C++ can be made memory-safe after the fact. Fil-C compiles unmodified C and C++ and enforces pointer safety at run time. Running the identical nlohmann parser through it, against the clang -O2 build of the same source, prices the guarantee.

On Kalshi the safe build costs 11,852 ns a frame against 2,707 ns for the unsafe one, a 4.4-fold tax; on Polymarket, with its heavier ladders, 19,775 ns against 4,097 ns, a 4.8-fold tax. Fil-C shows the safety is reachable from C++, and it shows the bill: a parser made memory-safe at run time runs almost five times slower.
The hand-tuned Rust is the other end of that measurement. It reaches 359 ns a frame on Polymarket and 276 ns on Kalshi, in the same tier as C, and it does so with no unsafe block anywhere in its source. The tuning that took Rust to C-class throughput removed none of the safety. C and C++ reach that speed by staying in the unsafe corner; Fil-C leaves the corner at a four to five-fold cost; Rust was never in it. Throughput next to C, safety without a collector, and a p99 with nothing hiding in it: that is the case for writing the hot ingest in Rust.
5. Provenance
Measured 18 August 2026. The network probe is pure-stdlib TCP-connect and WebSocket ping/pong, the latter immune to clock skew, run from Kuwait and from AWS us-east-1. Kalshi sits behind CloudFront in Ashburn; Polymarket sits behind Cloudflare, edge in Ashburn, origin in the European region. The compute race ran on a us-east-1 c7i.large, one core pinned, page cache dropped before each run, best of seven, over deterministic corpora of two million deltas built from a fixed seed. Every entrant produced the identical fingerprint before its number counted. All hosts and credentials were torn down after measurement.