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:
| Platform | Overround Mechanism | Typical Overround |
|---|---|---|
| Polymarket CLOB | Near-zero spread on liquid markets; 2% fee on net winnings | ~0-1% spread + 2% on profit |
| Kalshi | Built into bid-ask spread | ~2-5% on most markets |
| Traditional sportsbook (-110/-110) | Baked into odds | 4.76% |
| Offshore sportsbook (typical) | Varies by sport and book | 4-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.
- Next in the series: Expected Value for Prediction Market Agents — the decision framework for whether an agent should trade at a given price.
- Deeper on orderbooks: The Prediction Market Microstructure guide covers orderbook depth, spread analysis, and slippage modeling.
- The full API reference: Prediction Market API Reference documents every endpoint for Polymarket and Kalshi side by side.
- For sportsbook math: Sports Betting Math 101 covers odds formats, vig calculation, and the sportsbook-specific probability extraction methods.
- See it in action: The Agent Betting Stack shows how probability extraction fits into the full four-layer agent architecture.
