~2s → ms
reaction after a partial fill
Measured before → after on the one event that actually costs money: reassembling a position after a partial fill.
HQ Paphos, Cyprus · worldwide
99 Francs designed and built an automated trading and market-making system for an independent quantitative trading desk on Polymarket. We kept the quant logic in Python and moved only the latency-critical execution path into a Rust sidecar — cutting the reaction time on the most expensive event from roughly two seconds to the low tens of milliseconds, without rewriting a line of strategy code.

The headline win is the reaction time on a partial fill — a measured before / after, with a sub-20 ms in-process decision budget verified against recorded market data.
~2s → ms
Measured before → after on the one event that actually costs money: reassembling a position after a partial fill.
~100×
Round-number framing of roughly two seconds down to the low tens of milliseconds.
2,700+
Across Python (1,731) and the Rust execution crate (~1,000) — unit, replay and certification runs.
~2 months
A bounded sub-project, flag-gated per market and validated live before being armed under a formal certification.
A Python quant engine, a low-latency Rust execution core, a React control dashboard, a full backtesting and replay system, and a safe virtual-to-real rollout. We build the infrastructure and the safeguards — strategy and returns stay with the client.
The desk needed an execution path fast enough to avoid getting picked off, a way to test many strategies without risking capital, and a gated, reversible route to putting real money on-chain.
On a fast market a resting quote that is not pulled in time gets picked off. The original Python control loop ran on a multi-second poll, so the follow-up quote after a partial fill appeared 0 to 2+ seconds late — long enough to turn a small, reliable profit into a several-times-larger loss.
The desk needed to compare dozens of strategies on live and recorded data — in a paper mode indistinguishable from real — before a single dollar moved on-chain.
Going live had to be deliberate: fail-closed on any stale feed, reversible behind flags, and armed only after formal certification.
Four surfaces, each with one job — with the millisecond-sensitive work isolated in Rust so the rest could stay in the language it belonged in.
The financial source of truth — strategy models (numpy / scipy), market discovery, EIP-712 order signing (web3), accounting, risk stops, alerts. Trusted and easy to change.
A low-latency sidecar (tokio + the venue's official Rust CLOB SDK) owning only the millisecond-sensitive work: a lock-free order-book cache, a ~5 ms decision tick, place / cancel, and folding fills into inventory in real time.
A single-page app (lightweight-charts + recharts) with a tab per strategy, live equity curves, a signal-log browser, real-wallet equity and one-switch mirror settings.
An Express API over a single SQLite book-of-record — strategy configs as rows, live heartbeats and circuit-breaker state, and safe start / stop of the engine.
Live price feeds and the venue order book continuously update in-memory state. The Python engine runs each enabled strategy in its own loop; when conditions are met it sizes the position against real book depth, signs the order, and either sends it directly or — for the market-making path — hands the quote context to the Rust sidecar over a local Unix socket. The sidecar owns the millisecond place / cancel loop; fills stream back over a user-WebSocket, reconcile into inventory and write to SQLite, which instantly powers the dashboard and Telegram alerts. The sidecar is best-effort: if it drops, Python falls back to native handling — it can never take the system down.
The obvious answer — “rewrite it all in Rust” — was the wrong one. The quant models, signing, accounting and risk were correct and valuable. We moved only order-book ingestion, the decision loop and place / cancel into a Rust sidecar; the core migration landed in about two weeks, and the full execution plane followed over the next weeks.
| What we measured | Before (Python) | After (Rust plane) |
|---|---|---|
| Reaction after a partial fill | 0–2+ seconds | low tens of ms (sub-20 ms in-process decision, verified on recorded market data) |
| Decision tick | multi-second poll | ~5 ms |
| Cancel path | Python HTTP round-trip | removed from the hot path |
| Strategy code rewritten | — | none |
Strategy thresholds and formulas stay the client's — what we built is the system around them.
Every strategy is a config row, enabled or disabled independently, each with its own dashboard tab. Roughly 25+ variants — arbitrage, market-making, momentum, latency — have run side-by-side on live data.
Every strategy runs simulated by default; any one can be mirrored to a real-wallet configuration, with a flag on every trade distinguishing virtual from real.
Fills are modelled against real order-book depth, not the midpoint — replaying six years of minute data, real recorded venue prices, and full captured order-book sessions on a monotonic clock with a latency sweep.
Depth-weighted imbalance across the top levels flags when the market has abandoned a side, with hysteresis and staleness guards — so the maker stops buying the losing leg instead of chasing it.
Orders are formed and signed before they are needed, and a WebSocket-reactive requote loop cancels a stale leg in milliseconds — shrinking the window in which a resting quote can be picked off.
~20 typed alerts (placements, resolutions, daily stops, guard pauses) plus a React admin for per-strategy config, mirror settings and strategy creation.


On the platform's A/B framework the client backtested around 65 strategies. One automated arbitrage strategy reached +955% ROI at a 77.1% win rate across 481 fully automated trades over ~4 months. That is the client's own result on our infrastructure — we make no performance promises and never sell returns; we build the system that lets a quant team find and validate strategies safely.

Spec-driven and test-heavy: a detailed design doc — reviewed independently before a line was written — preceded every milestone, each shipped in small, feature-flagged, reversible steps.
We stood up the three-tier stack, migrated to the venue's V2 API, and shipped the first arbitrage family — establishing functional correctness before any optimisation.
The center of gravity: proliferating and hardening strategies, diagnosing where the market-maker was getting picked off, and building the first fast-cancel Rust sidecar.
We refactored the engine into a registry-driven layout, made inventory accounting exact, and moved the book and decision loop into Rust — the core migration landed in about two weeks.
We extended the sidecar to serve several markets at once, then ran an explicit measurement phase — verifying latency and parity against recorded data before scaling by diversification, not size.
Every major milestone passed multiple rounds of independent AI code review before merge, and the live controller stays flag-gated per market — a control surface for safe rollout, not a sign the path is unfinished.
Each order's ID is derived from its signature before it is sent, so a lost network response never means a lost order.
Fills are counted in integer micro-units, never floating point — no rounding drift at any size, and idempotent writes survive restarts and WebSocket replays.
A stale feed, a dropped socket or a watchdog timeout all resolve to “stop quoting,” never “quote on stale prices.”
The autonomous Rust controller runs the full decision → place → cancel → fill loop on its own, with its latency wins validated live. Because it trades real money, every part sits behind feature flags — armed, paused or rolled back instantly per market — and was cleared by a formal certification: zero accounting drift, 100% canonical-path fills, zero secrets. The flags are a safety feature, not a sign the path is unfinished.
Have a system that's fast enough to be dangerous but slow enough to leak money?
Only for the latency-critical path. Here the problem was a slow control loop, not a slow language: a multi-second poll left the follow-up quote seconds late. We kept the quant logic in Python and moved only order-book ingestion, the decision loop and place/cancel into a Rust sidecar. More on the approach in our Python-to-Rust migration write-up, and the Python development service.