SideGuy · Prediction Markets · Cross-Platform Arbitrage Scanner

How to build a cross-platform arbitrage scanner for Kalshi + Polymarket in 2026

Operator-honest build guide. The scanner is one of the four buildable projects in prediction-market quant work (per the backtest read). Here's the actual stack, the data sources, and the structural barriers.

TL;DR

The architecture (operator-honest reference)

┌─────────────────────────────────────────────────────────────┐ │ EVENT LISTING SCRAPER LAYER │ Kalshi API → /events, /markets endpoints │ Polymarket → CLOB API + on-chain reads │ Underdog → HTML scrape (no public API) │ PrizePicks → HTML scrape (no public API) └─────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────┐ │ EVENT MATCHER (the hard part) │ Fuzzy name matching + manual override table │ Resolution-criteria reconciliation flags │ Stores matched events to SQLite/Postgres └─────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────┐ │ DIVERGENCE CALCULATOR │ Implied probability per platform │ Net of fees + slippage │ Alert when |Δ| > threshold (operator-set) └─────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────┐ │ HUMAN OPERATOR (decides + executes) │ Reviews the alert │ Checks resolution-criteria alignment │ Executes both sides if real arb (or one side as carve) └─────────────────────────────────────────────────────────────┘

Note the last layer: operator-in-the-loop. Fully automated execution is technically possible but operator-honest practice keeps a human approving each cross-platform position. Resolution-criteria mismatches catch you when you trust the scanner blindly.

The divergence threshold math

Cost basis to clear before an arb is profitable:

CostKalshi sidePolymarket side
Per-contract fee~$0.01-0.03Variable (Polygon gas typically $0.01-2)
Slippage on entry0.5-2% in thin markets1-3% in thin markets
Resolution timingUsually same daySame day to days
Effective cost per side~1-3%~2-4%

Combined cost ~3-5%. So divergence below 5 percentage points usually isn't profitable. Above 8 points it's interesting. Above 15 points (rare, news-shock-driven) it's the moment.

The hard problem: fuzzy event matching

Same event has different identifiers across platforms:

KALSHI: "PRES-2026" — "Will Trump win 2026 election?" POLYMARKET: "trump-wins-2024-3" — "Donald Trump wins 2024 US election" UD PREDICT: "Election 2024" — outcome-coded as Trump/Harris/Other Match attempt by name string: FUZZY Match attempt by resolution date: USEFUL Match attempt by resolution criteria: MANUAL OVERRIDE NEEDED

The operator move: build an event-matching table that maps platform IDs to a canonical event-id. Maintain it manually for high-value events (elections, major sports finals). Use fuzzy name matching as a first-pass filter, manual confirmation for actual position-taking.

The Python skeleton (minimum viable)

import asyncio, httpx, pandas as pd async def fetch_kalshi_markets(client): r = await client.get("https://api.elections.kalshi.com/trade-api/v2/markets") return r.json()["markets"] async def fetch_polymarket_markets(client): r = await client.get("https://clob.polymarket.com/markets") return r.json() async def scan_arbs(threshold_pp=8): async with httpx.AsyncClient(timeout=10) as c: k = await fetch_kalshi_markets(c) p = await fetch_polymarket_markets(c) # Match events (your matching table here) matched = match_events(k, p) for event in matched: k_prob = event.kalshi_yes_price / 100 p_prob = event.poly_yes_price diff_pp = abs(k_prob - p_prob) * 100 if diff_pp > threshold_pp: print(f"⚡ ARB: {event.name} · Kalshi {k_prob:.2%} vs Poly {p_prob:.2%} · Δ {diff_pp:.1f}pp") asyncio.run(scan_arbs())

~50 lines to a working v1. The remaining ~95% of effort is the matching table, alert routing (Slack/SMS), and execution-side automation.

Structural barriers (the honest 4)

1. Event-matching is fuzzy

Same event, different identifiers. Fuzzy name matching catches 70-80%; the rest needs human curation. Maintain a manual mapping table.

2. Latency kills arbs

By the time you see the divergence on screen, the other side may have moved. Sub-second polling on both APIs is the table stakes. WebSocket subscriptions where available (Kalshi).

3. Capital fragmentation

You need funded balance on each platform. KYC on each. Account history on each. The operator capital lock per platform is real — you can't run the scanner from a single bank account.

4. Resolution criteria mismatch

Kalshi may settle "Trump wins" on Electoral College; Polymarket may settle on Popular Vote. If the scanner doesn't know this, the "arb" can resolve as a loss on both sides. This is why operator-in-the-loop is mandatory.

⚠️ Not financial advice. Prediction-market arbitrage is high-execution-skill work. Most scanners surface signals that aren't actually risk-free arbs once resolution criteria are reconciled. Start with paper-trading + small live positions before scaling capital.

How this connects to the SideGuy framework

The arb scanner is the scanner layer · once a divergence is real, the position taken IS a Betting Lab release-carve operation. You release on one platform (Kalshi or Polymarket), and the opposite-side position on the other platform IS the carve.

Per the release-carve operating system doctrine, the divergence isn't a "perfect trade" · it's the substrate that creates the day's carving opportunity. The scanner surfaces the release moment; the operator carves through the resolution window.

Want the full framework?

The SideGuy Betting Lab is the public doctrine — 12 layers of structure from bracket / middle / gap through release-carve.

Read the SideGuy Betting Lab

© 2026 SideGuy Solutions · Encinitas, CA · Text PJ 858-461-8054

💬 Text PJ