Kalshi & Polymarket Arbitrage Scanner - Cross-Exchange Gaps
Pricing
Pay per usage
Kalshi & Polymarket Arbitrage Scanner - Cross-Exchange Gaps
Finds the same question listed on both Kalshi and Polymarket and reports the price gap, each side’s spread, and whether the gap actually clears both spreads. Plus every market on both exchanges in one normalized schema. Lexical matching, match score on every pair. No API keys.
Pricing
Pay per usage
Rating
0.0
(0)
Developer
SignalData
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
6 days ago
Last modified
Categories
Share
Kalshi & Polymarket Market Data + Cross-Exchange Price Gaps
Every market on Kalshi and Polymarket in one normalized schema — prices, implied probability, spread, volume, open interest, close time, resolution rules — plus the part no other actor gives you: the same question matched across both exchanges, with the price gap between them.
No API keys. Both exchanges are read through their public endpoints.
The reason this exists
Kalshi quotes in cents, Polymarket in dollars. Kalshi calls it yes_bid, Polymarket calls it bestBid. Kalshi says volume_fp, Polymarket says volumeNum. One returns arrays, the other sometimes returns arrays encoded as strings. If you want to compare the two, you write a normalization layer first and a strategy second.
This actor is that layer, already written and tested against the live response shapes of both APIs.
Cross-exchange gaps
When the same real-world question trades on both venues, the actor pairs them and reports:
{"type": "cross_exchange_match","question_kalshi": "Will the high temperature in NYC be above 79.5 degrees on Sep 8?","question_polymarket": "NYC high temp above 79.5F on September 8?","kalshi_probability": 0.44,"polymarket_probability": 0.60,"probability_gap": 0.16,"combined_spread": 0.06,"gap_exceeds_spreads": true,"match_score": 0.83,"kalshi_url": "https://kalshi.com/markets/kxhighny","polymarket_url": "https://polymarket.com/event/nyc-high-sep-8"}
gap_exceeds_spreads is the field to sort on. A 16-point gap when the two spreads together are 6 points is a real dislocation, not just the cost of crossing. Rows come back with the widest gap first.
Match strictness is tunable. The two exchanges word the same event very differently — Kalshi writes "Fed decision in September?" where Polymarket writes "Will the Fed decrease interest rates by 25 bps after the September 2026 meeting?" — so the default sits at a loose 0.35 and every row carries its match_score. Read that score before trading on a pair; this is lexical matching, not semantic, and it is deliberately reported rather than hidden.
Market rows
{"type": "market","exchange": "kalshi","market_id": "KXHIGHNY-26SEP08-B79.5","event_id": "KXHIGHNY-26SEP08","series_id": "KXHIGHNY","question": "Will the high temperature in NYC be above 79.5 degrees on Sep 8?","yes_bid": 0.42, "yes_ask": 0.46, "mid_price": 0.44,"implied_probability": 0.44, "spread": 0.04,"volume": 15320, "volume_24h": 4210, "open_interest": 8800,"close_time": "2026-09-08T23:30:00Z","strike_type": "greater", "floor_strike": 79.5,"rules": "Settles on the NWS Daily Climate Report for Central Park.","url": "https://kalshi.com/markets/kxhighny"}
Prices are always dollars in the 0–1 range on both exchanges, whichever units the source used. Polymarket rows additionally carry outcomes and outcome_prices for multi-outcome markets, and implied_probability reads the Yes leg specifically rather than assuming it is first in the list.
Example input
Everything liquid on both exchanges, with gaps:
{ "exchanges": ["kalshi", "polymarket"], "status": "open","maxMarkets": 500, "minVolume": 1000, "crossExchangeGaps": true }
One theme only — scanning is free, you are billed only for what comes back:
{ "search": ["temperature", "weather", "rain", "snow"], "scanLimit": 5000, "maxMarkets": 200 }
A single Kalshi series, e.g. the New York daily high:
{ "exchanges": ["kalshi"], "kalshiSeriesTicker": "KXHIGHNY", "status": "open" }
Settled markets for backtesting:
{ "status": "settled", "maxMarkets": 5000, "crossExchangeGaps": false }
Pricing
| Record | Price |
|---|---|
market | $0.001 |
cross_exchange_match | $0.005 |
Scanning is not billed. A daily pull of 500 liquid markets with gap detection runs about $0.55.
Pairs well with
Weather Data for Prediction Markets — the official NWS settlement values and multi-model forecasts for the stations temperature markets resolve on. Pull the market prices here, the physical data there, and you have both halves of the trade.
Use from an AI agent
Callable through Apify's MCP server. An agent can ask for open markets matching a theme and get back a clean, sorted, typed table without any exchange-specific glue code.
Notes and limits
- Question matching is lexical (word overlap), not semantic, and every pair carries its
match_scoreso you can judge it yourself. At the default 0.35 you will see some loose pairs; raise the strictness if you want fewer and cleaner. Expect few or no matches when you pull the whole book untargeted — the two exchanges list mostly different events. Search a theme ("fed", "bitcoin", "temperature") to find the overlap. - Polymarket's Gamma API returns markets sorted by 24-hour volume; Kalshi is paged by cursor. Both are capped by
maxMarketsso a run cannot bill you unexpectedly. - Order-book depth is not included — these are top-of-book prices and traded volume.
- If one exchange is down, the run still returns the other and logs the failure rather than dying.
Support
Open an issue on the actor page. Requests for extra fields, other exchanges, or a different match algorithm are welcome.