How to Detect Price Divergence Between Polymarket and Kalshi

How to Detect Price Divergence Between Polymarket and Kalshi

How to Detect Price Divergence Between Polymarket and Kalshi

Learn how to detect price divergence between Polymarket and Kalshi with our detailed pipeline. Maximize your trading accuracy and profits!

How to Detect Price Divergence Between Polymarket and Kalshi

TL;DR:

  • Detecting genuine mispricings between Polymarket and Kalshi requires matching markets using a stable canonical ID and applying a symmetric KL-divergence threshold above 0.15. Confirm liquidity depth and identical resolution text before executing trades, ensuring the net-of-fee edge exceeds 1.5 percent for viability. Building such a pipeline benefits from Assymetrix’s pre-normalized data API, which simplifies market pairing and facilitates robust backtesting and live detection.

A reproducible detection pipeline combines normalized cross-venue market matching, spread and z-score screening, and a symmetric KL-divergence above 0.15 threshold to flag likely genuine mispricings between Polymarket and Kalshi. When a signal fires, run three immediate checks before sizing any position:

  • Confirm resolution text is word-for-word identical across both venues

  • Verify order-book depth at your target notional on both sides

  • Compute net-of-fee edge; if it clears 1.5% after combined taker costs, flag for execution

If any check fails, log the signal for analysis and move on. The rest of this guide shows you how to build every layer of that pipeline.

Table of Contents

  • How to detect price divergence between Polymarket and Kalshi: the core metrics

  • How do you match the same market across both venues?

  • What data infrastructure does real-time divergence detection require?

  • How do you execute both legs without creating directional exposure?

  • Worked example: a Fed decision market divergence

  • How should you backtest and calibrate detection thresholds?

  • How does the Assymetrix Data API accelerate this pipeline?

  • Why do resolution-rule differences create false arbitrage signals?

  • What does a live divergence monitoring system look like?

  • Key Takeaways

  • The trade-off most detection systems get wrong

  • Assymetrix gives you the canonical layer this pipeline needs

  • FAQ

  • Useful sources and further reading

How to detect price divergence between Polymarket and Kalshi: the core metrics

Spread, z-score, and symmetric KL divergence


Close-up of hand with stylus near screens showing trading graphs

Raw spread, the absolute difference between Polymarket’s yes-price and Kalshi’s yes-price on a matched market, is the fastest first filter. It is also the most misleading in isolation. A 3-cent spread at 50¢ probability is structurally different from a 3-cent spread at 92¢, because the information content and reversion dynamics differ across probability space.

The z-score corrects for that. Compute it as the current spread divided by the rolling standard deviation of that paired spread over a lookback window (typically 500–2,000 ticks per market category). A z-score above 2.0 on a stable pair warrants attention; above 3.0 it is worth escalating to the distributional check.

Symmetric KL divergence is the definitive filter. For binary markets where each venue quotes a yes-probability p and q:

KL_sym = 0.5 * (p * log(p/q) + (1-p) * log((1-p)/(1-q)))
       + 0.5 * (q * log(q/p) + (1-q) * log((1-q)/(1-p)))
KL_sym = 0.5 * (p * log(p/q) + (1-p) * log((1-p)/(1-q)))
       + 0.5 * (q * log(q/p) + (1-q) * log((1-q)/(1-p)))

A symmetric KL above 0.15 signals a probability distribution inconsistency large enough to be a genuine mispricing rather than transient noise. Below that threshold, the gap is more likely bid-ask friction or a momentary liquidity imbalance.

A preliminary gross-arb screen runs in parallel: if the cheapest Yes across both venues plus the cheapest No across both venues sums to less than $1.00, a gross arbitrage exists before fees. That check is O(1) and should run on every tick.

Pro Tip: Calibrate KL and z-score thresholds separately by market category. Political markets tend to have higher baseline volatility and wider natural spreads than economic indicator markets (CPI, FOMC). A threshold that generates clean signals on Fed-decision markets will produce excessive false positives on election markets in the final 48 hours before resolution.

How do you match the same market across both venues?

Canonical normalization and fuzzy-matching pipeline

Polymarket and Kalshi use incompatible internal identifiers, different title conventions, and sometimes different outcome sets for what is functionally the same event. The normalization pipeline is where most detection systems fail.


Infographic illustrating canonical normalization and fuzzy matching pipeline steps

The canonical schema fields to align are: normalized title, event date, resolution source, outcome set (yes/no vs. binary contract), and category tag. Strip punctuation, lowercase everything, remove stopwords, and apply named-entity alignment to catch “Fed” vs. “Federal Reserve” or “FOMC” vs. “Federal Open Market Committee.”

Pipeline stage

Operation

Output

Ingestion

Pull raw title, slug, resolution text, tags

Raw record per venue

Canonicalization

Lowercase, tokenize, strip stopwords, NER alignment

Normalized token set

Candidate scoring

Jaccard similarity on token sets + resolution-source match

Score 0–1 per pair

Human-overwatch gate

Flag pairs scoring 0.70–0.85 for manual review

Confirmed or rejected

Confirmed pair

Assign canonical_market_id, store venue_ids

Canonical paired record

Pairs scoring above 0.85 on both token similarity and resolution-source match can be auto-confirmed. Anything below 0.70 is discarded. The middle band requires a human review queue, which shrinks quickly once you build a confirmed-pair library.

A rule-based resolution-source check is non-negotiable. Two markets with identical titles but different resolution sources (BLS advance release vs. BLS revised release, for example) are not the same market. That check alone eliminates the most dangerous false arbs.

What data infrastructure does real-time divergence detection require?

Feed requirements, canonical schema, and latency budgets

Infrastructure layer

Requirement

Notes

Feed type

WebSocket or streaming REST

Polling introduces detection lag

Timestamp accuracy

UTC, millisecond precision

Required for cross-venue tick alignment

Sequence IDs

Per-venue event sequence

Detects dropped messages

Canonical schema fields

market_id, canonical_title, venue_ids, yes_price, no_price, best_depth, timestamp_utc

Minimum viable schema

End-to-end detection latency

Budget per layer

Time synchronization matters more than most teams expect. Clock skew between your Polymarket feed handler and your Kalshi feed handler will produce phantom divergences that disappear on closer inspection. Run NTP or PTP synchronization on all feed-ingestion nodes and log the measured skew in your provenance records.

For depth reconstruction, prefer normalized tick-level snapshots supplemented by periodic full book-dumps. Top-of-book prices are insufficient for sizing; you need the incremental slippage curve at each notional bucket to know whether your target size is actually fillable at the quoted price.

Pro Tip: Store raw ticks with full provenance metadata (venue, sequence ID, ingest timestamp, processing timestamp) even if you only query aggregated snapshots in production. That audit trail is what makes backtests reproducible and lets you diagnose whether a missed signal was a feed gap or a genuine absence of divergence.

How do you execute both legs without creating directional exposure?

Leg risk, fee-aware edge, and execution controls

Leg risk is the primary operational hazard: one leg fills, the other fails due to latency, rate limits, or thin liquidity, and you hold an unintended directional position. Professional systems minimize this by firing both legs as close together as possible, with a kill switch that cancels the unfilled leg and closes the filled leg if the second order does not confirm within a defined timeout (typically 500 ms to 2 s depending on venue API rate limits).

Net-of-fee edge is the number that actually matters. Combined taker fees on common Kalshi-Polymarket pairs often consume 3–5 cents per contract round-trip. A gross edge under roughly 4–5 cents is marginal at best after fees and slippage; practitioners treat sub-4-cent gross edges as non-viable. The minimum viable net edge rule of thumb is 1.5% after all costs.

Execution checklist before firing:

  1. Confirm canonical_market_id match and identical resolution text

  2. Reconstruct order-book slices at target notional; verify fill is achievable at posted prices

  3. Compute net-of-fee edge; reject if below threshold

  4. Check withdrawal and settlement constraints (Kalshi uses ACH/USD; Polymarket uses USDC on Polygon)

  5. Verify neither venue has a pending resolution event within the next 60 minutes

  6. Fire both legs simultaneously with retry logic and a hard kill switch on timeout

Worked example: a Fed decision market divergence

Suppose Polymarket quotes “Fed cuts rates at May FOMC” at 0.62 yes, and Kalshi quotes the same event at 0.55 yes. The gross-arb screen fires immediately: 0.55 + (1 - 0.62) = 0.93 < 1.00.

Compute symmetric KL: with p = 0.62 and q = 0.55, KL_sym ≈ 0.018. That is well below 0.15, meaning the distributional gap is within noise range despite the 7-cent headline spread. The z-score on this pair’s 30-day spread history comes back at 1.4, also below the 2.0 threshold. No signal. Log and continue.

Now shift the scenario: Polymarket at 0.72, Kalshi at 0.55. KL_sym ≈ 0.089, z-score at 2.8. Still below the KL threshold, but the z-score warrants a depth check.

Scenario

Polymarket yes

Kalshi yes

KL_sym

Z-score

Signal?

Baseline

0.62

0.55

0.018

1.4

No

Moderate gap

0.72

0.55

0.089

2.8

Depth check

Strong gap

0.82

0.55

0.21

Yes — verify resolution

At the strong-gap scenario, KL_sym = 0.21 exceeds 0.15. Reconstruct book slices: Polymarket shows $8,000 available at 0.82; Kalshi shows $12,000 at 0.55. For a $5,000 notional position, both sides are fillable. Net-of-fee edge after 3 cents per side: approximately 24 cents per dollar, well above the 1.5% minimum.

Pro Tip: Use fixed-fraction sizing (e.g., 2–5% of capital per signal) rather than full Kelly in early live trading. Kelly sizing is theoretically optimal but requires an accurate edge estimate, which your backtest may overstate before you have live fill data to calibrate against.

How should you backtest and calibrate detection thresholds?

Backtesting a divergence detector requires four inputs: canonical historical ticks for both venues, per-venue order-book reconstructions at the time of each signal, the fee schedule in effect during the test period, and a realistic fill model that accounts for queue position and partial fills.

  1. Build a canonical tick database from historical exports, joining on canonical_market_id

  2. Replay ticks chronologically; compute spread, z-score, and KL_sym at each step

  3. At each threshold exceedance, simulate fills using reconstructed book slices

  4. Apply fee schedules and record net PnL per signal

  5. Split into in-sample calibration and out-of-sample validation sets; use bootstrap resampling to estimate confidence intervals on hit rate and mean return per signal

KL threshold

Approx. signal rate

Approx. true-positive rate

Mean net edge per signal

> 0.10

High

Lower (more noise)

Marginal

> 0.15

Moderate

Higher

Positive after fees

> 0.20

Low

Highest

Strong but rare

The 0.15 threshold sits at the practical optimum for most political and economic market categories: enough signals to generate meaningful returns, with a true-positive rate that justifies automated execution. Tighten to 0.20 for fully automated systems with no human review; loosen to 0.10 only in monitored paper-trade mode.

How does the Assymetrix Data API accelerate this pipeline?

Assymetrix provides the canonical normalization layer that replaces the fuzzy-matching pipeline described above. The Data API at data.assymetrix.com returns pre-matched market pairs with a stable canonical_market_id, normalized yes/no prices from both venues, depth metadata, resolution text, and UTC timestamps in a single response. The historical coverage spans nearly one billion rows of trading activity, which is the sample size required for statistically stable threshold calibration across market categories.

Sample canonical schema returned by the API:

Field

Description

canonical_market_id

Stable cross-venue identifier

venue_map

{polymarket_id, kalshi_id}

yes_price_poly

Polymarket yes mid

yes_price_kalshi

Kalshi yes mid

best_depth_poly

Top-of-book depth, Polymarket

best_depth_kalshi

Top-of-book depth, Kalshi

resolution_text

Full resolution clause (both venues)

timestamp_utc

Millisecond-precision UTC

A Python snippet to fetch a paired record and compute KL_sym in-stream:

import requests, math

def kl_sym(p, q, eps=1e-9):
    p, q = max(p, eps), max(q, eps)
    p_, q_ = 1 - p, 1 - q
    return 0.5 * (p*math.log(p/q) + p_*math.log(p_/q_)
                + q*math.log(q/p) + q_*math.log(q_/p_))

resp = requests.get(
    "https://data.assymetrix.com/v1/markets/paired",
    headers={"Authorization": "Bearer YOUR_KEY"}
)
for market in resp.json()["markets"]:
    kl = kl_sym(market["yes_price_poly"], market["yes_price_kalshi"])
    if kl > 0.15:
        print(f"Signal: {market['canonical_market_id']} | KL={kl:.3f}")
import requests, math

def kl_sym(p, q, eps=1e-9):
    p, q = max(p, eps), max(q, eps)
    p_, q_ = 1 - p, 1 - q
    return 0.5 * (p*math.log(p/q) + p_*math.log(p_/q_)
                + q*math.log(q/p) + q_*math.log(q_/p_))

resp = requests.get(
    "https://data.assymetrix.com/v1/markets/paired",
    headers={"Authorization": "Bearer YOUR_KEY"}
)
for market in resp.json()["markets"]:
    kl = kl_sym(market["yes_price_poly"], market["yes_price_kalshi"])
    if kl > 0.15:
        print(f"Signal: {market['canonical_market_id']} | KL={kl:.3f}")

Pro Tip: Use Assymetrix’s canonical_market_id as the join key in your backtest database. Fuzzy-match drift, where a pair that was correctly matched at ingestion silently diverges as market titles update, is one of the hardest bugs to catch post-hoc. A stable canonical ID eliminates it.

Why do resolution-rule differences create false arbitrage signals?

Resolution-rule mismatches are the single most common source of false arb signals. Two markets with nearly identical titles can resolve on different data releases (BLS advance vs. BLS revised), different official sources, or different cutoff times, producing asymmetric outcomes that make a convergence trade a directional bet in disguise.

The workflow is non-negotiable: always fetch and compare the full resolution text from both venues before confirming a pair. Any textual mismatch, even a difference in the cited data release vintage, disqualifies the pair from arb treatment. Flag it as a non-arb divergence and route it to a separate research queue.

Regulatory settlement mechanics also differ. Kalshi settles in USD via ACH with custodial fund holding; Polymarket settles in USDC on Polygon with non-custodial wallet control. Settlement timing differences affect capital lock-up calculations and should be factored into annualized return estimates.

This article is general information, not legal or financial advice. Confirm current regulatory requirements and fee schedules with each venue’s official documentation and a qualified professional before trading.

What does a live divergence monitoring system look like?

Dashboard KPIs and runbook steps

A production monitoring system needs four dashboard KPIs: signal rate (signals per hour by market category), true-positive rate after manual spot-checks, mean detection-to-execution latency, and fill success rate (both legs filled vs. one-leg failures).

Alert tiers:

  • P0 (auto-execute): KL > 0.15 + depth sufficient at target notional + resolution text confirmed identical + net edge > 1.5%

  • P1 (human review): KL > 0.10 + depth borderline or resolution text flagged for review

  • P2 (log only): Gross-arb screen fires but KL < 0.10

Runbook for a P0 alert:

  1. Automated system fires both legs with kill-switch timeout

  2. Post-trade reconciliation confirms both fills within 30 seconds

  3. If one leg fails, automated cancel-and-close sequence runs; alert on-call engineer

  4. Log signal, fill prices, slippage, and net PnL to the audit database

  5. Flag for threshold review if fill slippage exceeded the pre-trade estimate by more than 20%

Data-quality exceptions (missing ticks, feed gaps, anomalous prices) should trigger an automatic pause on automated execution for the affected market pair until the feed is confirmed clean.

Key Takeaways

Detecting genuine price divergence between Polymarket and Kalshi requires canonical market matching, a symmetric KL-divergence threshold above 0.15, confirmed liquidity depth, and identical resolution text before any position is sized.

Point

Details

Core detection rule

Canonical pair match + symmetric KL > 0.15 + depth check + identical resolution text = valid signal

Fee-aware edge minimum

Net edge must exceed 1.5% after combined taker fees; gross edges under ~4–5 cents are typically non-viable

Backtest sample size

Use nearly one billion rows of historical activity to calibrate KL and z-score thresholds by market category

Resolution text is mandatory

Always compare full resolution clauses; title similarity alone produces false arb signals

Assymetrix integration

The Assymetrix Data API delivers pre-matched canonical pairs with depth metadata, eliminating fuzzy-match drift

The trade-off most detection systems get wrong

The conventional framing treats divergence detection as a data problem: get faster feeds, tighter spreads, lower latency. That framing is incomplete. The durable edge in cross-venue prediction market arbitrage has shifted toward resolution-rule analysis and superior normalization, precisely because mechanical price gaps close faster as more automated systems enter the space.

The teams that consistently extract edge are not the ones with the lowest-latency feed. They are the ones who built a canonical pair library with verified resolution text, who track false positives systematically and retrain their pair-scoring thresholds quarterly, and who treat leg risk as a first-class engineering problem rather than an afterthought. A 500-millisecond kill switch on a failed second leg is worth more than shaving 50 milliseconds off detection latency.

One operational note worth internalizing: Kalshi’s ACH settlement and Polymarket’s USDC settlement create asymmetric capital lock-up periods that most backtest models ignore. A trade that looks attractive on a 7-day resolution horizon may tie up capital on the Kalshi side for 2–3 additional business days post-resolution. That friction compounds across a portfolio of simultaneous positions and should be modeled explicitly.

Assymetrix gives you the canonical layer this pipeline needs

Building a cross-venue divergence detector from raw Polymarket and Kalshi feeds means solving canonical normalization, fuzzy-match drift, depth reconstruction, and provenance logging before you write a single line of detection logic. Assymetrix solves that layer first.


Assymetrix

(unsupported figure removed)

The Assymetrix Data API delivers pre-normalized paired market records with stable canonical IDs, yes/no prices from both venues, depth metadata, full resolution text, and millisecond UTC timestamps through a single integration. The historical archive covers nearly one billion rows of trading activity across Polymarket and Kalshi, giving your backtest the sample size it actually needs for statistically stable threshold calibration. Cross-venue arbitrage signals and Smart Money wallet tracking are surfaced on top of the same canonical feed.

Streaming subscriptions, historical exports, and developer API access are available at data.assymetrix.com. Start with the free tier to validate your detection pipeline, then scale to a streaming subscription when you move to live execution.

FAQ

What symmetric KL-divergence threshold signals a real mispricing?

A symmetric KL above 0.15 between Polymarket and Kalshi yes-prices on a confirmed canonical pair indicates a genuine mispricing rather than transient noise. Below that threshold, the gap is more likely bid-ask friction.

How do fees affect the minimum viable edge for a Polymarket-Kalshi arb?

Combined taker fees on common pairs often consume 3–5 cents per contract round-trip, making gross edges under roughly 4–5 cents non-viable. Target a net edge of at least 1.5% after all costs before sizing a position.

Why do identical-sounding markets sometimes resolve differently?

Resolution-rule mismatches, such as one venue using a BLS advance release and another using the revised figure, or different cutoff times, can cause two markets with nearly identical titles to produce asymmetric outcomes. Always compare full resolution text before confirming a pair.

How does Assymetrix simplify cross-venue market matching?

Assymetrix assigns a stable canonical_market_id to pre-matched Polymarket and Kalshi pairs, eliminating fuzzy-match drift and providing normalized prices, depth metadata, and resolution text through a single API call.

What is leg risk and how do you control it?

Leg risk occurs when one side of a two-venue trade fills and the other fails, leaving an unintended directional position. Control it with simultaneous order submission and a hard kill switch that cancels the filled leg if the second order does not confirm within a defined timeout.

Useful sources and further reading

The methods and thresholds in this guide draw on the following sources. Use them to reproduce the KL calibration, validate fee assumptions, and audit the execution risk framework described above.

How to Detect Price Divergence Between Polymarket and Kalshi

TL;DR:

  • Detecting genuine mispricings between Polymarket and Kalshi requires matching markets using a stable canonical ID and applying a symmetric KL-divergence threshold above 0.15. Confirm liquidity depth and identical resolution text before executing trades, ensuring the net-of-fee edge exceeds 1.5 percent for viability. Building such a pipeline benefits from Assymetrix’s pre-normalized data API, which simplifies market pairing and facilitates robust backtesting and live detection.

A reproducible detection pipeline combines normalized cross-venue market matching, spread and z-score screening, and a symmetric KL-divergence above 0.15 threshold to flag likely genuine mispricings between Polymarket and Kalshi. When a signal fires, run three immediate checks before sizing any position:

  • Confirm resolution text is word-for-word identical across both venues

  • Verify order-book depth at your target notional on both sides

  • Compute net-of-fee edge; if it clears 1.5% after combined taker costs, flag for execution

If any check fails, log the signal for analysis and move on. The rest of this guide shows you how to build every layer of that pipeline.

Table of Contents

  • How to detect price divergence between Polymarket and Kalshi: the core metrics

  • How do you match the same market across both venues?

  • What data infrastructure does real-time divergence detection require?

  • How do you execute both legs without creating directional exposure?

  • Worked example: a Fed decision market divergence

  • How should you backtest and calibrate detection thresholds?

  • How does the Assymetrix Data API accelerate this pipeline?

  • Why do resolution-rule differences create false arbitrage signals?

  • What does a live divergence monitoring system look like?

  • Key Takeaways

  • The trade-off most detection systems get wrong

  • Assymetrix gives you the canonical layer this pipeline needs

  • FAQ

  • Useful sources and further reading

How to detect price divergence between Polymarket and Kalshi: the core metrics

Spread, z-score, and symmetric KL divergence


Close-up of hand with stylus near screens showing trading graphs

Raw spread, the absolute difference between Polymarket’s yes-price and Kalshi’s yes-price on a matched market, is the fastest first filter. It is also the most misleading in isolation. A 3-cent spread at 50¢ probability is structurally different from a 3-cent spread at 92¢, because the information content and reversion dynamics differ across probability space.

The z-score corrects for that. Compute it as the current spread divided by the rolling standard deviation of that paired spread over a lookback window (typically 500–2,000 ticks per market category). A z-score above 2.0 on a stable pair warrants attention; above 3.0 it is worth escalating to the distributional check.

Symmetric KL divergence is the definitive filter. For binary markets where each venue quotes a yes-probability p and q:

KL_sym = 0.5 * (p * log(p/q) + (1-p) * log((1-p)/(1-q)))
       + 0.5 * (q * log(q/p) + (1-q) * log((1-q)/(1-p)))

A symmetric KL above 0.15 signals a probability distribution inconsistency large enough to be a genuine mispricing rather than transient noise. Below that threshold, the gap is more likely bid-ask friction or a momentary liquidity imbalance.

A preliminary gross-arb screen runs in parallel: if the cheapest Yes across both venues plus the cheapest No across both venues sums to less than $1.00, a gross arbitrage exists before fees. That check is O(1) and should run on every tick.

Pro Tip: Calibrate KL and z-score thresholds separately by market category. Political markets tend to have higher baseline volatility and wider natural spreads than economic indicator markets (CPI, FOMC). A threshold that generates clean signals on Fed-decision markets will produce excessive false positives on election markets in the final 48 hours before resolution.

How do you match the same market across both venues?

Canonical normalization and fuzzy-matching pipeline

Polymarket and Kalshi use incompatible internal identifiers, different title conventions, and sometimes different outcome sets for what is functionally the same event. The normalization pipeline is where most detection systems fail.


Infographic illustrating canonical normalization and fuzzy matching pipeline steps

The canonical schema fields to align are: normalized title, event date, resolution source, outcome set (yes/no vs. binary contract), and category tag. Strip punctuation, lowercase everything, remove stopwords, and apply named-entity alignment to catch “Fed” vs. “Federal Reserve” or “FOMC” vs. “Federal Open Market Committee.”

Pipeline stage

Operation

Output

Ingestion

Pull raw title, slug, resolution text, tags

Raw record per venue

Canonicalization

Lowercase, tokenize, strip stopwords, NER alignment

Normalized token set

Candidate scoring

Jaccard similarity on token sets + resolution-source match

Score 0–1 per pair

Human-overwatch gate

Flag pairs scoring 0.70–0.85 for manual review

Confirmed or rejected

Confirmed pair

Assign canonical_market_id, store venue_ids

Canonical paired record

Pairs scoring above 0.85 on both token similarity and resolution-source match can be auto-confirmed. Anything below 0.70 is discarded. The middle band requires a human review queue, which shrinks quickly once you build a confirmed-pair library.

A rule-based resolution-source check is non-negotiable. Two markets with identical titles but different resolution sources (BLS advance release vs. BLS revised release, for example) are not the same market. That check alone eliminates the most dangerous false arbs.

What data infrastructure does real-time divergence detection require?

Feed requirements, canonical schema, and latency budgets

Infrastructure layer

Requirement

Notes

Feed type

WebSocket or streaming REST

Polling introduces detection lag

Timestamp accuracy

UTC, millisecond precision

Required for cross-venue tick alignment

Sequence IDs

Per-venue event sequence

Detects dropped messages

Canonical schema fields

market_id, canonical_title, venue_ids, yes_price, no_price, best_depth, timestamp_utc

Minimum viable schema

End-to-end detection latency

Budget per layer

Time synchronization matters more than most teams expect. Clock skew between your Polymarket feed handler and your Kalshi feed handler will produce phantom divergences that disappear on closer inspection. Run NTP or PTP synchronization on all feed-ingestion nodes and log the measured skew in your provenance records.

For depth reconstruction, prefer normalized tick-level snapshots supplemented by periodic full book-dumps. Top-of-book prices are insufficient for sizing; you need the incremental slippage curve at each notional bucket to know whether your target size is actually fillable at the quoted price.

Pro Tip: Store raw ticks with full provenance metadata (venue, sequence ID, ingest timestamp, processing timestamp) even if you only query aggregated snapshots in production. That audit trail is what makes backtests reproducible and lets you diagnose whether a missed signal was a feed gap or a genuine absence of divergence.

How do you execute both legs without creating directional exposure?

Leg risk, fee-aware edge, and execution controls

Leg risk is the primary operational hazard: one leg fills, the other fails due to latency, rate limits, or thin liquidity, and you hold an unintended directional position. Professional systems minimize this by firing both legs as close together as possible, with a kill switch that cancels the unfilled leg and closes the filled leg if the second order does not confirm within a defined timeout (typically 500 ms to 2 s depending on venue API rate limits).

Net-of-fee edge is the number that actually matters. Combined taker fees on common Kalshi-Polymarket pairs often consume 3–5 cents per contract round-trip. A gross edge under roughly 4–5 cents is marginal at best after fees and slippage; practitioners treat sub-4-cent gross edges as non-viable. The minimum viable net edge rule of thumb is 1.5% after all costs.

Execution checklist before firing:

  1. Confirm canonical_market_id match and identical resolution text

  2. Reconstruct order-book slices at target notional; verify fill is achievable at posted prices

  3. Compute net-of-fee edge; reject if below threshold

  4. Check withdrawal and settlement constraints (Kalshi uses ACH/USD; Polymarket uses USDC on Polygon)

  5. Verify neither venue has a pending resolution event within the next 60 minutes

  6. Fire both legs simultaneously with retry logic and a hard kill switch on timeout

Worked example: a Fed decision market divergence

Suppose Polymarket quotes “Fed cuts rates at May FOMC” at 0.62 yes, and Kalshi quotes the same event at 0.55 yes. The gross-arb screen fires immediately: 0.55 + (1 - 0.62) = 0.93 < 1.00.

Compute symmetric KL: with p = 0.62 and q = 0.55, KL_sym ≈ 0.018. That is well below 0.15, meaning the distributional gap is within noise range despite the 7-cent headline spread. The z-score on this pair’s 30-day spread history comes back at 1.4, also below the 2.0 threshold. No signal. Log and continue.

Now shift the scenario: Polymarket at 0.72, Kalshi at 0.55. KL_sym ≈ 0.089, z-score at 2.8. Still below the KL threshold, but the z-score warrants a depth check.

Scenario

Polymarket yes

Kalshi yes

KL_sym

Z-score

Signal?

Baseline

0.62

0.55

0.018

1.4

No

Moderate gap

0.72

0.55

0.089

2.8

Depth check

Strong gap

0.82

0.55

0.21

Yes — verify resolution

At the strong-gap scenario, KL_sym = 0.21 exceeds 0.15. Reconstruct book slices: Polymarket shows $8,000 available at 0.82; Kalshi shows $12,000 at 0.55. For a $5,000 notional position, both sides are fillable. Net-of-fee edge after 3 cents per side: approximately 24 cents per dollar, well above the 1.5% minimum.

Pro Tip: Use fixed-fraction sizing (e.g., 2–5% of capital per signal) rather than full Kelly in early live trading. Kelly sizing is theoretically optimal but requires an accurate edge estimate, which your backtest may overstate before you have live fill data to calibrate against.

How should you backtest and calibrate detection thresholds?

Backtesting a divergence detector requires four inputs: canonical historical ticks for both venues, per-venue order-book reconstructions at the time of each signal, the fee schedule in effect during the test period, and a realistic fill model that accounts for queue position and partial fills.

  1. Build a canonical tick database from historical exports, joining on canonical_market_id

  2. Replay ticks chronologically; compute spread, z-score, and KL_sym at each step

  3. At each threshold exceedance, simulate fills using reconstructed book slices

  4. Apply fee schedules and record net PnL per signal

  5. Split into in-sample calibration and out-of-sample validation sets; use bootstrap resampling to estimate confidence intervals on hit rate and mean return per signal

KL threshold

Approx. signal rate

Approx. true-positive rate

Mean net edge per signal

> 0.10

High

Lower (more noise)

Marginal

> 0.15

Moderate

Higher

Positive after fees

> 0.20

Low

Highest

Strong but rare

The 0.15 threshold sits at the practical optimum for most political and economic market categories: enough signals to generate meaningful returns, with a true-positive rate that justifies automated execution. Tighten to 0.20 for fully automated systems with no human review; loosen to 0.10 only in monitored paper-trade mode.

How does the Assymetrix Data API accelerate this pipeline?

Assymetrix provides the canonical normalization layer that replaces the fuzzy-matching pipeline described above. The Data API at data.assymetrix.com returns pre-matched market pairs with a stable canonical_market_id, normalized yes/no prices from both venues, depth metadata, resolution text, and UTC timestamps in a single response. The historical coverage spans nearly one billion rows of trading activity, which is the sample size required for statistically stable threshold calibration across market categories.

Sample canonical schema returned by the API:

Field

Description

canonical_market_id

Stable cross-venue identifier

venue_map

{polymarket_id, kalshi_id}

yes_price_poly

Polymarket yes mid

yes_price_kalshi

Kalshi yes mid

best_depth_poly

Top-of-book depth, Polymarket

best_depth_kalshi

Top-of-book depth, Kalshi

resolution_text

Full resolution clause (both venues)

timestamp_utc

Millisecond-precision UTC

A Python snippet to fetch a paired record and compute KL_sym in-stream:

import requests, math

def kl_sym(p, q, eps=1e-9):
    p, q = max(p, eps), max(q, eps)
    p_, q_ = 1 - p, 1 - q
    return 0.5 * (p*math.log(p/q) + p_*math.log(p_/q_)
                + q*math.log(q/p) + q_*math.log(q_/p_))

resp = requests.get(
    "https://data.assymetrix.com/v1/markets/paired",
    headers={"Authorization": "Bearer YOUR_KEY"}
)
for market in resp.json()["markets"]:
    kl = kl_sym(market["yes_price_poly"], market["yes_price_kalshi"])
    if kl > 0.15:
        print(f"Signal: {market['canonical_market_id']} | KL={kl:.3f}")

Pro Tip: Use Assymetrix’s canonical_market_id as the join key in your backtest database. Fuzzy-match drift, where a pair that was correctly matched at ingestion silently diverges as market titles update, is one of the hardest bugs to catch post-hoc. A stable canonical ID eliminates it.

Why do resolution-rule differences create false arbitrage signals?

Resolution-rule mismatches are the single most common source of false arb signals. Two markets with nearly identical titles can resolve on different data releases (BLS advance vs. BLS revised), different official sources, or different cutoff times, producing asymmetric outcomes that make a convergence trade a directional bet in disguise.

The workflow is non-negotiable: always fetch and compare the full resolution text from both venues before confirming a pair. Any textual mismatch, even a difference in the cited data release vintage, disqualifies the pair from arb treatment. Flag it as a non-arb divergence and route it to a separate research queue.

Regulatory settlement mechanics also differ. Kalshi settles in USD via ACH with custodial fund holding; Polymarket settles in USDC on Polygon with non-custodial wallet control. Settlement timing differences affect capital lock-up calculations and should be factored into annualized return estimates.

This article is general information, not legal or financial advice. Confirm current regulatory requirements and fee schedules with each venue’s official documentation and a qualified professional before trading.

What does a live divergence monitoring system look like?

Dashboard KPIs and runbook steps

A production monitoring system needs four dashboard KPIs: signal rate (signals per hour by market category), true-positive rate after manual spot-checks, mean detection-to-execution latency, and fill success rate (both legs filled vs. one-leg failures).

Alert tiers:

  • P0 (auto-execute): KL > 0.15 + depth sufficient at target notional + resolution text confirmed identical + net edge > 1.5%

  • P1 (human review): KL > 0.10 + depth borderline or resolution text flagged for review

  • P2 (log only): Gross-arb screen fires but KL < 0.10

Runbook for a P0 alert:

  1. Automated system fires both legs with kill-switch timeout

  2. Post-trade reconciliation confirms both fills within 30 seconds

  3. If one leg fails, automated cancel-and-close sequence runs; alert on-call engineer

  4. Log signal, fill prices, slippage, and net PnL to the audit database

  5. Flag for threshold review if fill slippage exceeded the pre-trade estimate by more than 20%

Data-quality exceptions (missing ticks, feed gaps, anomalous prices) should trigger an automatic pause on automated execution for the affected market pair until the feed is confirmed clean.

Key Takeaways

Detecting genuine price divergence between Polymarket and Kalshi requires canonical market matching, a symmetric KL-divergence threshold above 0.15, confirmed liquidity depth, and identical resolution text before any position is sized.

Point

Details

Core detection rule

Canonical pair match + symmetric KL > 0.15 + depth check + identical resolution text = valid signal

Fee-aware edge minimum

Net edge must exceed 1.5% after combined taker fees; gross edges under ~4–5 cents are typically non-viable

Backtest sample size

Use nearly one billion rows of historical activity to calibrate KL and z-score thresholds by market category

Resolution text is mandatory

Always compare full resolution clauses; title similarity alone produces false arb signals

Assymetrix integration

The Assymetrix Data API delivers pre-matched canonical pairs with depth metadata, eliminating fuzzy-match drift

The trade-off most detection systems get wrong

The conventional framing treats divergence detection as a data problem: get faster feeds, tighter spreads, lower latency. That framing is incomplete. The durable edge in cross-venue prediction market arbitrage has shifted toward resolution-rule analysis and superior normalization, precisely because mechanical price gaps close faster as more automated systems enter the space.

The teams that consistently extract edge are not the ones with the lowest-latency feed. They are the ones who built a canonical pair library with verified resolution text, who track false positives systematically and retrain their pair-scoring thresholds quarterly, and who treat leg risk as a first-class engineering problem rather than an afterthought. A 500-millisecond kill switch on a failed second leg is worth more than shaving 50 milliseconds off detection latency.

One operational note worth internalizing: Kalshi’s ACH settlement and Polymarket’s USDC settlement create asymmetric capital lock-up periods that most backtest models ignore. A trade that looks attractive on a 7-day resolution horizon may tie up capital on the Kalshi side for 2–3 additional business days post-resolution. That friction compounds across a portfolio of simultaneous positions and should be modeled explicitly.

Assymetrix gives you the canonical layer this pipeline needs

Building a cross-venue divergence detector from raw Polymarket and Kalshi feeds means solving canonical normalization, fuzzy-match drift, depth reconstruction, and provenance logging before you write a single line of detection logic. Assymetrix solves that layer first.


Assymetrix

(unsupported figure removed)

The Assymetrix Data API delivers pre-normalized paired market records with stable canonical IDs, yes/no prices from both venues, depth metadata, full resolution text, and millisecond UTC timestamps through a single integration. The historical archive covers nearly one billion rows of trading activity across Polymarket and Kalshi, giving your backtest the sample size it actually needs for statistically stable threshold calibration. Cross-venue arbitrage signals and Smart Money wallet tracking are surfaced on top of the same canonical feed.

Streaming subscriptions, historical exports, and developer API access are available at data.assymetrix.com. Start with the free tier to validate your detection pipeline, then scale to a streaming subscription when you move to live execution.

FAQ

What symmetric KL-divergence threshold signals a real mispricing?

A symmetric KL above 0.15 between Polymarket and Kalshi yes-prices on a confirmed canonical pair indicates a genuine mispricing rather than transient noise. Below that threshold, the gap is more likely bid-ask friction.

How do fees affect the minimum viable edge for a Polymarket-Kalshi arb?

Combined taker fees on common pairs often consume 3–5 cents per contract round-trip, making gross edges under roughly 4–5 cents non-viable. Target a net edge of at least 1.5% after all costs before sizing a position.

Why do identical-sounding markets sometimes resolve differently?

Resolution-rule mismatches, such as one venue using a BLS advance release and another using the revised figure, or different cutoff times, can cause two markets with nearly identical titles to produce asymmetric outcomes. Always compare full resolution text before confirming a pair.

How does Assymetrix simplify cross-venue market matching?

Assymetrix assigns a stable canonical_market_id to pre-matched Polymarket and Kalshi pairs, eliminating fuzzy-match drift and providing normalized prices, depth metadata, and resolution text through a single API call.

What is leg risk and how do you control it?

Leg risk occurs when one side of a two-venue trade fills and the other fails, leaving an unintended directional position. Control it with simultaneous order submission and a hard kill switch that cancels the filled leg if the second order does not confirm within a defined timeout.

Useful sources and further reading

The methods and thresholds in this guide draw on the following sources. Use them to reproduce the KL calibration, validate fee assumptions, and audit the execution risk framework described above.