← All work

Quant · Prediction Markets — Independent build

Polymarket Engine

A production algorithmic-trading engine for Polymarket's order book — five alpha strategies, unified behind a fifteen-gate risk architecture.

Role

Independent build

Venue

Polymarket CLOB · Polygon PoS

Runtime

Python 3.12 + Rust (NautilusTrader)

Scale

~18k LOC · 84-doc knowledge base

Polymarket engine dashboard Bayesian Arbitrage · Ensemble Forecasting · Kelly Sizing Poly­bot

Every trade has to pass fifteen gates in order — liquidity, toxicity, volatility, evidence, nonce, latency, inventory — before a single order leaves the machine.

What it does

The engine detects and exploits statistical mispricing in prediction markets, then routes any candidate trade through a sequential all-or-nothing validation pipeline that enforces risk limits and sizes positions before submission. The organising idea is a single decision inequality: map the market state to a go / no-go, where every term is a named risk constraint.

Five alpha strategies

  • Bayesian cross-market arbitrage — detecting violations of the law of total probability across dependent markets.
  • Intra-market rebalancing — exploiting sum-to-one deviations between YES/NO within a market.
  • Volatility-adjusted market making — Avellaneda–Stoikov in logit space, spreads tuned to order-flow toxicity (VPIN).
  • Ensemble forecasting — a twelve-model LLM ensemble aggregated in log-odds, weighted by Brier score and Platt-calibrated.
  • Whale copy-trading — tracking historically profitable wallets on-chain and mirroring, with counter-position size reduction.

How it's built

A Python/Rust hybrid: Python carries strategy logic, ML and backtesting; execution and order-book management run through NautilusTrader's Rust core, signing on Polygon with EIP-712. An eleven-feature state vector feeds the fifteen gates — liquidity depth, VPIN toxicity, volatility guardrail, contrarian-evidence search, nonce and RPC sync, latency-adaptive order type, inventory limits, a TimesFM price guard, fractional-Kelly sizing, and a global kill switch. Sizing uses Kelly with explicit ambiguity aversion for model disagreement; validation is walk-forward across 34+ out-of-sample windows with Monte-Carlo slippage and fee modelling. Every gate decision is logged to JSONL for exact backtest replay.

Signals of rigour

Log-odds (not arithmetic) ensemble aggregation, so the maths stays Bayesian-coherent. VPIN as a toxicity gate on entry. A combinatorial check that a new position doesn't violate the Bayesian consistency of the whole portfolio. Kill switches on daily, monthly and drawdown loss. It reads like a quant desk's process, encoded.

Python 3.12RustNautilusTraderTimesFMscikit-learnWeb3.pyEIP-712Pydantic-AIPyArrow

Core feature

From Polymarket Engine's actual codebase

The engine's core: gates.py — the fifteen-gate pre-trade pipeline (G1 liquidity depth through G15 kill switch). Every candidate trade must pass all fifteen gates in order; a single failure halts it before an order is ever signed.

core/gates.py — 15-gate pipeline (actual source)

polybot / src/polybot/core/gates.py 1,302 lines Python 3.12
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 27 28 263 264 265 274 275 277 279 280 281
"""15-gate decision architecture for the Polymarket trading bot. Implements: - M2-007: Gate 1 — Liquidity depth check (0.5% slippage) - M2-008: Gate 2 — Spread/VPIN validation (regime-dependent threshold) - M3-016: Gate 3 — Volatility guardrail (60s rolling stddev) - M3-017: Gate 4 — Domain authority scoring (news credibility) - M3-018: Gate 5 — Contrarian evidence search (red-team LLM) - M3-019: Gate 6 — Sentiment divergence (CLOB vs RTDS, soft reject) - M3-020: Gate 7 — Whale tracker threshold (Bitquery, size reduction) - M3-021: Gate 8 — Combinatorial dependency verification (Bayesian) - M2-009: Gate 9 — EIP-712 nonce synchronization - M2-010: Gate 10 — RPC sync state (within 2 blocks) - M2-011: Gate 11 — Latency ping threshold (<150ms → FOK; else GTC) - M3-022: Gate 12 — Inventory limits (<5% market, <20% sector) - M3-023: Gate 13 — Price guard outlier (3σ from TimesFM) - M2-012: Gate 14 — Fractional Kelly sizing (Eq 5.3) - M2-013: Gate 15 — Global kill switch (daily/monthly/drawdown) A trade proceeds only when ALL gates pass — one failure halts it. G1 → G2 → G3 → … → G14 → G15 → TRADE """ ⋯ 234 lines folded class LiquidityDepthGate(Gate): """Gate 1: verify sufficient CLOB depth for the proposed order. Pass if depth D >= order_size_usdc, within a 0.5% slippage budget.""" def __init__(self, slippage_budget: float = SLIPPAGE_BUDGET) -> None: super().__init__(gate_id=1, name="liquidity_depth") def evaluate(self, state: MarketState, ctx: GateContext) -> GateResult: if ctx.order_size_usdc <= state.D: return self._pass(f"depth ${state.D:.2f} >= order ${ctx.order_size_usdc:.2f}") return self._fail(f"depth ${state.D:.2f} < order ${ctx.order_size_usdc:.2f}")
● 15 gates| G1 liquidity_depth → G15 kill_switch| all-or-nothing · JSONL logged| Python + Rust (NautilusTrader)