ASF

Keeping a Prediction-Market Book Fresh, Quickly

August 18, 2026|
A
A

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.

Grouped bar chart of round-trip and handshake latency by vantage point
Round-trip and handshake by vantage point, log scale. Kalshi collapses from 77 ms in Kuwait to 1.4 ms in us-east-1: it is native to the region. Polymarket edge handshakes stay small at both points, yet its ping to origin holds near 88 ms from us-east and 92 ms from Kuwait.

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.

Bar chart contrasting edge handshake against origin round-trip for Polymarket from us-east-1
Polymarket from us-east-1, log scale. Two protocols agree: the WebSocket ping to origin returns at 88 ms and the order-book REST endpoint returns its first byte at 114 ms while completes at 16 ms. The socket terminates one edge away; the data travels much further.

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.

Percentile summary of Polymarket WebSocket ping round-trip from both vantage points
Polymarket ping/pong round-trip, min to p95 shaded, median and p99 marked. A 15 ms tail sits over a tight body, and the median holds near 88 ms from us-east-1 across fifty pings.

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.

Horizontal bar chart of ingest throughput in million frames per second by entrant
Ingest throughput on one core, coloured by class. C and tuned Rust reach 2.8 million frames a second; idiomatic Rust holds 1.3 million with memory safety and no collector; Java through Gson and BigDecimal trails at 42 thousand.

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.

Horizontal bar chart of nanoseconds per frame on a log axis by entrant
Cost per frame, log scale. A zero-copy parse over a bespoke integer book sits at one end; a document object model or a boxed decimal sits at the other. The nlohmann DOM lands among the interpreters, below Node.
Grouped scatter of throughput by parsing strategy
Throughput grouped by approach. Zero-copy and fixed-integer entrants cluster high across three languages; the document-object-model, managed-JIT, and interpreted groups fall away in turn. Approach separates the field more than language does.

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

Dumbbell chart of best against median nanoseconds per frame by entrant
Best against median across seven runs, log scale. The compiled entrants hold under a percent of run-to-run spread; the interpreters widen slightly. A tight best-median gap is what lets the ranking carry weight.

4. Both axes together

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

Log-scale timeline placing per-frame parse cost against wire latency
One update on a log time axis. Parse and apply cluster in the hundreds of nanoseconds to tens of microseconds; the wire spends milliseconds to tens of milliseconds. Over five orders of magnitude separate the two ends of the path.

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.

Scatter of the entrants across two axes, memory safety and whether a garbage collector runs, sized by throughput
Every entrant placed by whether a collector runs and whether memory safety holds, sized by Polymarket throughput. The safe and collector-free corner is the one the hot path wants; Rust holds it at full speed, Fil-C at a fraction of it, and C and C++ reach that speed only in the unsafe corner.

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.

Bar chart of nanoseconds per frame, clang -O2 against Fil-C -O2, for the same nlohmann parser on each market
Identical nlohmann parser, clang against Fil-C , on the same c7i.large. The memory-safe build carries a several-fold runtime tax on both markets.

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.