# BTC 5-min Polymarket Bot

> One engineer ran a 219k-line production trading system solo, under 13 quality gates that cannot be bypassed.
>
> https://pravda.systems/work/btc-bot · 2026-06-13

**Problem.** Trading Bitcoin's 5-minute prediction markets means reacting in under a second across 11 live exchanges, normally a four-person team's job.

**Solution.** One engineer built and runs it solo using AI agents: a production Rust system that reads 11 exchanges, scores an ML model, and prices each bet in microseconds.

**Outcome.** A live system on AWS (paper mode, no real money) that decides in 21 microseconds, locked behind 66 frozen design records, 13 unskippable quality gates, and 102 stress tests: the same discipline you get on simpler automation work.

## Key metrics

- **291M / day** Market events captured per day — 11 venues, 49 event streams, one capture day (2026-06-11), ~3,370 events/second _(verified: DuckDB row count over data/microstruct/2026-06-11/*/*/*.parquet on the synced prod mirror)_
- **21 µs p50** Decision speed, in production — median time to price a bet and decide, measured over 506,243 live calls (2026-06-12) _(verified: duration_ns percentiles of span_name=evaluate_reflex in data/spans/live/2026-06-12 tracing parquet)_
- **2,948 passing** Automated tests — Rust workspace suite, zero failures at the last recorded full run (2026-06-11). The suite has grown since: 3,258 test attributes are in the tree today, but this states the last run whose PASS was actually recorded rather than a count of tests that exist. _(verified: cargo test --workspace result recorded in docs/planning/optimization-pass-2026-06-10.md state log, 2026-06-11)_
- **13 strict gates** Quality gates per commit — AI code review, supply-chain audit, schema-drift and doc checks block every commit. No bypass flag exists. _(verified: PHASE1_GATES + PHASE2_GATES roster in scripts/hooks/run_gates_parallel.py)_
- **102 runners** Soak-test runners — data-completeness, latency-budget and invariant checks against a prod mirror synced every 5 minutes _(verified: count of tests/soak/run_*.py)_
- **99.8%** Capture reliability — 5-minute capture partitions present over the last 19 full days (5,461 of 5,472) _(verified: collector_heartbeat.parquet partition presence per day, data/microstruct 2026-05-24..2026-06-11)_
- **3,139 commits / 123 days** Solo delivery pace — one engineer with AI agents under strict review gates, 2026-03-21 to 2026-07-21 inclusive _(verified: git rev-list --count HEAD = 3139; first/last commit dates from git log --date=short)_
- **219k lines of Rust** Codebase — 389 Rust files across crates/ and xtask/, plus 77,747 lines of Python test and ops tooling over 220 files, and 66 architecture decision records _(verified: wc -l over git-tracked crates/ + xtask/ *.rs (219,450 across 389 files) and tests/soak + scripts *.py (77,747 across 220); ls docs/decisions/ADR-*.md = 66)_

## The problem

**Trading Bitcoin's 5-minute prediction markets is normally a four-person job. This project asks whether one engineer can do it.**

Polymarket runs a binary market on Bitcoin every five minutes: will the price be up or down at the close. To trade it you need three things at once: fresh data from many exchanges (because the answer is being decided right now), software fast enough to act inside the 300-second window, and enough verification that you can let it run unattended, with real-money authority one flag away.

That is normally a team's job: a data engineer, a backend engineer, an SRE, and a quant developer. The question this project answers is whether **one engineer, working with AI agents under strict review gates**, can build and operate the whole thing.


## What it does

**A live Rust system on AWS prices a bet and decides in 21 microseconds, measured, not estimated.**

Two always-on Rust services run on a single small ARM cloud instance. The collector connects to **11 venues** (Binance, Coinbase, Kraken, OKX, Bybit, Deribit, Gemini, Bitstamp, Chainlink and Polymarket among them) across **49 event streams**. On 2026-06-11 it captured **291 million market events**, about **3,370 per second**, writing roughly 7.7 GB of compressed columnar data that day into a research corpus now spanning about 147 GB.

The trading process consumes that feed over shared memory and decides, on every top-of-book change, whether to place an order. Production tracing puts the full decision pass at a **21 µs median and ~60 µs at the 99th percentile, measured over 506,243 live calls** in a single day. A machine-learned model re-scores the market roughly once a second, whenever a fresh exchange candle lands.

It runs in **paper mode**: every order takes the real signing, risk-check and venue round-trip, then is rejected at size zero by design, so the wire path is exercised continuously without money at risk. Brief operator-funded validations have exercised the real-money path end to end. No trading-performance figures are published.


## How it stays fast

**Nothing polls. Every decision fires the instant a market event arrives, moved between processes in about a microsecond.**

Everything is event-driven and there is no polling loop. A venue message arrives, flows through lock-free shared-memory IPC in about **1 µs**, and either changes a decision input or it doesn't. Decisions that fire become signed orders pulled from a pre-signed pool, so the hot path never waits on cryptography.

Every order writes an audit trail, a state-machine row for each transition, timestamped, into an append-only journal. Over four recent paper days the bot placed **23,329 orders across 1,067 five-minute markets**, and each one can be replayed transition by transition.

A separate probe fires a one-cent test order roughly every second, millions of placements a week, purely to measure how fast each venue acknowledges and cancels. Median acknowledgement is about **38 ms**. The 99th percentile stretches past **2.8 s** when the market moves. That measured distribution, not a guess, is what the backtester uses to model execution.



## Why you can trust it unattended

**13 quality gates block every commit, and there is no flag to skip them.**

The operating discipline is the part that makes an always-on system trustworthy with one person behind it. Every commit passes **13 strict pre-commit gates**: link and freshness checks, schema-drift detectors, supply-chain audits, and an AI code reviewer that reads each staged file and can block the commit. There are no bypass flags. The suite held **2,948 passing tests** at its last recorded full run.

Verification continues after deploy. **102 soak-test runners** check the production data (completeness, latency budgets, schema invariants) against a mirror synced every five minutes, and a systemd timer probes process health every minute. Capture coverage over the last 19 full days is **99.8%** of all 5-minute partitions. Each deploy ships with a recorded git commit and binary checksum and keeps the previous binary as a one-command rollback. An offline simulator replays recorded data and reproduces every live decision at **100% parity**, so changes are proven safe before they ever reach the wire.



## What one person delivered

**3,139 commits and 219,000 lines of Rust in 123 days, solo, with every number measured on the running system.**

One engineer shipped this in **123 days**: **3,139 commits**, **219,000 lines of Rust across 389 files** plus 77,747 lines of Python test and operations tooling, with AI agent orchestration as the only toolchain. Capture coverage held at **99.8%** over 19 days, and **66 frozen design records** explain why each major choice was made, so any future engineer (human or AI) inherits the reasoning, not just the code. The system even watches the market around itself, decoding tens of thousands of counterparty wallets from on-chain settlement events each week to study how the venue actually behaves.

The point is not any single number. It is that every figure above was measured on the running system, and the machinery that measured it ships with the product. The same discipline (spend caps, audit logs, unskippable tests) applies to automation work an order of magnitude simpler.

## Features

- **Two parallel decision paths** — A fast reflex path reacts to every order-book change while a slower path re-scores the ML model, running on separate CPU-pinned threads so neither blocks the other.
- **114-signal ML ensemble** — XGBoost and CatBoost models score 114 live market signals through ONNX Runtime in-process, with no network call on the decision path.
- **Microsecond internal data bus** — Market data moves between the two processes through lock-free shared memory in about one microsecond, with no kernel round-trip.
- **Offline simulator that proves changes safe** — An offline twin replays recorded market data through the exact same decision code and asserts a 100% match against live decisions before any change ships.
- **13 unskippable quality gates** — Every commit must pass an AI code reviewer, supply-chain audit, schema-drift detector, and doc checks, all blocking, with no bypass flag in the codebase.
- **Atomic deploy with auto-rollback** — Each deploy cross-compiles for ARM, swaps the binary atomically, and watches a health endpoint for up to 180 seconds, rolling back to the previous binary on failure.

## Architecture

Two Rust processes on a single AWS Graviton 4 ARM box (eu-west-1, Dublin). `microstruct` ingests 11 venues via WebSocket/REST and publishes to 10 iceoryx2 SHM streams. `btc-bot-live` subscribes, runs the orchestrator and reflex hot paths, manages order execution, and drains all events to Parquet and a WebSocket broadcast. A hexagonal `core` crate holds all pure math (no I/O). `sim` owns the offline replay engine. One-directional crate DAG enforced by the compiler.

- **microstruct (feeds crate)** — 11-venue WebSocket + REST collector. Writes Parquet partitions and two SQLite WAL databases. Publishes BTC-only events on 10 iceoryx2 streams.
- **btc-bot-live (live crate)** — Event-driven orchestrator + reflex + GTC executor. Subscribes to iceoryx2, reads SQLite read-only, drains 13-variant DbRow stream to Parquet and WebSocket :9091.
- **core crate** — Pure math: evaluate_reflex, 114-feature compute, PupGrid, fee-aware pricing, k=6 regime classifier, HARD4/TDA2/RES2 detector kernels. No I/O.
- **sim crate** — Offline replay twin. Owns OrtPredictor (ONNX Runtime). Calls identical evaluate_reflex. Parity oracle asserts 100% fire-set match.
- **clob crate** — Polymarket CLOB V2 wire surface: HTTP/2 client, EIP-712 V2 signer, 198-slot presign grid, canonical error classifier.
- **iceoryx2 IPC bus** — 10 per-stream lock-free SHM payload services plus feature-advance notifier and boot-handshake. ~1 µs per hop, no kernel transition.
- **Dashboard** — Plotly Dash operator UI on :8052, fed by ws_to_sqlite.py adapter off the bot's WebSocket broadcast. Mobile-reachable over Tailscale.

## Tech

- **Languages:** Rust, Python
- **Frameworks:** tokio, iceoryx2, ONNX Runtime (ORT), XGBoost, CatBoost, Plotly Dash
- **Infrastructure:** AWS eu-west-1 (Dublin), m8g.xlarge (Graviton 4 ARM), systemd, WSL2 cross-compile, SQLite WAL, Apache Parquet
- **AI/ML:** XGBoost (ONNX), CatBoost (ONNX), DeepSeek (AI pre-commit code critic), Claude Code (AI agent orchestration, sole developer toolchain)

## Skills demonstrated

- Building production systems solo with AI agents
- Low-latency, event-driven Rust systems programming
- Machine-learning inference in the live path (ONNX, XGBoost, CatBoost)
- Real-time data pipelines across 11 live sources
- Enforced quality gates that block bad commits automatically
- Test-before-deploy verification with an offline simulator
- Auditable order trails and unattended 24/7 operation
- Atomic AWS deployment with automatic rollback
- Documented, frozen design decisions for handoff
- Spend caps and safe-by-default operating controls
