← Back to blog
·10 min read·SettleRisk Team

Resolution Timing Arbitrage: Exploiting Cross-Platform Settlement Asynchronicity

Deep Dive

Resolution Timing Arbitrage: Exploiting Cross-Platform Settlement Asynchronicity

Executive Summary

When the same event trades on multiple prediction market platforms, the resolution timing is rarely synchronized. One venue may settle hours, days, or even weeks before another—creating a window where an informed trader knows the outcome while positions remain open elsewhere. This is resolution timing arbitrage, and it represents one of the most persistent yet underappreciated edges in prediction market microstructure.

This article provides a quantitative framework for:

  • Identifying timing arbitrage opportunities across Polymarket, Kalshi, and other venues
  • Modeling the expected value of cross-platform latency exploitation
  • Building monitoring systems to detect resolution announcements in real-time
  • Managing the counterparty and operational risks inherent in settlement delays

By the end, you'll have working code for timing arbitrage detection and a decision matrix for when to exploit—or avoid—these edges.

Core Concept

The Settlement Latency Window

Prediction markets resolve through diverse mechanisms with varying speeds:

| Platform | Typical Resolution Time | Settlement Mechanism | Notification Latency | |----------|------------------------|---------------------|---------------------| | Polymarket | 2-48 hours post-event | UMA Optimistic Oracle | 1-5 minutes (Discord/Twitter) | | Kalshi | 1-7 days post-event | Internal + CFTC oversight | 5-30 minutes (Email/API) | | Axiom | 1-24 hours post-event | UMA-based | 1-10 minutes (On-chain events) | | Betfair | Immediate to 24 hours | Exchange matching engine | Real-time (Streaming API) | | Crypto sportsbooks | Immediate to 48 hours | Automated oracle feeds | 1-15 minutes |

The settlement latency window (SLW) is the time between:

  1. The first authoritative resolution (outcome becomes knowable)
  2. The final platform settlement (all positions closed)

During this window, traders with faster information pipelines can:

  • Exit winning positions at pre-resolution prices
  • Enter contrarian positions on lagging platforms
  • Hedge cross-platform exposure with near-certain outcomes

The Arbitrage Value Equation

The expected value of a timing arbitrage opportunity can be modeled as:

EV = (P × S × D) - (C × T) - R

Where:

  • P = Probability of successful information edge (0.0-1.0)
  • S = Size of position that can be executed
  • D = Price delta between platforms (normalized to 0.0-1.0)
  • C = Capital cost per unit time (including opportunity cost and funding)
  • T = Expected time to full settlement
  • R = Risk-adjusted cost of adverse selection or platform intervention

A simplified Timing Arbitrage Score (TAS) for rapid assessment:

TAS = (D × √S) / (T × σ)

Where σ represents the volatility of the underlying event (higher volatility = more noise, harder to exploit).

Information Asymmetry Sources

Timing edges emerge from several structural factors:

  1. Oracle Diversity: Platforms using different resolution sources (primary vs. secondary reporting)
  2. Dispute Windows: UMA-based markets have 48-96 hour dispute periods before finalization
  3. Manual Review: Human oversight for edge cases creates unpredictable delays
  4. Time Zone Effects: Operational teams in different geographic regions
  5. Technical Latency: API polling intervals, webhook delivery, and database propagation

Worked Example

Scenario: The 2024 Election Resolution Cascade

Consider the 2024 U.S. Presidential election results as a canonical timing arbitrage case:

Event Timeline:

  • Nov 5, 11:47 PM ET: Major networks call Pennsylvania for Candidate A
  • Nov 5, 11:52 PM ET: Mathematical elimination—Candidate B cannot reach 270 electoral votes
  • Nov 6, 12:15 AM ET: Polymarket resolution proposal submitted (UMA oracle)
  • Nov 6, 12:47 AM ET: Kalshi trading suspended pending resolution review
  • Nov 6, 2:30 AM ET: UMA dispute window expires, Polymarket settles
  • Nov 6, 9:00 AM ET: Kalshi official resolution and settlement

Arbitrage Opportunity Window:

| Time | Platform | Action | Price | Implied Edge | |------|----------|--------|-------|-------------| | 11:52 PM | Polymarket | Buy YES | $0.94 | 6% | | 12:15 AM | Axiom | Buy YES | $0.96 | 4% | | 2:30 AM | Kalshi | Still trading | $0.97 | 3% | | 9:00 AM | All platforms | Settled at $1.00 | — | — |

Quantitative Analysis:

A trader with $500,000 capital and 15-minute information latency could have:

Position Size: $500,000
Average Entry: $0.955
Settlement Price: $1.00
Gross Profit: $500,000 × (1.00 - 0.955) = $22,500
Capital Cost (9.25 hours @ 8% APR): $500,000 × 0.08 × (9.25/8760) = $42
Expected Value: $22,500 - $42 - $500 (risk buffer) = $21,958
ROI: 4.4% in <24 hours
Annualized ROI: ~1,600% (if repeatable)

This represents a TAS of 7.2 (highly favorable) assuming σ=0.05.

Implementation Notes

Real-Time Resolution Detection Pipeline

Building a timing arbitrage system requires sub-minute detection of resolution events. Here's a production-ready monitoring architecture:

#!/usr/bin/env python3
"""
Resolution Timing Arbitrage Detector
Monitors multiple platforms for settlement events and cross-references prices
"""

import asyncio
import json
import os
from dataclasses import dataclass
from datetime import datetime, timedelta
from typing import Dict, List, Optional
import aiohttp
import websockets


@dataclass
class MarketPosition:
    platform: str
    market_id: str
    yes_price: float
    no_price: float
    liquidity: float
    last_updated: datetime


@dataclass
class ResolutionEvent:
    platform: str
    market_id: str
    outcome: str
    confidence: float
    detected_at: datetime
    source: str  # 'websocket', 'polling', 'manual'


class TimingArbitrageDetector:
    def __init__(self):
        self.positions: Dict[str, List[MarketPosition]] = {}
        self.resolution_cache: Dict[str, ResolutionEvent] = {}
        self.arbitrage_threshold = 0.03  # 3% minimum edge
        
    async def poll_polymarket(self) -> List[MarketPosition]:
        """Poll Polymarket API for market data"""
        async with aiohttp.ClientSession() as session:
            async with session.get(
                "https://gamma-api.polymarket.com/markets",
                params={"active": "true", "closed": "false"}
            ) as resp:
                data = await resp.json()
                return [
                    MarketPosition(
                        platform="polymarket",
                        market_id=m["conditionId"],
                        yes_price=float(m.get("outcomePrices", [0, 1])[1]),
                        no_price=float(m.get("outcomePrices", [1, 0])[0]),
                        liquidity=float(m.get("volume", 0)),
                        last_updated=datetime.utcnow()
                    )
                    for m in data
                ]
    
    async def poll_kalshi(self) -> List[MarketPosition]:
        """Poll Kalshi API for market data (requires auth)"""
        api_key = os.environ.get("KALSHI_API_KEY")
        async with aiohttp.ClientSession() as session:
            async with session.get(
                "https://trading-api.kalshi.com/v1/markets",
                headers={"Authorization": f"Bearer {api_key}"}
            ) as resp:
                data = await resp.json()
                return [
                    MarketPosition(
                        platform="kalshi",
                        market_id=m["ticker"],
                        yes_price=m.get("yes_ask", 0) / 100,
                        no_price=m.get("no_ask", 0) / 100,
                        liquidity=m.get("volume", 0),
                        last_updated=datetime.utcnow()
                    )
                    for m in data.get("markets", [])
                ]
    
    async def monitor_twitter_resolution(self, keywords: List[str]):
        """Monitor Twitter/X for resolution announcements"""
        # Note: Requires Twitter API v2 access
        # This is a simplified implementation
        pass
    
    def calculate_arbitrage_opportunity(
        self,
        market_pair: List[MarketPosition],
        resolved_outcome: str
    ) -> Optional[Dict]:
        """
        Calculate if a timing arbitrage exists
        Returns opportunity details if edge > threshold
        """
        if len(market_pair) < 2:
            return None
            
        resolved_platform = None
        unresolved_platforms = []
        
        for pos in market_pair:
            market_key = f"{pos.platform}:{pos.market_id}"
            if market_key in self.resolution_cache:
                resolved_platform = pos
            else:
                unresolved_platforms.append(pos)
        
        if not resolved_platform or not unresolved_platforms:
            return None
            
        opportunities = []
        for unresolved in unresolved_platforms:
            # Calculate price delta
            if resolved_outcome == "yes":
                delta = 1.0 - unresolved.yes_price
                action = "buy_yes"
                entry = unresolved.yes_price
            else:
                delta = 1.0 - unresolved.no_price
                action = "buy_no"
                entry = unresolved.no_price
                
            if delta > self.arbitrage_threshold:
                ev = self._calculate_ev(
                    position_size=min(10000, unresolved.liquidity * 0.1),
                    entry_price=entry,
                    delta=delta
                )
                
                opportunities.append({
                    "action": action,
                    "target_platform": unresolved.platform,
                    "resolved_platform": resolved_platform.platform,
                    "entry_price": entry,
                    "expected_exit": 1.0,
                    "delta": delta,
                    "position_size": min(10000, unresolved.liquidity * 0.1),
                    "expected_value": ev,
                    "timestamp": datetime.utcnow().isoformat()
                })
        
        return opportunities[0] if opportunities else None
    
    def _calculate_ev(
        self,
        position_size: float,
        entry_price: float,
        delta: float,
        time_to_settlement: float = 24,  # hours
        capital_cost_annual: float = 0.08
    ) -> float:
        """Calculate expected value of timing arbitrage"""
        gross_profit = position_size * delta
        capital_cost = position_size * capital_cost_annual * (time_to_settlement / 8760)
        risk_buffer = position_size * 0.001  # 10bps risk adjustment
        return gross_profit - capital_cost - risk_buffer
    
    async def run_monitoring_loop(self):
        """Main monitoring loop"""
        while True:
            try:
                # Poll all platforms
                polymarket_data = await self.poll_polymarket()
                # kalshi_data = await self.poll_kalshi()  # Uncomment with valid API key
                
                # Group by market correlation (simplified—would use semantic matching)
                # For demonstration, assume markets are pre-mapped
                
                print(f"[UTC {datetime.utcnow()}] Polled {len(polymarket_data)} markets")
                
                await asyncio.sleep(30)  # 30-second polling interval
                
            except Exception as e:
                print(f"Error in monitoring loop: {e}")
                await asyncio.sleep(60)


if __name__ == "__main__":
    detector = TimingArbitrageDetector()
    asyncio.run(detector.run_monitoring_loop())

Cross-Platform Market Mapping

The most challenging aspect of timing arbitrage is market correlation detection—determining when two markets on different platforms represent the same underlying event. Approaches include:

  1. Semantic Matching: NLP-based comparison of market titles and descriptions
  2. Keyword Clustering: Shared entities (candidates, teams, companies, countries)
  3. Resolution Source Alignment: Markets referencing the same oracle source
  4. Manual Curation: Maintaining a mapping database for high-volume events

Execution Considerations

Once an opportunity is detected, execution speed becomes critical:

| Factor | Impact | Mitigation | |--------|--------|------------| | API latency | 100-500ms | WebSocket feeds, colocation | | Rate limiting | Throttling | Exponential backoff, multiple keys | | Position limits | Reduced size | Multiple sub-accounts | | Withdrawal delays | Capital trapped | Pre-funded accounts on all platforms |

Failure Modes / Common Mistakes

1. False Resolution Signals

Not all early announcements are authoritative. Common traps:

  • Projected results: News organizations calling races before 100% counted
  • Conditional resolutions: "Assuming no recount" settlements that get disputed
  • Test environments: Staging systems leaking false signals

Mitigation: Require multiple independent confirmations before acting.

2. Dispute Window Risk (UMA Markets)

UMA-based markets have a 48-96 hour dispute window. A "resolved" market can revert:

Case Study: Market resolved YES at 2:00 AM
Trader buys NO at $0.02 on lagging platform
Dispute raised at 10:00 AM (legitimate ambiguity found)
Market reverts to unresolved
Final resolution: YES (original outcome stood)
Result: 100% loss on NO position

Mitigation: Only exploit timing edges after the dispute window closes, or size positions to account for revert probability.

3. Platform Intervention

Platforms may void trades or suspend markets when timing arbitrage is detected:

  • Kalshi: CFTC-regulated, can cancel "clearly erroneous" trades
  • Polymarket: UMA governance can modify resolutions
  • Crypto sportsbooks: Often reserve right to void suspicious activity

Mitigation: Diversify across platforms; never exceed 5% of daily volume on any single venue.

4. Adverse Selection in Fast Markets

When you're buying at $0.94 after a resolution signal, you may be trading against:

  • Insiders with better information
  • Automated systems with faster feeds
  • Platform operators themselves

Mitigation: Analyze order book depth; if your entry moves the market significantly, the edge may already be gone.

Checklist

Before executing a timing arbitrage strategy:

  • [ ] Confirmed resolution source is authoritative (not projection/estimate)
  • [ ] Verified dispute window has closed (for UMA markets)
  • [ ] Checked position limits won't restrict intended size
  • [ ] Confirmed withdrawal capability on target platform
  • [ ] Analyzed order book depth for slippage estimation
  • [ ] Calculated TAS > 2.0 (favorable edge threshold)
  • [ ] Set up automated position sizing (don't exceed 10% of liquidity)
  • [ ] Tested API endpoints within last 24 hours
  • [ ] Verified capital is pre-funded on all target platforms
  • [ ] Set stop-loss for case of resolution reversal

Sources + Further Reading

Platform Documentation

Academic Research

  • "The Market Microstructure of Prediction Markets" — Wolfers & Zitzewitz (2004)
  • "Arbitrage and Efficiency in Event Markets" — Crosetto & Filippin (2016)
  • "Information Aggregation in Prediction Markets" — Chen et al. (2021)

Industry Analysis

  • Bloomberg: "The $100 Million Race to Predict the Future" (2024)
  • FT Alphaville: "Prediction Markets and the Wisdom of Crowds" (2023)
  • Kalshi Blog: "How We Settle Markets" (2024)

Related SettleRisk Resources

  • Oracle Governance Risk Framework
  • Resolution Infrastructure Deep Dive
  • UMA Whale Concentration Analysis

This article is for educational purposes only. Timing arbitrage carries significant risk of loss, and past performance does not guarantee future results. Always conduct your own research and never trade with capital you cannot afford to lose.

Get weekly risk analysis in your inbox

Market risk scores, emerging dispute patterns, and settlement delay trends — delivered every Monday.