Prediction Markets Fundamentals
Prediction markets are exchange-traded markets where participants buy and sell contracts whose payoffs are tied to the outcomes of future events. They function as decentralized forecasting engines, aggregating dispersed information into probability estimates through the price mechanism. ## Key Points - "Will candidate X win the 2028 presidential election?" - "Will GPT-5 be released before July 2026?" - "Will global average temperature exceed 1.5C above pre-industrial levels in 2027?" 1. Buyers submit bids (maximum price they will pay) 2. Sellers submit asks (minimum price they will accept) 3. When a bid meets or exceeds an ask, a trade executes 4. The last trade price becomes the current market price - Prices always sum to 1.0 across all outcomes - The liquidity parameter `b` controls price sensitivity (higher b = more liquidity, less price impact per trade) - Maximum subsidy (loss) the market maker can incur is `b * ln(n)` where n is the number of outcomes - Prices move smoothly and continuously - Blockchain-based (Polygon), uses USDC ## Quick Example ``` Adjusted probability = market_price / (1 - fee_rate) Example: 0.70 / (1 - 0.02) = 0.714 (71.4%) ``` ``` Adjusted probability = market_price * (1 + risk_free_rate * time_to_resolution) ```
skilldb get prediction-skills/prediction-markets-fundamentalsFull skill: 456 linesPrediction Markets Fundamentals
Overview
Prediction markets are exchange-traded markets where participants buy and sell contracts whose payoffs are tied to the outcomes of future events. They function as decentralized forecasting engines, aggregating dispersed information into probability estimates through the price mechanism.
The core insight: market prices for binary outcome contracts directly correspond to the crowd's implied probability of that outcome occurring.
How Prediction Markets Work
The Basic Mechanism
A prediction market creates a contract for a specific, verifiable future event. For example:
- "Will candidate X win the 2028 presidential election?"
- "Will GPT-5 be released before July 2026?"
- "Will global average temperature exceed 1.5C above pre-industrial levels in 2027?"
Each contract pays out a fixed amount (typically $1 or 1 unit) if the event occurs, and $0 if it does not. The current trading price therefore reflects the market's aggregate probability estimate.
If a contract trades at $0.73, the market implies a 73% probability the event will occur.
Order Book Mechanics
Buy Orders (Bids) Sell Orders (Asks)
$0.70 — 500 shares $0.74 — 300 shares
$0.68 — 1200 shares $0.75 — 800 shares
$0.65 — 2000 shares $0.78 — 450 shares
$0.60 — 3500 shares $0.80 — 1500 shares
Spread: $0.04 (between best bid and best ask)
Mid-price: $0.72 (implied probability: 72%)
The bid-ask spread represents the cost of immediacy. Tighter spreads indicate more liquid markets with more reliable probability estimates.
Continuous Double Auction
Most prediction markets use a continuous double auction mechanism:
- Buyers submit bids (maximum price they will pay)
- Sellers submit asks (minimum price they will accept)
- When a bid meets or exceeds an ask, a trade executes
- The last trade price becomes the current market price
class PredictionMarket:
def __init__(self, question: str, resolution_date: str):
self.question = question
self.resolution_date = resolution_date
self.bids = [] # (price, quantity, trader_id)
self.asks = [] # (price, quantity, trader_id)
self.last_price = 0.50 # Start at 50/50
self.trade_history = []
def submit_bid(self, price: float, quantity: int, trader_id: str):
"""Submit a buy order. Price is between 0 and 1."""
assert 0 < price < 1, "Price must be between 0 and 1"
# Check for matching asks
while quantity > 0 and self.asks:
best_ask = min(self.asks, key=lambda x: x[0])
if price >= best_ask[0]:
trade_qty = min(quantity, best_ask[1])
self._execute_trade(best_ask[0], trade_qty, trader_id, best_ask[2])
quantity -= trade_qty
best_ask = (best_ask[0], best_ask[1] - trade_qty, best_ask[2])
if best_ask[1] <= 0:
self.asks.remove(best_ask)
else:
break
if quantity > 0:
self.bids.append((price, quantity, trader_id))
def _execute_trade(self, price, quantity, buyer_id, seller_id):
self.last_price = price
self.trade_history.append({
'price': price,
'quantity': quantity,
'buyer': buyer_id,
'seller': seller_id,
'timestamp': datetime.now()
})
@property
def implied_probability(self):
return self.last_price
Automated Market Makers (AMMs)
Many prediction markets use automated market makers instead of order books, guaranteeing liquidity at all times.
Logarithmic Market Scoring Rule (LMSR)
Invented by Robin Hanson, the LMSR is the most common AMM for prediction markets:
import math
class LMSR:
"""Logarithmic Market Scoring Rule market maker."""
def __init__(self, num_outcomes: int, liquidity: float):
self.num_outcomes = num_outcomes
self.b = liquidity # Liquidity parameter
self.quantities = [0.0] * num_outcomes # Shares outstanding
def cost(self) -> float:
"""Current cost function value."""
return self.b * math.log(
sum(math.exp(q / self.b) for q in self.quantities)
)
def price(self, outcome: int) -> float:
"""Current price (probability) for an outcome."""
exp_values = [math.exp(q / self.b) for q in self.quantities]
return exp_values[outcome] / sum(exp_values)
def cost_to_buy(self, outcome: int, shares: float) -> float:
"""Cost to buy a given number of shares of an outcome."""
old_cost = self.cost()
self.quantities[outcome] += shares
new_cost = self.cost()
self.quantities[outcome] -= shares # Reset
return new_cost - old_cost
def buy(self, outcome: int, shares: float) -> float:
"""Execute a purchase. Returns the cost paid."""
cost = self.cost_to_buy(outcome, shares)
self.quantities[outcome] += shares
return cost
def all_prices(self) -> list:
"""Return prices for all outcomes (should sum to ~1)."""
return [self.price(i) for i in range(self.num_outcomes)]
Key properties of LMSR:
- Prices always sum to 1.0 across all outcomes
- The liquidity parameter
bcontrols price sensitivity (higher b = more liquidity, less price impact per trade) - Maximum subsidy (loss) the market maker can incur is
b * ln(n)where n is the number of outcomes - Prices move smoothly and continuously
Constant Product Market Maker (CPMM)
Used by some DeFi prediction markets:
class CPMM:
"""Constant Product Market Maker for binary outcomes."""
def __init__(self, initial_liquidity: float):
self.yes_reserve = initial_liquidity
self.no_reserve = initial_liquidity
self.k = initial_liquidity ** 2 # Constant product
def price_yes(self) -> float:
return self.no_reserve / (self.yes_reserve + self.no_reserve)
def price_no(self) -> float:
return self.yes_reserve / (self.yes_reserve + self.no_reserve)
def buy_yes(self, amount: float) -> float:
"""Buy YES shares with `amount` collateral. Returns shares received."""
new_yes_reserve = self.k / (self.no_reserve + amount)
shares = self.yes_reserve - new_yes_reserve
self.yes_reserve = new_yes_reserve
self.no_reserve += amount
return shares
Interpreting Market Prices as Probabilities
Direct Interpretation
The simplest interpretation: a contract trading at $X implies an X% probability. But several caveats apply.
Adjustments to Consider
1. Transaction Costs / Fees
If the market charges a 2% fee on winnings, a contract at $0.70 may actually imply a higher probability because traders discount the fee:
Adjusted probability = market_price / (1 - fee_rate)
Example: 0.70 / (1 - 0.02) = 0.714 (71.4%)
2. Time Value of Money
For long-duration contracts, the price includes a discount for capital being locked up:
Adjusted probability = market_price * (1 + risk_free_rate * time_to_resolution)
3. Risk Premium
Markets that correlate with systematic risk carry a risk premium. Events that are bad for traders' portfolios when they occur will trade at prices above true probability.
4. Liquidity Premium
Thin markets with wide spreads have less informative prices. The midpoint of the bid-ask spread is a better estimate than the last trade price.
Probability Extraction Best Practices
def extract_probability(
last_price: float,
bid: float,
ask: float,
fee_rate: float = 0.0,
days_to_resolution: int = 0,
annual_risk_free_rate: float = 0.05
) -> dict:
"""Extract calibrated probability from market data."""
# Use midpoint for thin markets
midpoint = (bid + ask) / 2
spread = ask - bid
# Choose base price
if spread > 0.10: # Wide spread, use midpoint
base_price = midpoint
confidence = "low"
elif spread > 0.05:
base_price = midpoint
confidence = "medium"
else:
base_price = last_price
confidence = "high"
# Adjust for fees
if fee_rate > 0:
base_price = base_price / (1 - fee_rate)
# Adjust for time value
if days_to_resolution > 30:
time_fraction = days_to_resolution / 365
discount = 1 + annual_risk_free_rate * time_fraction
base_price = min(base_price * discount, 0.99)
return {
'implied_probability': round(base_price, 4),
'confidence': confidence,
'spread': spread,
'raw_price': last_price
}
Major Prediction Market Platforms
Polymarket
- Blockchain-based (Polygon), uses USDC
- Binary and categorical markets
- Uses CPMM and order book hybrid
- Largest volume in crypto prediction markets
- Focused on politics, crypto, sports, current events
Metaculus
- Not a real-money market; uses reputation points
- Continuous probability estimates (not binary trading)
- Strong calibration tracking
- Community of skilled forecasters
- Research-oriented, long-term questions
Manifold Markets
- Play-money markets with mana currency
- Very low friction to create markets
- Community-driven market creation
- Good for niche and personal questions
- Calibration data publicly available
Kalshi
- CFTC-regulated US exchange
- Real-money binary options on events
- Focused on economic, political, and climate events
- Order book model
- Legal clarity in the US regulatory framework
PredictIt
- CFTC no-action letter (limited)
- Political event contracts
- $850 position limits
- Academic research orientation
Information Aggregation Theory
The Hayek Hypothesis
Friedrich Hayek argued that markets aggregate dispersed information that no single planner could collect. Prediction markets operationalize this: each trader brings private information and beliefs, and the price reflects the synthesis.
Marginal Trader Hypothesis
Not all traders need to be informed. A small number of informed "marginal traders" can drive prices to accurate levels even if most participants are noise traders. This is why prediction markets can work with relatively few sophisticated participants.
No-Trade Theorem Paradox
In theory, rational traders with common priors should not trade (because an offer to trade reveals information). Prediction markets work because:
- Traders have genuinely different information
- Traders have different priors (beliefs)
- Some traders are motivated by entertainment, hedging, or non-financial reasons
- Noise traders provide liquidity for informed traders
Practical Applications
Corporate Decision Markets
# Example: Using internal prediction markets for product decisions
class CorporateMarket:
"""Internal prediction market for company decisions."""
def __init__(self, question: str, employees: list):
self.question = question
self.market = LMSR(num_outcomes=2, liquidity=1000)
self.positions = {emp: {'yes': 0, 'no': 0} for emp in employees}
self.initial_allocation = 100 # Play money per employee
def get_forecast(self) -> float:
"""Get current probability estimate."""
return self.market.price(0) # Price of YES outcome
def aggregate_department_views(self, department_positions: dict) -> dict:
"""Analyze how different departments are trading."""
return {
dept: {
'avg_position': sum(p['yes'] for p in positions) / len(positions),
'conviction': max(abs(p['yes']) for p in positions)
}
for dept, positions in department_positions.items()
}
Conditional Markets
Conditional markets answer "If X happens, what is the probability of Y?" by creating linked markets:
Market A: "Will policy X be implemented?" — Trading at $0.40
Market B: "Will GDP grow > 3% AND policy X is implemented?" — Trading at $0.25
Market C: "Will GDP grow > 3% AND policy X is NOT implemented?" — Trading at $0.15
P(GDP > 3% | Policy X) = Price_B / Price_A = 0.25 / 0.40 = 62.5%
P(GDP > 3% | No Policy X) = Price_C / (1 - Price_A) = 0.15 / 0.60 = 25%
This reveals the market's estimate of causal impact.
Common Pitfalls
Favorite-Longshot Bias
Markets tend to overprice low-probability events and underprice high-probability events. A contract at $0.05 often implies less than 5% true probability.
Thin Market Bias
Markets with few participants and low volume produce unreliable signals. Always check:
- Daily volume
- Number of unique traders
- Bid-ask spread
- Time since last trade
Resolution Risk
Ambiguity in how a market resolves can distort prices. Well-designed markets have crystal-clear resolution criteria specified in advance.
Manipulation Attempts
While markets generally resist manipulation (informed traders profit by correcting manipulated prices), short-term manipulation is possible in thin markets. The cost of sustained manipulation scales with market liquidity.
Building Your Own Prediction Market
Key Design Decisions
- Market mechanism: Order book vs. AMM vs. parimutuel
- Incentive structure: Real money, play money, or reputation
- Resolution mechanism: Oracle, committee, or automated
- Liquidity provision: Initial subsidy, market maker, or organic
- Regulatory compliance: Jurisdiction-specific requirements
Minimum Viable Implementation
class SimplePredictionMarket:
"""A minimal prediction market for internal use."""
def __init__(self, question: str, resolution_criteria: str):
self.question = question
self.resolution_criteria = resolution_criteria
self.amm = LMSR(num_outcomes=2, liquidity=100)
self.traders = {}
self.created_at = datetime.now()
self.resolved = False
self.outcome = None
def register_trader(self, trader_id: str, balance: float = 100):
self.traders[trader_id] = {
'balance': balance,
'shares_yes': 0,
'shares_no': 0
}
def buy_yes(self, trader_id: str, shares: float):
cost = self.amm.cost_to_buy(0, shares)
if self.traders[trader_id]['balance'] >= cost:
self.amm.buy(0, shares)
self.traders[trader_id]['balance'] -= cost
self.traders[trader_id]['shares_yes'] += shares
return cost
raise ValueError("Insufficient balance")
def current_probability(self) -> float:
return self.amm.price(0)
def resolve(self, outcome: bool):
self.resolved = True
self.outcome = outcome
# Pay out winners
for trader_id, position in self.traders.items():
if outcome:
position['balance'] += position['shares_yes'] * 1.0
else:
position['balance'] += position['shares_no'] * 1.0
Further Reading
- Robin Hanson, "Logarithmic Market Scoring Rules for Modular Combinatorial Information Aggregation" (2003)
- Justin Wolfers and Eric Zitzewitz, "Prediction Markets" (Journal of Economic Perspectives, 2004)
- Philip Tetlock, "Superforecasting: The Art and Science of Prediction" (2015)
- Scott Page, "The Difference: How the Power of Diversity Creates Better Groups" (2007)
Key Takeaways
- Market prices for binary contracts directly encode probability estimates
- Liquidity and volume are critical indicators of price reliability
- LMSR is the gold standard AMM for prediction markets, providing guaranteed liquidity with bounded loss
- Always adjust raw prices for fees, time value, and spreads before interpreting as probabilities
- Conditional markets can reveal causal relationships, not just correlations
- Even play-money markets produce useful forecasts when well-designed
Install this skill directly: skilldb add prediction-skills