A prediction market price is an implied probability. YES at $0.63 = 63% chance. YES + NO must equal $1.00 — if they don’t, arbitrage exists. This is the foundational math every betting agent needs before doing anything else.

Why This Matters for Agents

Before an autonomous agent can evaluate whether a prediction market position is worth taking, it needs to answer one question: what probability does the market imply?

This is Layer 3 — Trading. Price-to-probability conversion is the first operation in any agent’s decision pipeline. The agent pulls prices from the Polymarket CLOB API or Kalshi REST API, converts them to implied probabilities, then passes those probabilities to its Layer 4 intelligence module for comparison against its own model. If the agent’s model says 72% and the market says 63%, there may be edge. But without understanding what $0.63 actually means mathematically, the agent is blind.

Everything in this series builds on what follows. Expected value, Kelly sizing, Bayesian updating — all require clean implied probabilities as inputs.

The Binary Contract

A prediction market binary contract is the simplest financial instrument that exists:

  • YES contract: Pays $1.00 if the event happens. Pays $0.00 if it doesn’t.
  • NO contract: Pays $1.00 if the event doesn’t happen. Pays $0.00 if it does.

That’s it. Every prediction market — Polymarket, Kalshi, or otherwise — is built on this primitive.

If you buy a YES contract for $0.63 and the event occurs, you receive $1.00. Your profit is $0.37. If the event doesn’t occur, you lose your $0.63.

Payoff Structure — YES Contract Bought at $0.63

Event Occurs:      +$1.00 - $0.63 = +$0.37 profit
Event Doesn't:     +$0.00 - $0.63 = -$0.63 loss

Why Price Equals Probability

Here’s the key insight: the price of a YES contract is the implied probability of the event occurring. This isn’t a metaphor — it’s a mathematical identity under the no-arbitrage assumption.

The proof is straightforward.

Suppose you believe the true probability of an event is p. You’re considering buying a YES contract at price c.

Your expected value is:

EV = p × ($1.00 - c) - (1 - p) × c
EV = p - pc - c + pc
EV = p - c

A rational agent buys when EV > 0, which means p > c. A rational agent sells when p < c. In equilibrium — when no agent can profitably trade — the price converges to c = p.

The price is the probability.

This holds exactly in a zero-fee market. In practice, fees and spreads create a small wedge between price and true probability, which we’ll address below.

The No-Arbitrage Condition

In a fair binary market, a mathematical constraint must hold:

Price(YES) + Price(NO) = $1.00

This is the completeness condition. Since exactly one of {YES, NO} will pay $1.00, a portfolio of one YES and one NO always pays exactly $1.00. If the cost of that portfolio is anything other than $1.00, free money exists.

Case 1: Sum Less Than $1.00 — Guaranteed Profit

Suppose on Polymarket, a market is priced:

YES = $0.58
NO  = $0.37
Sum = $0.95

An agent buys one YES for $0.58 and one NO for $0.37. Total cost: $0.95.

  • If the event occurs: YES pays $1.00. Profit = $1.00 - $0.95 = $0.05
  • If the event doesn’t occur: NO pays $1.00. Profit = $1.00 - $0.95 = $0.05

Guaranteed $0.05 profit per $0.95 risked, regardless of outcome. That’s a 5.26% risk-free return. This is arbitrage — and it gets closed almost instantly on liquid markets because agents (and humans) compete to capture it.

Case 2: Sum Greater Than $1.00 — The Overround

Now suppose:

YES = $0.53
NO  = $0.49
Sum = $1.02

Buying both sides costs $1.02 for a guaranteed $1.00 return — you’d lose $0.02 no matter what. The $0.02 excess is the overround (also called the vig or vigorish in sportsbook terminology). It’s the market maker’s margin.

In sportsbooks, the overround is massive — typically 4-10%. In prediction markets, it’s much smaller:

PlatformOverround MechanismTypical Overround
Polymarket CLOBNear-zero spread on liquid markets; 2% fee on net winnings~0-1% spread + 2% on profit
KalshiBuilt into bid-ask spread~2-5% on most markets
Traditional sportsbook (-110/-110)Baked into odds4.76%
Offshore sportsbook (typical)Varies by sport and book4-10%

For the full sportsbook vig breakdown with live data, see the AgentBets Vig Index.

Extracting Probabilities from Real Markets

From Polymarket

Polymarket’s CLOB (Central Limit Order Book) shows a full orderbook with bids and asks. The implied probability comes from the midpoint between the best bid and best ask for YES:

Implied Probability = (Best Bid + Best Ask) / 2

For a market with YES best bid = $0.61 and YES best ask = $0.63:

Implied Probability = ($0.61 + $0.63) / 2 = $0.62 = 62%

The spread ($0.02) is the cost of immediacy — if you want to trade now rather than place a limit order, you pay the spread.

Here’s how an agent pulls this programmatically using py-clob-client:

from py_clob_client.client import ClobClient

client = ClobClient(
    host="https://clob.polymarket.com",
    chain_id=137  # Polygon
)

# Get orderbook for a specific market (token_id from Gamma API)
token_id = "71321045679252212594626385532706912750332728571942532289631379312455583992563"
book = client.get_order_book(token_id)

best_bid = float(book.bids[0].price) if book.bids else 0
best_ask = float(book.asks[0].price) if book.asks else 1

midpoint = (best_bid + best_ask) / 2
spread = best_ask - best_bid

print(f"Best bid:  ${best_bid:.4f}")
print(f"Best ask:  ${best_ask:.4f}")
print(f"Midpoint:  ${midpoint:.4f} ({midpoint*100:.1f}%)")
print(f"Spread:    ${spread:.4f}")

For the full py-clob-client method reference, see py_clob_client Docs.

From Kalshi

Kalshi uses fixed-point dollar string pricing. A YES price of "0.6300" means 63% implied probability:

import requests
from decimal import Decimal

KALSHI_API = "https://api.elections.kalshi.com/trade-api/v2"

# No auth required for market data
resp = requests.get(f"{KALSHI_API}/markets", params={
    "limit": 5,
    "status": "open"
})

for market in resp.json()["markets"]:
    yes_bid = market.get("yes_bid_dollars", "0")
    yes_ask = market.get("yes_ask_dollars", "0")

    if yes_bid and yes_ask:
        bid = Decimal(yes_bid)
        ask = Decimal(yes_ask)
        midpoint = (bid + ask) / 2
        spread = ask - bid

        print(f"{market['ticker']}: {market['title'][:60]}")
        print(f"  YES bid: ${yes_bid}  |  YES ask: ${yes_ask}")
        print(f"  Implied: {float(midpoint):.1%}  |  Spread: ${spread}")
        print()

For the full Kalshi API reference, see the Prediction Market API Reference or the Kalshi API tool entry.

Multi-Outcome Markets

Many real prediction markets have more than two outcomes — “Who will win the 2028 presidential election?” might have 8+ candidates.

The math extends naturally. For n outcomes, the completeness condition becomes:

Σ Price(outcome_i) = $1.00    (in a zero-vig market)

In practice, the sum exceeds $1.00 by the overround. To extract true implied probabilities from a multi-outcome market with overround, use the multiplicative method — divide each price by the sum of all prices:

True_Prob(i) = Price(i) / Σ Price(j)

Worked Example

A Polymarket “Who will be the next UK Prime Minister?” market might show:

Keir Starmer:     $0.65
Rishi Sunak:      $0.18
Other:            $0.12
Nigel Farage:     $0.08
────────────────────────
Sum:              $1.03  (overround = 3%)

The raw prices sum to $1.03, so they aren’t true probabilities. Applying the multiplicative correction:

import numpy as np

prices = {"Starmer": 0.65, "Sunak": 0.18, "Other": 0.12, "Farage": 0.08}
total = sum(prices.values())
overround = total - 1.0

print(f"Overround: {overround:.1%}\n")
print(f"{'Outcome':<12} {'Raw Price':>10} {'True Prob':>10}")
print("-" * 34)
for name, price in prices.items():
    true_prob = price / total
    print(f"{name:<12} ${price:>8.2f}  {true_prob:>9.1%}")
print("-" * 34)
print(f"{'Sum':<12} ${total:>8.2f}  {'100.0%':>10}")

Output:

Overround: 3.0%

Outcome       Raw Price  True Prob
----------------------------------
Starmer         $0.65      63.1%
Sunak           $0.18      17.5%
Other           $0.12      11.7%
Farage          $0.08       7.8%
----------------------------------
Sum             $1.03     100.0%

The multiplicative method is the simplest vig-removal technique. For sports betting, more sophisticated methods exist — Shin’s method accounts for insider trading, and the power method handles favorite-longshot bias. Those are covered in the Sports Betting Math 101 guide.

Cross-Platform Price Comparison

An agent monitoring multiple platforms needs to normalize prices into the same format. Here’s the conversion:

                    ┌──────────────┐
                    │  Probability │
                    │   (0 to 1)   │
                    └──────┬───────┘
                           │
              ┌────────────┼────────────┐
              ▼            ▼            ▼
      ┌──────────┐  ┌──────────┐  ┌──────────────┐
      │Polymarket│  │  Kalshi  │  │  Sportsbook  │
      │ $0.63    │  │  63¢     │  │  -170 / +170 │
      │ (direct) │  │ (÷ 100) │  │  (convert)   │
      └──────────┘  └──────────┘  └──────────────┘

For sportsbook American odds to probability conversion:

def american_to_prob(odds: int) -> float:
    """Convert American odds to implied probability."""
    if odds < 0:  # favorite
        return abs(odds) / (abs(odds) + 100)
    else:  # underdog
        return 100 / (odds + 100)

# -170 favorite → 63.0% implied
print(f"-170 → {american_to_prob(-170):.1%}")

# +170 underdog → 37.0% implied
print(f"+170 → {american_to_prob(170):.1%}")

# Combined: 63.0% + 37.0% = 100.0% (no vig in this example)
# Real sportsbooks: -110/-110 → 52.4% + 52.4% = 104.8% (4.8% vig)

The AgentBets Vig Index tracks sportsbook overrounds in real time. For the same event priced on both a prediction market and a sportsbook, the prediction market almost always has lower vig — which is why cross-platform arbitrage between sportsbooks and prediction markets is a viable agent strategy. See the Arbitrage Calculator for the math.

Where This Breaks Down

The “price = probability” identity relies on assumptions that don’t always hold:

1. Illiquid markets. In a market with $50 of total liquidity, the price is unreliable. The spread might be $0.10 wide, making the midpoint a poor probability estimate. An agent should track depth, not just price. If the best bid is $0.55 with $12 behind it, that $0.55 doesn’t carry the same information content as a $0.55 bid with $50,000 behind it.

2. Fee-adjusted pricing. Polymarket charges ~2% on net winnings. An agent that buys YES at $0.63 and wins receives $1.00 minus ~$0.0074 in fees (2% of the $0.37 profit). The fee-adjusted breakeven probability is slightly higher than the raw price implies. For precision:

Fee-adjusted breakeven = Price / (1 - fee_rate × (1 - Price))
$0.63 / (1 - 0.02 × 0.37) = $0.63 / 0.9926 = $0.6347

The 0.47% difference matters at scale.

3. Time value and opportunity cost. A contract trading at $0.95 for an event six months away might look like a 95% probability, but it also locks capital that could earn yield elsewhere. The risk-free rate creates a floor price for near-certain outcomes. This is why contracts near $0.95-$0.99 are often mispriced — the EMH guide covers this in depth.

4. Correlated outcomes. In multi-outcome markets, individual contract prices can temporarily violate completeness if trades in one outcome haven’t propagated to correlated outcomes. An agent that detects Σ prices < $1.00 across outcomes should verify it isn’t a transient orderbook lag before executing an arb.

Implementation: Agent Probability Extraction Module

Here’s a self-contained module an agent can use to extract clean probabilities from both Polymarket and Kalshi:

import numpy as np
from dataclasses import dataclass


@dataclass
class MarketProbability:
    """Standardized probability output for agent consumption."""
    platform: str
    market_id: str
    outcomes: dict[str, float]  # outcome_name -> probability
    overround: float
    spread: float
    method: str  # "midpoint", "multiplicative", "last_trade"


def polymarket_probability(
    best_bid: float,
    best_ask: float,
    fee_rate: float = 0.02
) -> tuple[float, float]:
    """
    Extract implied probability from Polymarket YES bid/ask.
    Returns (raw_probability, fee_adjusted_probability).
    """
    midpoint = (best_bid + best_ask) / 2
    spread = best_ask - best_bid
    
    # Fee-adjusted: account for Polymarket's winner fee
    if midpoint > 0 and midpoint < 1:
        fee_adjusted = midpoint / (1 - fee_rate * (1 - midpoint))
    else:
        fee_adjusted = midpoint
    
    return midpoint, fee_adjusted


def remove_overround(
    prices: dict[str, float],
    method: str = "multiplicative"
) -> dict[str, float]:
    """
    Remove overround from multi-outcome market prices.
    Returns dict of outcome -> true probability.
    
    Methods:
      multiplicative: divide each by sum (simplest, assumes uniform vig)
      
    For Shin's method and power method, see the sports-betting-math-101 guide.
    """
    total = sum(prices.values())
    
    if method == "multiplicative":
        return {k: v / total for k, v in prices.items()}
    
    raise ValueError(f"Unknown method: {method}")


def detect_arbitrage(
    prices: dict[str, float],
    fee_rate: float = 0.0
) -> dict:
    """
    Check if a multi-outcome market has an arbitrage opportunity.
    Returns arb details if sum of prices < 1.0 after fees.
    """
    total = sum(prices.values())
    fee_adjusted_total = total * (1 + fee_rate)
    
    if fee_adjusted_total < 1.0:
        profit_per_dollar = 1.0 - fee_adjusted_total
        return {
            "arb_exists": True,
            "raw_sum": total,
            "fee_adjusted_sum": fee_adjusted_total,
            "profit_per_dollar": profit_per_dollar,
            "roi_pct": (profit_per_dollar / fee_adjusted_total) * 100
        }
    
    return {
        "arb_exists": False,
        "raw_sum": total,
        "overround": total - 1.0,
        "overround_pct": (total - 1.0) * 100
    }

What’s Next

This page establishes the foundation: price = probability, and the no-arbitrage condition constrains market prices. Everything else in the series builds on this.