Polymarket vs Kalshi Arbitrage — Same Question, Two Prices
Pricing
from $20.00 / 1,000 contract pair priced across venues
Polymarket vs Kalshi Arbitrage — Same Question, Two Prices
Compare the same question on Polymarket and Kalshi: bid/ask, gross gap and net gap after both venues' fees. Unknown Polymarket fees leave net null with a reason. $0.02 per gross-priced pair, suggestions included; refusals free. Unofficial.
Pricing
from $20.00 / 1,000 contract pair priced across venues
Rating
0.0
(0)
Developer
h ichi
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
4 days ago
Last modified
Categories
Share
What it does: Takes a question that trades on both Polymarket and Kalshi and prices the gap between them, before fees and after Kalshi's fee plus the market-specific Polymarket taker fee. If Polymarket's fee settings are unavailable or unsupported, it returns the gross gap with a null net gap and an explicit reason.
You enter: Pairs you checked, e.g. will-bitcoin-outperform-gold-in-2026|KXBTCVSGOLD-26 (Polymarket|Kalshi).
You get: One row per pair: best bid and ask on each site, which site to buy on and sell on, gap in cents per $1 before and after the fee, dollars resting at those prices, close-date gap. Pairs it suggests itself (on by default) are marked unverified, indicative only.
Price: $0.02 per pair priced, the pairs it suggests included. +$0.002 per site row if you also want each side (two per pair, on by default). Pairs that can't be priced are never charged.
Unofficial — not affiliated with Polymarket or Kalshi. Reads public pages only.
Confirmed pairs — the only tradable number
You list the pairs you have checked, as "<polymarket-slug-or-conditionId>|<KALSHI-TICKER>". Only these get an edgePct.
| field | meaning |
|---|---|
matchVerified | true — you confirmed this pairing |
direction | e.g. "buy polymarket / sell kalshi" — which leg you lift |
edgePct | (bid on the dearer venue - ask on the cheaper) x 100, cents per $1 contract |
edgeNetPct | the same, less both venues' fees at the executed prices; null when Polymarket's fee is unknown |
kalshiFeeCents / polymarketFeeCents | per contract; see Fees below |
netPriced | whether the net gap can be calculated from supported fee settings |
polymarketFeeStatus / polymarketFeeReason | enabled, disabled, unknown or unsupported, with the source validation result |
directionBasis | net-edge when fees are known; gross-edge-fees-unknown when the direction is only a gross comparison |
polymarketDepthUsd / kalshiDepthUsd | dollars resting at the touch, bid and ask |
closeGapDays | how far apart the two contracts settle |
directionsBlocked | the round trip that was not taken, and why |
Suggested pairs — never a trade, always a question
With autoSuggest on, the matcher proposes pairings it found. These carry matchVerified: false, edgePct: null, and their number under the deliberately different name indicativeEdgePct — alongside matchScore, matchBasis (what actually matched), closeGapDays, and both resolution texts verbatim (polymarketResolution, kalshiResolution) so you can confirm or reject in one glance. confirmAs gives you the exact string to paste into pairs.
Reading them matters. In a live run on 2026-08-10 the matcher proposed OpenAI IPO before 2027? against Kalshi's Who will IPO before 2027? OpenAI — same company, same year, an 8-point apparent edge. The two resolution texts do not agree: Polymarket needs the IPO completed by 31 Dec 2026, Kalshi needs it confirmed before 1 Jan 2027. Announcing is easier than completing, so Kalshi trades higher for a reason. That gap is a definition, not an arbitrage — and it is visible only because both texts travel with the suggestion.
What the matcher refuses to do
Every gate below is a hard drop, not a score penalty, because a fact that is simply wrong cannot be traded off against wording similarity. Each one's losses are counted in the summary.
| gate | why |
|---|---|
close times more than maxCloseGapDays apart | contracts that settle weeks apart are not the same contract |
token overlap below minMatchScore | |
| numeric thresholds present on both sides but disagreeing | "BTC above $150,000" and "BTC above $120,000" are 0.75 similar as text and are opposite bets |
| dates present on both sides but disagreeing | |
| opposite direction words (above / below) | the one pairing that would flip the sign of the edge |
| a qualifier on one side only (second, exactly, not, consecutive) | "second-hottest year" vs "hottest year" is one word and the opposite bet |
| the shared words are more common than the differing ones | see below |
That last gate came out of a live run. At minMatchScore 0.6 the matcher paired "Remote IPO before 2027?" with "Who will IPO before 2027? Kraken" — two different companies whose entire overlap is the template ipo / before / 2027. A candidate is now dropped unless the rarest word the two questions share is at least as rare as the rarest word they differ on.
What it counts
A filtered set that hides its own losses reads as complete, so the spread_summary record reports every drop: droppedCloseGap, droppedPolarity, droppedAsymmetricQualifier, droppedNumericThresholdDisagreement, droppedDateDisagreement, droppedNoSharedSubjectWord, droppedBelowMatchScore, duplicateKalshiSuggestionsDropped, duplicatePolymarketSuggestionsDropped, unpriceableLegs, confirmedPairsUnresolvable. Verified and unverified edge statistics are kept in separate fields and never averaged together. Net statistics and best-net records exclude null net gaps. confirmedPairsNetPriced / suggestionsNetPriced count known net gaps; confirmedPairsFeeUnknown / suggestionsFeeUnknown count priced gross gaps with unavailable or unsupported fees.
Depth, and what is refused
minLiquidityUsd applies to the size resting at the touch on both legs — the Polymarket side from the CLOB order book, the Kalshi side from yes_bid_size / yes_ask_size, each valued at its own price. Gamma's book-wide liquidity is reported separately as bookWideLiquidityUsd and is not used for this, because it is not the size behind the quote.
A pair is refused, not priced, when:
- either venue has no two-sided quote (one side of the book is empty);
- the depth a direction needs is below
minLiquidityUsd, in both directions; - a leg is not accepting orders, or is not a binary Yes/No market;
- the pair string does not resolve to one market on each venue.
Every refusal names the input to change and is returned with the record rather than dropped.
Fees
- Kalshi:
ceil(coefficient x P x (1 - P))dollars per contract, rounded up to the next cent — 2c on a 50c contract. The coefficient (published: 0.07) is an input, because a stale fee constant would quietly overstate every edge. - Polymarket: reads
feesEnabledandfeeSchedulefrom each Gamma market. For a positive finiterateno greater than 1,exponent: 1andtakerOnly: true, the one-share taker fee israte × P × (1 − P)USD, evaluated at the Polymarket ask when buying or bid when selling. Amounts below $0.00001 are zero; other amounts round half-up to five USD decimals before conversion to cents. For example, rate0.05at a 42c price costs $0.01218, or 1.218c per share. Only an explicitfeesEnabled: falseestablishes a fee-free market. No category defaults or maker/taker rebate discounts are assumed. See the official fee formula and precision and market fee settings. - Missing, malformed or unsupported settings produce
polymarketFeeCents: null,netPriced: falseand a nulledgeNetPct(orindicativeEdgeNetPctfor suggestions). The valid quotes, gross gap and individual leg rows remain available. The displayed direction then maximizes the gross gap and is markeddirectionBasis: "gross-edge-fees-unknown"; it is not a net-profit recommendation. When fees are known, direction selection subtracts both executed legs' fees. Apply a minimum-net filter only to rows withnetPriced: trueand a non-null net field; unknown does not mean zero. polymarketFeesEnabled,polymarketFeeRate,polymarketFeeExponentandpolymarketFeeTakerOnlyexpose the validated source settings. Individual Polymarket leg rows expose the same metadata asfeesEnabled,feeRate,feeExponent,feeTakerOnly,feeStatusandfeeReason, plusbidFeeCents/askFeeCents. Calculations are per one share; an actual multi-share order can round differently, and execution prices can move.- Gas / relayer cost on the Polymarket leg is not modelled. A net edge smaller than your own transaction cost is not a trade.
What one row looks like
Measured on 2026-08-09 (real run, fee-free at that time) — one confirmed pair, with the current fee-status fields shown and a few fields left out for length. Current runs re-read each market's fee settings.
{"type": "confirmed_pair","pair": "will-bitcoin-outperform-gold-in-2026|KXBTCVSGOLD-26","matchVerified": true,"polymarketQuestion": "Will Bitcoin outperform Gold in 2026?","kalshiQuestion": "Will Bitcoin outperform gold in 2026?","polymarketYesBid": 0.17,"polymarketYesAsk": 0.19,"kalshiYesBid": 0.178,"kalshiYesAsk": 0.215,"polymarketDepthUsd": { "bid": 1.7, "ask": 19.0 },"kalshiDepthUsd": { "bid": 0.93, "ask": 10.24 },"closeGapDays": 0.0,"priced": true,"edgePct": -1.2,"edgeNetPct": -3.2,"direction": "buy polymarket / sell kalshi","kalshiFeeCents": 2,"polymarketFeeCents": 0,"polymarketFeeStatus": "disabled","polymarketFeeReason": "Gamma explicitly reports feesEnabled=false","polymarketFeesEnabled": false,"netPriced": true,"directionBasis": "net-edge","directionsBlocked": []}
Each row also carries feeModel and depthBasis in plain words, so the numbers above can be checked without reading this page.
Price
$0.02 per contract pair priced — every pair that gets a gross price gap is charged, including suggestions and rows whose net gap is null because the Polymarket fee is unknown, so ten priced pairs cost $0.20. A refused pair is never charged: a pair without a two-sided quote on both venues, or with a leg too thin to trade, produced no answer, and you do not pay for a non-answer.
Each venue's side of a pair is $0.002 and on by default (includeIndividualLegs), two per priced pair — confirmed and suggested alike. A refused pair carries no leg rows and no leg charge, because a refusal is free whole. Turn it off if you only want the pair rows. You pay per pair; there is no monthly fee.
Input
{"pairs": ["will-bitcoin-outperform-gold-in-2026|KXBTCVSGOLD-26"],"autoSuggest": true,"categories": ["Financials"],"maxEventsPerVenue": 300,"maxCloseGapDays": 3,"minMatchScore": "0.6","minLiquidityUsd": "0","kalshiFeeCoefficient": "0.07"}
categories filters the Kalshi side only, and it is the lever that matters: Kalshi carries over 8,000 open events, so scanning without a category is scanning a slice of an arbitrary ordering. Pick the categories your pairs live in (Politics, Economics, Elections, Financials, Companies, Crypto, World, Sports, Climate and Weather).
maxEventsPerVenue defaults to 200 and tops out at 300; the example above asks for the maximum. 300 is where the scan stops fitting in the 256MB the Actor runs under — both venues' pools stay in memory for the whole match — so it is a measured ceiling rather than a chosen one.
Reads both sites' public data only, no login, requests spaced out. Nothing is kept between runs — every run re-reads both live order books.
If something goes wrong
- Wrong number or a failed run? Open a ticket on the Issues tab. I read every one and reply within 2 business days (Japan time).
- You never get a fake "empty" result. If the site can't be read, the run fails and says so.
- A pair that can't be priced = no charge. A pair that does get a price costs $0.02 even when the gap comes out negative — that number is the result you asked for.
- Checked every week. An automatic test runs this tool weekly; if the site changes, I fix it.
- Public pages only. No login, no personal data, and it goes easy on the site.
More tools by the same author
- Kalshi Arbitrage Finder — Groups Priced Against $1
- Polymarket Odds, Volume & Top Markets by Topic
- Polymarket Markets — Odds, Bid/Ask, Volume, One Row Each
- Polymarket Arbitrage Finder — Groups Priced Under $1
All tools (Japan marketplaces, real estate, jobs, racing, prediction markets): https://apify.com/jpmarketdata
Disclaimer
Unofficial, independent tool — not affiliated with, endorsed by, or sponsored by Kalshi or Polymarket. Product names and logos belong to their owners and only say where the data comes from. Data is read from public pages, for market research; check before you act on it.