TypeScript Polymarket Arbitrage Bot: Multi-Strategy Detection & CLOB Execution

·2 min read

TypeScript Polymarket Arbitrage Bot

Arbitrage on Polymarket is not one strategy - it is a family of edge types with different risk profiles, speed requirements, and capital efficiency. I built a TypeScript Polymarket arbitrage bot that implements multiple strategies behind a single execution engine, with dry-run, scan-only, and live modes.

Live overview: casatrick.github.io/polymarket-arbitrage-bot

Strategy comparison

Strategy Edge type Risk Speed needed
Intra-market YES + NO < $1.00 Very low Medium
Multi-outcome / bundle Outcomes sum < 100% Low Medium
Latency / temporal Spot vs implied lag Medium Very high
Correlation / logical Related market mismatch Medium High
Tail-end / resolution Near-certain outcomes Very low Low
Market making Bid-ask spread Low-medium High

The bot routes each market through enabled strategies in src/strategies/, then executes via a shared CLOB trader module.

Project structure

src/
├── bot.ts
├── strategies/
│   ├── intraMarket.ts
│   ├── latency.ts
│   ├── correlation.ts
│   └── tailEnd.ts
├── arbEngine.ts    # strategy selector
├── trader.ts       # CLOB execution
├── market.ts       # market data + WebSocket
└── config.ts

Adding a new strategy means one file + a config flag - the engine handles discovery, sizing, and logging consistently.

Intra-market: the core loop

if (yesPrice + noPrice < 1.00 - CONFIG.minEdge) {
  const edge = 1.00 - (yesPrice + noPrice);
  const size = calculatePositionSize(edge, market.liquidity);
  await executeArbitrage(market.id, size, yesPrice, noPrice);
}

Default minEdge: 2%. Position sizing supports Kelly criterion or fixed fraction modes via config.ts.

Latency arbitrage on crypto markets

For 5m/15m BTC and ETH up/down markets, Polymarket prices can lag spot feeds. The latency strategy compares implied probability against external price data and trades the convergence gap:

const impliedProb = getImpliedProbability(market);
const diff = Math.abs(impliedProb - externalPrice);
if (diff > CONFIG.minLatencyEdge) {
  await trader.placeOrder(market.id, determineSide(externalPrice), size);
}

This is the highest-frequency strategy - WebSocket latency and server placement matter. For production, host near Polymarket CLOB infrastructure (Dublin/Amsterdam region on a non-geoblocked VPS).

Tail-end / resolution arbitrage

When a market resolves within 24 hours and the leading outcome trades above 0.96, buying certainty captures small returns with minimal hold time:

if (market.timeToResolution < 24 * 60 * 60 && market.highestPrice > 0.96) {
  await trader.buyCertainty(market.id, market.highestOutcome);
}

Low volatility, capital-efficient - good complement to faster strategies.

Run modes

npm run bot:dry   # simulation - start here
npm run scan      # scanner only, no execution
npm run bot       # live trading

Configure via .env:

PRIVATE_KEY=0x...
POLYMARKET_API_KEY=...
POLYMARKET_API_SECRET=...
POLYMARKET_API_PASSPHRASE=...
CHAIN_ID=137

Risk controls

Every strategy shares the same risk layer:

Never run live without validating in dry-run first.

Python vs TypeScript versions

I maintain two open-source Polymarket arbitrage bots:

Repo Language Focus
polymarket-arbitrage-bot-python Python 5 crypto strategies, signal ranking
polymarket-arbitrage-bot TypeScript Modular strategies, CLOB + WebSocket

For late-entry probability capture on BTC 5/15-minute markets specifically, see the dedicated Polymarket trading bot.

Building custom arbitrage infrastructure? See about for contact details.

Related posts