> "The best way to predict the future is to create a market for it."
In This Chapter
- 5.1 The Platform Ecosystem Overview
- 5.2 Polymarket — The Crypto-Native Leader
- 5.3 Kalshi — The Regulated Exchange
- 5.4 Metaculus — The Forecasting Platform
- 5.5 Manifold Markets — Play Money Innovation
- 5.6 PredictIt — The Academic Pioneer
- 5.7 Other Notable Platforms
- 5.8 Head-to-Head Comparison
- 5.9 Choosing the Right Platform
- 5.10 API Landscape and Data Access
- 5.11 Building a Multi-Platform Dashboard in Python
- 5.12 Practical Considerations
- 5.13 Chapter Summary
- What's Next
Chapter 5: The Modern Platform Landscape
"The best way to predict the future is to create a market for it." — Adapted from Peter Drucker
In previous chapters, we explored what prediction markets are, why they work, and the mathematical foundations that make them powerful aggregators of information. Now it is time to get concrete. Where do you actually go to trade on beliefs about the future?
The modern prediction market landscape is surprisingly diverse. A crypto-native exchange processing hundreds of millions in volume sits alongside a federally regulated derivatives exchange, which coexists with play-money platforms where anyone can spin up a market in seconds. Some platforms pay you in dollars, others in cryptocurrency, and still others in points that have no monetary value at all — yet somehow still produce remarkably accurate forecasts.
This chapter is your field guide. We will examine every major platform in detail: how they work technically, what makes each one unique, where they excel, and where they fall short. By the end, you will know exactly which platform to use for any given purpose — whether you want to trade for profit, conduct research, practice forecasting, or build applications on top of prediction market data.
5.1 The Platform Ecosystem Overview
The prediction market ecosystem can be organized along two primary axes: monetary type (real money vs. play money) and regulatory framework (regulated vs. unregulated/decentralized). This creates a useful four-quadrant map.
The Four Quadrants
Quadrant 1: Regulated Real-Money Platforms These platforms operate under explicit regulatory approval from bodies like the U.S. Commodity Futures Trading Commission (CFTC). They require KYC (Know Your Customer) verification, comply with financial reporting requirements, and offer the strongest consumer protections.
- Kalshi — CFTC-regulated Designated Contract Market (DCM)
- PredictIt — Operated under a CFTC no-action letter (historically)
Quadrant 2: Crypto-Native Real-Money Platforms These platforms use blockchain technology and cryptocurrency for settlement. They operate outside traditional financial regulation, often through offshore entities or decentralized protocols.
- Polymarket — Largest by volume, built on Polygon
- Augur — Pioneering decentralized protocol on Ethereum
- Gnosis/Omen — Conditional token framework
Quadrant 3: Play-Money Platforms These platforms use virtual currencies with no real-world monetary value. Despite this, they often produce forecasts competitive with real-money markets, thanks to reputation incentives and intrinsic motivation.
- Manifold Markets — Community-driven, anyone can create markets
- Metaculus — Forecasting platform with continuous distributions
Quadrant 4: Adjacent Platforms These are not pure prediction markets but share significant overlap in function.
- Sports betting exchanges (Betfair, FanDuel)
- Corporate internal prediction markets (Google, Microsoft internal tools)
- Forecasting tournaments (Good Judgment Project, IARPA ACE)
Market Map: Platform Positioning
Real Money
|
Kalshi | Polymarket
PredictIt | Augur
| Gnosis/Omen
Regulated ——————————+———————————— Unregulated
|
Corporate | Manifold
Internal | Metaculus
|
Play Money / Points
This map is a simplification — platforms like Metaculus defy easy categorization since they are neither a traditional market nor purely play-money — but it provides a useful mental framework.
Volume and Activity (Approximate, as of late 2025)
| Platform | Monthly Volume | Active Markets | User Base |
|---|---|---|---|
| Polymarket | $500M–$1B+ | 300–500 | ~200K+ |
| Kalshi | $100M–$300M | 200–400 | ~100K+ |
| Metaculus | N/A (points) | 5,000+ | ~50K+ |
| Manifold | N/A (play money) | 10,000+ | ~30K+ |
| PredictIt | Winding down | ~50 | ~80K (peak) |
Note: These figures are approximate and fluctuate significantly. Polymarket volumes spike dramatically around major political events.
5.2 Polymarket — The Crypto-Native Leader
History and Background
Polymarket was founded in 2020 by Shayne Coplan when he was just 22 years old. It launched during the COVID-19 pandemic, initially attracting users who wanted to trade on pandemic-related outcomes. The platform gained massive attention during the 2024 U.S. presidential election cycle, when trading volumes surged past $1 billion per month, making it by far the largest prediction market in history by volume.
In January 2022, Polymarket settled with the CFTC for $1.4 million over offering unregistered binary options to U.S. persons. Following this, the platform officially blocked U.S. users through geofencing, though enforcement of this restriction has been a matter of ongoing discussion.
How It Works: The Conditional Token Framework
Polymarket is built on the Conditional Token Framework (CTF), originally developed by Gnosis. Here is how it works at a technical level:
-
Token Creation: For a binary market (Yes/No), the system creates two complementary tokens. If you deposit $1 of USDC (a stablecoin pegged to the U.S. dollar), you receive one "Yes" token and one "No" token.
-
The Invariant: One Yes token + one No token can always be redeemed for exactly $1 (minus fees). This ensures the market is zero-sum and prices stay anchored to probabilities.
-
Trading: Users trade these tokens on an order book. If you think the probability of an event is higher than the current Yes price, you buy Yes tokens. If lower, you buy No tokens (or sell Yes tokens).
-
Resolution: When the event resolves, the winning token is redeemable for $1, and the losing token becomes worthless.
Deposit $1 USDC
|
v
+--------+--------+
| 1 Yes | 1 No |
| Token | Token |
+--------+--------+
| |
v v
Trade on Trade on
Order Book Order Book
| |
v v
Event Resolves
|
v
Winning token = $1
Losing token = $0
The CLOB via BLOB
Polymarket uses a Central Limit Order Book (CLOB) for matching trades, but with a twist: orders are signed off-chain and matched by an operator, with settlement happening on-chain. This hybrid approach is sometimes called BLOB (bounded/blended limit order book).
This design gives Polymarket the speed and efficiency of a centralized exchange while maintaining the transparency and non-custodial properties of blockchain settlement. Users sign orders with their wallet, and the matching engine pairs compatible orders.
Market Creation
Polymarket markets are created by the Polymarket team and a set of trusted market makers. Unlike some platforms, individual users cannot freely create markets. Each market includes:
- A clearly defined resolution question
- Resolution criteria and source
- An expiration date
- The underlying Conditional Token pair
Interacting with the Polymarket API in Python
Polymarket offers several public endpoints. The two primary APIs are:
- CLOB API — For order book data, trade execution
- Gamma API — For market metadata, historical data
Here is a basic example of fetching market data:
"""
Example: Fetching Polymarket market data using the Gamma API.
The Gamma API provides market metadata, current prices, and
historical information without requiring authentication.
"""
import httpx
import json
from datetime import datetime
# Polymarket Gamma API base URL
GAMMA_API_BASE = "https://gamma-api.polymarket.com"
def fetch_active_markets(limit: int = 10, offset: int = 0) -> list[dict]:
"""
Fetch active markets from Polymarket.
Args:
limit: Number of markets to return (max 100).
offset: Pagination offset.
Returns:
List of market dictionaries.
"""
url = f"{GAMMA_API_BASE}/markets"
params = {
"limit": limit,
"offset": offset,
"active": True,
"closed": False,
}
response = httpx.get(url, params=params, timeout=30.0)
response.raise_for_status()
return response.json()
def fetch_market_by_slug(slug: str) -> dict:
"""
Fetch a specific market by its URL slug.
Args:
slug: The market's URL slug (e.g., 'will-bitcoin-hit-100k-in-2025').
Returns:
Market data dictionary.
"""
url = f"{GAMMA_API_BASE}/markets"
params = {"slug": slug}
response = httpx.get(url, params=params, timeout=30.0)
response.raise_for_status()
markets = response.json()
if markets:
return markets[0]
return {}
def display_market_summary(market: dict) -> None:
"""Print a formatted summary of a market."""
question = market.get("question", "N/A")
# Tokens contain outcome/price information
tokens = market.get("tokens", [])
print(f"Question: {question}")
print(f" Slug: {market.get('slug', 'N/A')}")
print(f" End Date: {market.get('endDate', 'N/A')}")
print(f" Active: {market.get('active', 'N/A')}")
print(f" Volume: ${float(market.get('volume', 0)):,.2f}")
print(f" Liquidity: ${float(market.get('liquidity', 0)):,.2f}")
for token in tokens:
outcome = token.get("outcome", "?")
price = float(token.get("price", 0))
print(f" {outcome}: {price:.1%}")
print()
def main():
print("=== Polymarket Active Markets ===\n")
markets = fetch_active_markets(limit=5)
for market in markets:
display_market_summary(market)
# Demonstrate fetching market time series
print("\n=== Detailed Market Lookup ===\n")
# Fetch a specific market (slug may change — this is illustrative)
specific = fetch_market_by_slug("will-bitcoin-hit-100k-in-2025")
if specific:
display_market_summary(specific)
else:
print("Market not found (slug may have changed).")
if __name__ == "__main__":
main()
Strengths and Weaknesses
Strengths: - Highest liquidity of any prediction market (especially for political and crypto events) - Non-custodial: users control their own wallets - Fast order execution with the hybrid CLOB model - Strong mobile experience - Rich public API for data access - No position limits on most markets
Weaknesses: - Not available to U.S. residents (officially) - Requires cryptocurrency (USDC on Polygon) to participate - Market creation is centralized — users cannot create their own markets - Resolution disputes can be contentious (relies on UMA oracle system) - Regulatory uncertainty remains
5.3 Kalshi — The Regulated Exchange
History and Regulatory Journey
Kalshi was founded in 2018 by Tarek Mansour and Luana Lopes Lara, both MIT graduates. In 2020, Kalshi received approval from the CFTC as a Designated Contract Market (DCM) — the same regulatory designation held by the Chicago Mercantile Exchange (CME). This made Kalshi the first federally regulated exchange dedicated to event contracts in the United States.
The regulatory journey was anything but smooth. Each new contract type Kalshi wanted to offer had to go through a CFTC approval process:
- 2020: Initial DCM approval
- 2021: Launch with weather and economic event contracts
- 2022: Expanded into entertainment, tech events, and more
- 2023–2024: Landmark legal battle over election contracts. Kalshi sued the CFTC after the commission blocked its congressional control contracts. A federal court ruled in Kalshi's favor, allowing election-related event contracts.
- 2024–2025: Rapid expansion into political markets, becoming a major player during election season
How It Works: Event Contracts
Kalshi uses a straightforward binary event contract model:
- Contracts: Each contract pays $1 if the event occurs and $0 if it does not.
- Pricing: Contracts trade between $0.01 and $0.99 (representing 1% to 99% probability).
- Order Book: Kalshi runs a traditional CLOB where buyers and sellers are matched.
- Settlement: Cash settlement in U.S. dollars, directly to your bank account.
Unlike Polymarket's crypto-based system, Kalshi operates entirely in U.S. dollars with standard banking infrastructure.
Market Categories
Kalshi organizes markets into several categories:
- Economics: Fed rate decisions, GDP, inflation, unemployment
- Politics: Elections, legislation, government actions
- Climate/Weather: Temperature records, hurricane activity
- Tech: Product launches, company milestones
- Finance: Stock price thresholds, crypto prices
- Culture/Entertainment: Award shows, TV ratings
Fee Structure
Kalshi's fee structure has evolved over time:
- Trading fee: Typically $0.01 per contract per side (varies by contract)
- No withdrawal fees for standard bank transfers
- No deposit fees for bank transfers
- Exchange fees may apply to certain contract types
Interacting with the Kalshi API in Python
Kalshi provides a well-documented REST API. Accessing market data requires authentication.
"""
Example: Interacting with the Kalshi API.
Kalshi provides a REST API for market data and trading.
Authentication is required for most endpoints.
Public market data can also be accessed via their demo/public endpoints.
"""
import httpx
import json
from datetime import datetime, timezone
# Kalshi API base URLs
KALSHI_API_BASE = "https://api.elections.kalshi.com/trade-api/v2"
KALSHI_DEMO_BASE = "https://demo-api.kalshi.co/trade-api/v2"
class KalshiClient:
"""Simple Kalshi API client for fetching market data."""
def __init__(self, email: str = "", password: str = "", demo: bool = True):
"""
Initialize the Kalshi client.
Args:
email: Kalshi account email.
password: Kalshi account password.
demo: If True, use demo API (no real money).
"""
self.base_url = KALSHI_DEMO_BASE if demo else KALSHI_API_BASE
self.token = None
self.client = httpx.Client(timeout=30.0)
if email and password:
self._login(email, password)
def _login(self, email: str, password: str) -> None:
"""Authenticate and store the access token."""
url = f"{self.base_url}/login"
payload = {"email": email, "password": password}
response = self.client.post(url, json=payload)
response.raise_for_status()
data = response.json()
self.token = data.get("token")
self.client.headers["Authorization"] = f"Bearer {self.token}"
def get_events(self, limit: int = 10, status: str = "open") -> list[dict]:
"""
Fetch events from Kalshi.
Args:
limit: Number of events to return.
status: Filter by status ('open', 'closed', 'settled').
Returns:
List of event dictionaries.
"""
url = f"{self.base_url}/events"
params = {"limit": limit, "status": status}
response = self.client.get(url, params=params)
response.raise_for_status()
data = response.json()
return data.get("events", [])
def get_markets(
self,
event_ticker: str = None,
limit: int = 20,
status: str = "open",
) -> list[dict]:
"""
Fetch markets, optionally filtered by event.
Args:
event_ticker: Filter by parent event ticker.
limit: Number of markets to return.
status: Filter by status.
Returns:
List of market dictionaries.
"""
url = f"{self.base_url}/markets"
params = {"limit": limit, "status": status}
if event_ticker:
params["event_ticker"] = event_ticker
response = self.client.get(url, params=params)
response.raise_for_status()
data = response.json()
return data.get("markets", [])
def get_market(self, ticker: str) -> dict:
"""
Fetch a single market by ticker.
Args:
ticker: The market ticker (e.g., 'INXD-25FEB14-B5450').
Returns:
Market data dictionary.
"""
url = f"{self.base_url}/markets/{ticker}"
response = self.client.get(url)
response.raise_for_status()
return response.json().get("market", {})
def get_market_orderbook(self, ticker: str, depth: int = 10) -> dict:
"""
Fetch the order book for a market.
Args:
ticker: The market ticker.
depth: Number of price levels to return.
Returns:
Order book dictionary with bids and asks.
"""
url = f"{self.base_url}/markets/{ticker}/orderbook"
params = {"depth": depth}
response = self.client.get(url, params=params)
response.raise_for_status()
return response.json().get("orderbook", {})
def display_market(market: dict) -> None:
"""Print a formatted market summary."""
print(f"Ticker: {market.get('ticker', 'N/A')}")
print(f" Title: {market.get('title', 'N/A')}")
print(f" Subtitle: {market.get('subtitle', 'N/A')}")
print(f" Status: {market.get('status', 'N/A')}")
yes_bid = market.get("yes_bid", 0)
yes_ask = market.get("yes_ask", 0)
if yes_bid and yes_ask:
midpoint = (yes_bid + yes_ask) / 2
print(f" Yes Bid: ${yes_bid/100:.2f}")
print(f" Yes Ask: ${yes_ask/100:.2f}")
print(f" Midpoint: {midpoint:.1f}%")
volume = market.get("volume", 0)
print(f" Volume: {volume:,} contracts")
print(f" Open Interest: {market.get('open_interest', 0):,}")
print()
def main():
# Using demo mode — no real credentials needed for illustration
# In practice, you would pass real credentials for the live API
print("=== Kalshi Market Data (Demo) ===\n")
print("Note: This example shows API structure.")
print("You need valid credentials to run against the live API.\n")
# Demonstrate the structure without requiring authentication
# The following shows what the data looks like
sample_market = {
"ticker": "FED-25MAR12-T4.50",
"title": "Fed funds rate",
"subtitle": "Will the Fed cut rates at the March 2025 meeting?",
"status": "open",
"yes_bid": 35,
"yes_ask": 38,
"volume": 152340,
"open_interest": 45200,
}
print("Sample market data structure:\n")
display_market(sample_market)
# To use with real credentials:
# client = KalshiClient(email="you@example.com", password="pass", demo=True)
# events = client.get_events(limit=5)
# for event in events:
# print(event["title"])
# markets = client.get_markets(event_ticker=event["event_ticker"])
# for m in markets:
# display_market(m)
if __name__ == "__main__":
main()
Strengths and Weaknesses
Strengths: - Fully CFTC-regulated — highest level of consumer protection - USD deposits and withdrawals via standard banking - No cryptocurrency required - Clean, professional interface - Growing selection of market categories - Legal for U.S. residents - Robust, well-documented API
Weaknesses: - U.S. only (currently) - Market creation is centralized (Kalshi team only) - Lower liquidity than Polymarket on many markets - Individual position limits on certain contracts - New contract types require regulatory approval, limiting agility - Fee structure can reduce profitability on small trades
5.4 Metaculus — The Forecasting Platform
A Different Paradigm
Metaculus is not a prediction market in the traditional sense — it is a forecasting platform. Instead of buying and selling contracts, users submit probability estimates (forecasts) for questions. There is no order book, no trading, and no real money at stake. Yet Metaculus has become one of the most respected sources of crowdsourced forecasts in the world.
Founded in 2015 by Anthony Aguirre and Greg Laughlin, both physics professors at UC Santa Cruz, Metaculus was designed to advance the science of human judgment and forecasting.
How It Works
Question Types: Metaculus supports several question types:
- Binary Questions: Will event X happen? Users submit a probability between 1% and 99%.
- Continuous Questions: What will the value of X be? Users submit a full probability distribution (using a mixture of logistic distributions).
- Date Questions: When will event X happen? Users submit a probability distribution over dates.
- Conditional Questions: If X happens, what is the probability of Y?
- Group Questions: Collections of related questions.
Aggregation: The "Community Prediction" is not a simple average — Metaculus uses a proprietary aggregation algorithm that weights forecasters by their track records, recency of prediction, and other factors. The exact algorithm is not fully public, but it generally produces predictions that outperform the simple median.
The platform also produces a "Metaculus Prediction," which is an algorithmically generated forecast that tends to outperform the community average.
Scoring System
Metaculus uses several scoring metrics:
Log Score: The primary scoring rule. For a binary question where the outcome is Yes, the log score is:
$$\text{Log Score} = \log_2(p)$$
where $p$ is the probability you assigned to the correct outcome. If you said 90% and the answer was Yes, your log score is $\log_2(0.9) \approx -0.152$. If you said 10% and the answer was Yes, your log score is $\log_2(0.1) \approx -3.322$.
Baseline Score: Metaculus compares your score against a baseline (typically the community median at the time of your prediction). Positive relative scores mean you outperformed the crowd.
Peer Score: A score comparing your prediction to what other forecasters predicted, designed to be more robust and harder to game.
Coverage: The fraction of a question's lifetime during which you had an active prediction. Higher coverage earns more weight.
Track Records and Calibration
One of Metaculus's most valuable features is transparent track records. Every user's calibration curve is visible:
Perfect Calibration (diagonal line):
100% | /
| /
80% | /
| /
60% | /
| /
40% | /
| /
20% | /
| /
0% |/______________________________
0% 20% 40% 60% 80% 100%
Predicted Probability
A well-calibrated forecaster should have their actual resolution rate match their predicted probability: events they predicted at 70% should resolve positively about 70% of the time.
Metaculus vs. Traditional Prediction Markets
| Feature | Prediction Markets | Metaculus |
|---|---|---|
| Incentive | Financial profit | Reputation, points |
| Mechanism | Order book trading | Direct probability submission |
| Output | Price (= probability) | Aggregated distribution |
| Updating | Market dynamics | Individual re-forecasts |
| Sybil resistance | Capital requirement | Account verification, track record |
| Question types | Mostly binary | Binary, continuous, date, conditional |
| Distribution info | Price only | Full probability distributions |
Python API Interaction
"""
Example: Interacting with the Metaculus API.
Metaculus provides a public API for accessing questions,
predictions, and user data.
"""
import httpx
import json
from datetime import datetime
METACULUS_API_BASE = "https://www.metaculus.com/api2"
def fetch_questions(
search: str = "",
limit: int = 10,
offset: int = 0,
status: str = "open",
order_by: str = "-activity",
) -> dict:
"""
Fetch questions from Metaculus.
Args:
search: Search string to filter questions.
limit: Number of questions to return.
offset: Pagination offset.
status: 'open', 'closed', 'resolved', or 'all'.
order_by: Sort order ('-activity', '-publish_time', '-votes', etc.).
Returns:
API response dictionary with 'results' list.
"""
url = f"{METACULUS_API_BASE}/questions/"
params = {
"search": search,
"limit": limit,
"offset": offset,
"status": status,
"order_by": order_by,
}
response = httpx.get(url, params=params, timeout=30.0)
response.raise_for_status()
return response.json()
def fetch_question_detail(question_id: int) -> dict:
"""
Fetch detailed data for a specific question.
Args:
question_id: The numeric question ID.
Returns:
Question data dictionary.
"""
url = f"{METACULUS_API_BASE}/questions/{question_id}/"
response = httpx.get(url, timeout=30.0)
response.raise_for_status()
return response.json()
def display_question(q: dict) -> None:
"""Print a formatted question summary."""
title = q.get("title", "N/A")
q_id = q.get("id", "N/A")
status = q.get("status", "N/A")
# Community prediction
community = q.get("community_prediction", {})
if isinstance(community, dict):
full = community.get("full", {})
if isinstance(full, dict):
q2 = full.get("q2") # Median
else:
q2 = None
else:
q2 = None
forecasters = q.get("number_of_forecasters", 0)
print(f"[{q_id}] {title}")
print(f" Status: {status}")
if q2 is not None:
print(f" Community Median: {q2:.1%}")
print(f" Forecasters: {forecasters}")
print(f" URL: https://www.metaculus.com/questions/{q_id}/")
print()
def main():
print("=== Metaculus Open Questions ===\n")
# Fetch popular open questions
result = fetch_questions(limit=5, order_by="-votes")
questions = result.get("results", [])
for q in questions:
display_question(q)
# Search for specific topics
print("=== AI-Related Questions ===\n")
ai_result = fetch_questions(search="artificial intelligence", limit=5)
for q in ai_result.get("results", []):
display_question(q)
if __name__ == "__main__":
main()
Strengths and Weaknesses
Strengths: - Rich question types including continuous distributions and conditionals - Transparent track records and calibration data - Strong community of skilled forecasters - No money required — low barrier to entry - Excellent for long-term, complex questions - Valuable for research and decision-support - Open API for data access
Weaknesses: - No financial incentives (may reduce participation for some) - Slower to react than real-money markets (no continuous trading) - Community can be insular — new users face a learning curve - Question resolution can be slow or contentious - Cannot express intensity of belief through position sizing (everyone's vote weights similarly, modulo track record) - API rate limits can be restrictive for heavy data users
5.5 Manifold Markets — Play Money Innovation
The Vision: Markets for Everything
Manifold Markets launched in 2022 with a radical premise: What if anyone could create a prediction market about anything? By using play money (called Mana, denoted M$), Manifold removed the regulatory barriers that constrain real-money platforms and created a vibrant, experimental ecosystem.
Founded by Stephen Grugett and James Grugett (brothers) along with Austin Chen, Manifold operates as a social prediction market platform — think of it as the Twitter of forecasting.
How Mana Works
- New users receive a starting balance of Mana (the amount has varied over time, typically M$500–M$1000).
- Mana can be purchased with real money but historically could not be redeemed for cash (this has evolved — Manifold experimented with charity donation redemption and prize points).
- Despite having no direct monetary value, Mana creates meaningful incentives: leaderboards, reputation, and the satisfaction of being right.
- In 2024, Manifold introduced "sweepstakes" markets using a separate "sweepcash" currency that could be redeemed for prizes, partially bridging the gap to real-money prediction.
Market Types
Manifold supports a remarkable variety of market types:
- Binary (Yes/No): Standard binary outcome markets.
- Multiple Choice: Markets with more than two outcomes.
- Free Response: Open-ended markets where users can add new answers.
- Numeric: Markets that resolve to a number within a range.
- Stock-like: Pseudo-stock markets for individuals or concepts.
- Bounty: Not a market — a bounty question where the creator pays Mana for useful answers.
- Polls: Simple polling questions.
Market Mechanism
Manifold uses an Automated Market Maker (AMM) based on the Constant Product (Maniswap) formula, though this has evolved over time. The key properties:
- Markets always have liquidity — you can always buy or sell.
- The price moves along a bonding curve.
- Creators provide initial liquidity when creating a market.
- Limit orders are also supported, creating a hybrid AMM+order-book system.
Unique Features
Anyone Can Create Markets: The defining feature. A user can create a market in under 30 seconds on any topic — "Will my cat knock over the Christmas tree this year?" or "Will GPT-5 be released before July 2025?"
Loans: Manifold provides daily "loans" on outstanding bets, freeing up capital. If you have M$100 bet on a market, Manifold gives you back a portion daily to bet elsewhere. This encourages active participation across many markets.
Comments and Discussion: Each market has a comment thread, creating community discussion around every question.
Groups and Topics: Markets are organized by topic (Politics, AI, Science, Personal, etc.), and users can create custom groups.
Calibration and Track Records: Like Metaculus, Manifold tracks user calibration.
Python API Interaction
"""
Example: Interacting with the Manifold Markets API.
Manifold provides a comprehensive public API.
Most read endpoints require no authentication.
"""
import httpx
import json
from datetime import datetime
MANIFOLD_API_BASE = "https://api.manifold.markets/v0"
def fetch_markets(
limit: int = 10,
sort: str = "liquidity",
order: str = "desc",
) -> list[dict]:
"""
Fetch markets from Manifold.
Args:
limit: Number of markets to return (max 1000).
sort: Sort field ('liquidity', 'created-time', 'updated-time', etc.).
order: Sort order ('asc' or 'desc').
Returns:
List of market dictionaries.
"""
url = f"{MANIFOLD_API_BASE}/search-markets"
params = {
"limit": limit,
"sort": sort,
"order": order,
}
response = httpx.get(url, params=params, timeout=30.0)
response.raise_for_status()
return response.json()
def fetch_market_by_slug(slug: str) -> dict:
"""
Fetch a specific market by its URL slug.
Args:
slug: The market slug (from the URL).
Returns:
Market data dictionary.
"""
url = f"{MANIFOLD_API_BASE}/slug/{slug}"
response = httpx.get(url, timeout=30.0)
response.raise_for_status()
return response.json()
def fetch_user(username: str) -> dict:
"""
Fetch a user profile.
Args:
username: The Manifold username.
Returns:
User data dictionary.
"""
url = f"{MANIFOLD_API_BASE}/user/{username}"
response = httpx.get(url, timeout=30.0)
response.raise_for_status()
return response.json()
def search_markets(query: str, limit: int = 10) -> list[dict]:
"""
Search for markets by text query.
Args:
query: Search string.
limit: Maximum results.
Returns:
List of matching market dictionaries.
"""
url = f"{MANIFOLD_API_BASE}/search-markets"
params = {"term": query, "limit": limit}
response = httpx.get(url, params=params, timeout=30.0)
response.raise_for_status()
return response.json()
def display_market(market: dict) -> None:
"""Print a formatted market summary."""
question = market.get("question", "N/A")
probability = market.get("probability")
total_liquidity = market.get("totalLiquidity", 0)
volume = market.get("volume", 0)
unique_bettors = market.get("uniqueBettorCount", 0)
creator = market.get("creatorUsername", "N/A")
mechanism = market.get("mechanism", "N/A")
print(f"Q: {question}")
if probability is not None:
print(f" Probability: {probability:.1%}")
print(f" Creator: @{creator}")
print(f" Mechanism: {mechanism}")
print(f" Liquidity: M${total_liquidity:,.0f}")
print(f" Volume: M${volume:,.0f}")
print(f" Unique Bettors: {unique_bettors}")
print(f" URL: https://manifold.markets/{market.get('creatorUsername')}/{market.get('slug', '')}")
print()
def main():
print("=== Manifold Markets — Top by Liquidity ===\n")
markets = fetch_markets(limit=5, sort="liquidity", order="desc")
for m in markets:
display_market(m)
print("=== Search: 'AI' ===\n")
ai_markets = search_markets("AI", limit=5)
for m in ai_markets:
display_market(m)
if __name__ == "__main__":
main()
Strengths and Weaknesses
Strengths: - Anyone can create markets — massive breadth of topics - Very low barrier to entry (free to play) - Excellent API, open source codebase - Creative market types (multiple choice, numeric, free response) - Active, engaged community - Fast iteration on features - Great for learning and practice
Weaknesses: - Play money reduces financial incentives (though sweepstakes addresses this partially) - Market quality varies enormously (many poorly specified markets) - Mana inflation and economic design challenges - Lower accuracy than real-money markets on high-stakes questions - Resolution disputes are common on community-created markets - Some markets are jokes or personal (not useful for serious forecasting)
5.6 PredictIt — The Academic Pioneer
The No-Action Letter
PredictIt holds a unique place in prediction market history. Launched in 2014 by Victoria University of Wellington (New Zealand), it operated in the United States under a CFTC no-action letter — essentially a promise from the regulator not to take enforcement action, contingent on several conditions:
- The platform must be operated by a university for academic research purposes.
- No market may have more than 850 traders.
- No trader may invest more than $850 in any single market.
- The platform must share data with academic researchers.
This was the first time a prediction market could legally operate in the U.S. with real money (outside of the Iowa Electronic Markets, which had a similar academic exemption).
Fee Structure
PredictIt's fees were notably high:
- 10% profit fee: PredictIt took 10% of any profits on a market.
- 5% withdrawal fee: An additional 5% fee on all withdrawals.
- No deposit fees.
These fees meant a trader needed a significant edge to be profitable. A contract priced at 50 cents with a true probability of 60% — normally a very attractive bet — would barely break even after PredictIt's fees.
The 850-Trader Limit Problem
The 850-trader limit created severe distortions:
- Popular markets would fill up almost instantly.
- Locked-out traders created artificial demand with no way to enter.
- Traders who got in early could hold positions hostage.
- It limited the information aggregation properties that make prediction markets valuable.
Regulatory Challenges and 2023 Status
In August 2022, the CFTC announced it would withdraw PredictIt's no-action letter, effective February 2023. After legal challenges, PredictIt was given limited extensions to wind down existing markets, but was prohibited from creating new ones.
As of late 2023 and into 2024, PredictIt was in a protracted wind-down phase. Several legal challenges were mounted, and the platform's ultimate fate remained uncertain. Victoria University and PredictIt's operators argued the CFTC's withdrawal was arbitrary and capricious.
Regardless of its operational status, PredictIt's legacy is significant: it proved that real-money prediction markets could operate in the U.S. regulatory environment and generated a wealth of academic research.
Historical Importance
PredictIt was instrumental in:
- Demonstrating demand: Millions of dollars traded on political outcomes proved there was a real market.
- Academic research: Dozens of published papers used PredictIt data.
- Regulatory precedent: The no-action letter model (and its limitations) informed subsequent regulatory approaches.
- Popularizing prediction markets: PredictIt was the first real-money prediction market many Americans encountered.
- Paving the way for Kalshi: Kalshi's founders have acknowledged that PredictIt demonstrated the market existed.
5.7 Other Notable Platforms
Augur
Augur was the first major decentralized prediction market protocol, launched on Ethereum in 2018 after a 2015 ICO that raised $5.3 million. Augur's key innovation was fully decentralized market creation and resolution using the REP token for dispute resolution.
However, Augur suffered from poor UX, high Ethereum gas fees, and low liquidity. Augur v2 launched in 2020 with improvements but never achieved mainstream adoption. Augur's ideas heavily influenced subsequent projects, including Polymarket.
Gnosis and Omen
Gnosis developed the Conditional Token Framework — the technical standard that Polymarket and others build upon. The Omen prediction market, powered by Gnosis, provided a decentralized interface for trading conditional tokens.
Gnosis has since pivoted to focus on its Gnosis Chain (formerly xDai) and the Gnosis Safe (now Safe) multi-signature wallet, but its conditional token framework remains one of the most important technical contributions to the prediction market ecosystem.
Insight Prediction
Insight Prediction is a smaller crypto-native platform that has carved out a niche with competitive fees and markets focused on geopolitics, conflict, and international events — topics that larger platforms sometimes shy away from.
Sports Betting Platforms as Prediction Markets
Platforms like Betfair Exchange function as prediction markets in all but name. Betfair's exchange model — where users bet against each other rather than against the house — is mechanically identical to a prediction market order book.
Key differences from dedicated prediction markets: - Focus exclusively on sports and racing events - Highly liquid (Betfair processes billions annually) - Regulated as gambling, not financial instruments - Sophisticated API and data infrastructure - Odds formats differ (decimal, fractional) but are convertible to probabilities
Corporate Internal Prediction Markets
Several major technology companies have operated internal prediction markets:
- Google: Ran internal prediction markets for product launch dates, quarterly metrics, and strategic decisions. Research published by Bo Cowgill showed these markets were well-calibrated.
- Microsoft: Used internal markets for project timeline predictions.
- Ford Motor Company: Experimented with internal prediction markets for quality control.
- Intel: Used prediction markets for forecasting chip yields.
These internal markets typically use play money and are designed to surface information that might not flow through normal management channels.
5.8 Head-to-Head Comparison
The following table provides a detailed comparison across the major platforms:
| Feature | Polymarket | Kalshi | Metaculus | Manifold | PredictIt |
|---|---|---|---|---|---|
| Type | Real money (crypto) | Real money (USD) | Points/reputation | Play money (Mana) | Real money (USD) |
| Founded | 2020 | 2018 (launched 2021) | 2015 | 2022 | 2014 |
| Regulation | Offshore/unregulated | CFTC-regulated DCM | N/A | N/A | CFTC no-action letter |
| Geography | Global (excl. U.S. officially) | U.S. only | Global | Global | U.S. only |
| Market Mechanism | CLOB (hybrid on/off-chain) | CLOB | Aggregated forecasts | AMM + limit orders | CLOB |
| Market Creation | Centralized (Polymarket team) | Centralized (Kalshi team) | Centralized (community nominations) | Open (anyone) | Centralized |
| Contract Type | Conditional tokens (USDC) | Binary event contracts | Probability estimates | Mana-denominated shares | Binary shares |
| Deposit Method | Crypto (USDC on Polygon) | Bank transfer, debit card | N/A | Credit card (for Mana purchase) | Bank transfer, credit card |
| Trading Fees | ~1-2% (taker) | ~$0.01/contract/side | N/A | Built into AMM spread | N/A |
| Withdrawal Fees | Gas fees | Free | N/A | N/A | 5% |
| Profit Fees | None | None | N/A | N/A | 10% |
| Position Limits | Generally none | Varies by contract | N/A | None | $850/market |
| Trader Limits | None | None | None | None | 850/market |
| API Quality | Good (Gamma + CLOB) | Good (REST) | Good (REST) | Excellent (REST) | Basic (REST) |
| Open Source | Partial | No | Partial | Yes (fully) | No |
| Typical Liquidity | Very high (political) | Medium-high | N/A | Low-medium | Low |
| Mobile App | Yes | Yes | Yes | Yes (web) | Yes |
| Resolution | UMA oracle | Kalshi team | Metaculus team | Market creator | PredictIt team |
Fee Impact Analysis
Consider a simple trade: buying a Yes contract at $0.60 that resolves to $1.00 (a $0.40 profit per contract).
| Platform | Gross Profit | Fees | Net Profit | Effective Fee Rate |
|---|---|---|---|---|
| Polymarket | $0.40 | ~$0.01 (taker fee) | ~$0.39 | ~2.5% | |
| Kalshi | $0.40 | ~$0.02 (buy + sell) | ~$0.38 | ~5% | |
| PredictIt | $0.40 | $0.04 (10% profit) + $0.018 (5% withdrawal) | ~$0.34 | ~15% |
PredictIt's fee structure was notably punishing, especially the combination of profit and withdrawal fees.
5.9 Choosing the Right Platform
Your ideal platform depends on your goals. Here is a decision framework:
Goal: Trading for Profit
Best choice: Polymarket (if non-U.S.) or Kalshi (if U.S.)
Rationale: - Real money creates real incentives and real rewards. - Polymarket offers the highest liquidity, making it easier to enter and exit positions. - Kalshi provides the safest regulatory environment for U.S. traders. - Both have APIs suitable for algorithmic trading.
Goal: Research and Data Analysis
Best choice: Metaculus or Manifold
Rationale: - Both offer excellent public APIs with rich data. - Metaculus provides continuous distributions, not just point estimates. - Manifold is fully open source — you can analyze the entire codebase. - Historical data is freely available from both. - Polymarket also has good data APIs for real-money market analysis.
Goal: Forecasting Practice
Best choice: Metaculus (for serious forecasting) or Manifold (for casual practice)
Rationale: - Metaculus has the best scoring system and calibration tools. - The Metaculus community is focused on accuracy and improvement. - Manifold offers more variety and social engagement. - Both are free to use.
Goal: Building Applications
Best choice: Manifold (fully open source) or Polymarket (best data APIs)
Rationale: - Manifold's entire codebase is open source on GitHub. - Manifold's API has the fewest restrictions. - Polymarket's APIs are well-suited for data applications. - Kalshi's API is excellent but more restricted.
Goal: Understanding Market Microstructure
Best choice: Start with Manifold (risk-free), then move to Polymarket or Kalshi
Rationale: - Manifold lets you experiment with trading strategies using play money. - You can observe how order books and AMMs work without financial risk. - Once comfortable, real-money platforms provide authentic market dynamics.
5.10 API Landscape and Data Access
Each platform offers different levels of API access. Here is a comprehensive overview:
Polymarket APIs
Gamma API (Market Data):
- Base URL: https://gamma-api.polymarket.com
- Authentication: None required for public data
- Rate limits: Moderate (undocumented, but approximately 60 requests/minute)
- Key endpoints:
- GET /markets — List markets with filtering
- GET /markets/{id} — Single market detail
- GET /events — Events (groups of related markets)
CLOB API (Trading):
- Base URL: https://clob.polymarket.com
- Authentication: Wallet signature (EIP-712)
- Key endpoints:
- GET /book — Order book for a token
- GET /price — Current price for a token
- POST /order — Place an order (authenticated)
Kalshi API
- Base URL:
https://api.elections.kalshi.com/trade-api/v2 - Authentication: Email/password login, returns JWT token
- Rate limits: 10 requests/second
- Key endpoints:
GET /events— List eventsGET /markets— List marketsGET /markets/{ticker}— Market detailsGET /markets/{ticker}/orderbook— Order bookGET /markets/{ticker}/history— Price historyPOST /portfolio/orders— Place order (authenticated)- Documentation: Comprehensive Swagger/OpenAPI docs available
Metaculus API
- Base URL:
https://www.metaculus.com/api2 - Authentication: Optional (token-based for write operations)
- Rate limits: Relatively restrictive (varies)
- Key endpoints:
GET /questions/— List questions with search/filterGET /questions/{id}/— Question detailGET /questions/{id}/predictions/— Prediction historyPOST /questions/{id}/predict/— Submit prediction (authenticated)
Manifold API
- Base URL:
https://api.manifold.markets/v0 - Authentication: API key (optional for read, required for write)
- Rate limits: 100 requests/minute (read), 10/minute (write)
- Key endpoints:
GET /markets— List all marketsGET /search-markets— Search marketsGET /slug/{slug}— Market by slugGET /market/{id}— Market by IDGET /market/{id}/positions— Positions on a marketGET /user/{username}— User profilePOST /bet— Place a bet (authenticated)POST /market— Create a market (authenticated)- Documentation: Well-maintained, with TypeScript type definitions
Comparison of API Capabilities
| Capability | Polymarket | Kalshi | Metaculus | Manifold |
|---|---|---|---|---|
| Public market data | Yes | Yes | Yes | Yes |
| Historical prices | Yes | Yes | Partial | Yes |
| Order book data | Yes | Yes | N/A | N/A (AMM) |
| Place trades | Yes (wallet) | Yes (JWT) | Yes (predict) | Yes (API key) |
| Create markets | No | No | No | Yes |
| User profiles | Limited | Limited | Yes | Yes |
| WebSocket/streaming | Yes | Yes | No | No |
| Bulk data export | Limited | Limited | Yes (datasets) | Yes (via Supabase) |
5.11 Building a Multi-Platform Dashboard in Python
Let us build a practical tool that fetches data from multiple platforms and presents it in a unified view. This demonstrates how to work across APIs and normalize data from different sources.
"""
Multi-Platform Prediction Market Dashboard
Fetches data from Polymarket, Kalshi, Metaculus, and Manifold,
then presents a unified view for comparison.
Usage:
python multi_platform_dashboard.py
Requirements:
pip install httpx tabulate
"""
import httpx
from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional
@dataclass
class NormalizedMarket:
"""A market normalized across platforms for comparison."""
platform: str
question: str
probability: Optional[float]
volume: Optional[float]
num_traders: Optional[int]
url: str
close_date: Optional[str] = None
category: str = ""
raw_data: dict = field(default_factory=dict, repr=False)
class PolymarketFetcher:
"""Fetch and normalize Polymarket data."""
BASE_URL = "https://gamma-api.polymarket.com"
def __init__(self):
self.client = httpx.Client(timeout=30.0)
def fetch_markets(self, limit: int = 20) -> list[NormalizedMarket]:
url = f"{self.BASE_URL}/markets"
params = {"limit": limit, "active": True, "closed": False}
try:
response = self.client.get(url, params=params)
response.raise_for_status()
raw_markets = response.json()
except (httpx.HTTPError, Exception) as e:
print(f" [Polymarket] Error: {e}")
return []
markets = []
for m in raw_markets:
tokens = m.get("tokens", [])
prob = None
for t in tokens:
if t.get("outcome", "").lower() == "yes":
try:
prob = float(t.get("price", 0))
except (ValueError, TypeError):
pass
nm = NormalizedMarket(
platform="Polymarket",
question=m.get("question", "N/A"),
probability=prob,
volume=float(m.get("volume", 0)) if m.get("volume") else None,
num_traders=None,
url=f"https://polymarket.com/event/{m.get('slug', '')}",
close_date=m.get("endDate"),
raw_data=m,
)
markets.append(nm)
return markets
def search(self, query: str, limit: int = 10) -> list[NormalizedMarket]:
url = f"{self.BASE_URL}/markets"
params = {"limit": limit, "active": True, "closed": False}
try:
response = self.client.get(url, params=params)
response.raise_for_status()
raw_markets = response.json()
except (httpx.HTTPError, Exception) as e:
print(f" [Polymarket] Search error: {e}")
return []
# Client-side filter (Gamma API has limited search)
query_lower = query.lower()
filtered = [
m for m in raw_markets
if query_lower in m.get("question", "").lower()
]
return self._normalize_list(filtered)
def _normalize_list(self, raw_markets: list) -> list[NormalizedMarket]:
markets = []
for m in raw_markets:
tokens = m.get("tokens", [])
prob = None
for t in tokens:
if t.get("outcome", "").lower() == "yes":
try:
prob = float(t.get("price", 0))
except (ValueError, TypeError):
pass
nm = NormalizedMarket(
platform="Polymarket",
question=m.get("question", "N/A"),
probability=prob,
volume=float(m.get("volume", 0)) if m.get("volume") else None,
num_traders=None,
url=f"https://polymarket.com/event/{m.get('slug', '')}",
close_date=m.get("endDate"),
raw_data=m,
)
markets.append(nm)
return markets
class MetaculusFetcher:
"""Fetch and normalize Metaculus data."""
BASE_URL = "https://www.metaculus.com/api2"
def __init__(self):
self.client = httpx.Client(timeout=30.0)
def fetch_questions(self, limit: int = 20) -> list[NormalizedMarket]:
url = f"{self.BASE_URL}/questions/"
params = {
"limit": limit,
"status": "open",
"order_by": "-activity",
"type": "forecast",
}
try:
response = self.client.get(url, params=params)
response.raise_for_status()
data = response.json()
except (httpx.HTTPError, Exception) as e:
print(f" [Metaculus] Error: {e}")
return []
markets = []
for q in data.get("results", []):
prob = self._extract_probability(q)
q_id = q.get("id", "")
nm = NormalizedMarket(
platform="Metaculus",
question=q.get("title", "N/A"),
probability=prob,
volume=None,
num_traders=q.get("number_of_forecasters"),
url=f"https://www.metaculus.com/questions/{q_id}/",
close_date=q.get("close_time"),
raw_data=q,
)
markets.append(nm)
return markets
def search(self, query: str, limit: int = 10) -> list[NormalizedMarket]:
url = f"{self.BASE_URL}/questions/"
params = {
"search": query,
"limit": limit,
"status": "open",
}
try:
response = self.client.get(url, params=params)
response.raise_for_status()
data = response.json()
except (httpx.HTTPError, Exception) as e:
print(f" [Metaculus] Search error: {e}")
return []
markets = []
for q in data.get("results", []):
prob = self._extract_probability(q)
q_id = q.get("id", "")
nm = NormalizedMarket(
platform="Metaculus",
question=q.get("title", "N/A"),
probability=prob,
volume=None,
num_traders=q.get("number_of_forecasters"),
url=f"https://www.metaculus.com/questions/{q_id}/",
close_date=q.get("close_time"),
raw_data=q,
)
markets.append(nm)
return markets
@staticmethod
def _extract_probability(q: dict) -> Optional[float]:
community = q.get("community_prediction", {})
if isinstance(community, dict):
full = community.get("full", {})
if isinstance(full, dict):
return full.get("q2")
return None
class ManifoldFetcher:
"""Fetch and normalize Manifold Markets data."""
BASE_URL = "https://api.manifold.markets/v0"
def __init__(self):
self.client = httpx.Client(timeout=30.0)
def fetch_markets(self, limit: int = 20) -> list[NormalizedMarket]:
url = f"{self.BASE_URL}/search-markets"
params = {"limit": limit, "sort": "liquidity", "order": "desc"}
try:
response = self.client.get(url, params=params)
response.raise_for_status()
raw_markets = response.json()
except (httpx.HTTPError, Exception) as e:
print(f" [Manifold] Error: {e}")
return []
return self._normalize_list(raw_markets)
def search(self, query: str, limit: int = 10) -> list[NormalizedMarket]:
url = f"{self.BASE_URL}/search-markets"
params = {"term": query, "limit": limit}
try:
response = self.client.get(url, params=params)
response.raise_for_status()
raw_markets = response.json()
except (httpx.HTTPError, Exception) as e:
print(f" [Manifold] Search error: {e}")
return []
return self._normalize_list(raw_markets)
def _normalize_list(self, raw_markets: list) -> list[NormalizedMarket]:
markets = []
for m in raw_markets:
creator = m.get("creatorUsername", "")
slug = m.get("slug", "")
nm = NormalizedMarket(
platform="Manifold",
question=m.get("question", "N/A"),
probability=m.get("probability"),
volume=m.get("volume"),
num_traders=m.get("uniqueBettorCount"),
url=f"https://manifold.markets/{creator}/{slug}",
close_date=None,
raw_data=m,
)
markets.append(nm)
return markets
class MultiPlatformDashboard:
"""Aggregates data from multiple prediction market platforms."""
def __init__(self):
self.polymarket = PolymarketFetcher()
self.metaculus = MetaculusFetcher()
self.manifold = ManifoldFetcher()
def fetch_all_top_markets(self, limit_per_platform: int = 10):
"""Fetch top markets from all platforms."""
print("Fetching from all platforms...\n")
all_markets = []
print(" Fetching Polymarket...")
all_markets.extend(self.polymarket.fetch_markets(limit_per_platform))
print(" Fetching Metaculus...")
all_markets.extend(self.metaculus.fetch_questions(limit_per_platform))
print(" Fetching Manifold...")
all_markets.extend(self.manifold.fetch_markets(limit_per_platform))
return all_markets
def search_across_platforms(self, query: str, limit: int = 5):
"""Search for a topic across all platforms."""
print(f"Searching for '{query}' across platforms...\n")
results = {}
print(" Searching Polymarket...")
results["Polymarket"] = self.polymarket.search(query, limit)
print(" Searching Metaculus...")
results["Metaculus"] = self.metaculus.search(query, limit)
print(" Searching Manifold...")
results["Manifold"] = self.manifold.search(query, limit)
return results
def display_search_results(self, results: dict):
"""Display cross-platform search results."""
for platform, markets in results.items():
print(f"\n{'='*60}")
print(f" {platform} ({len(markets)} results)")
print(f"{'='*60}")
if not markets:
print(" No results found.")
continue
for m in markets:
prob_str = f"{m.probability:.1%}" if m.probability else "N/A"
print(f"\n Q: {m.question}")
print(f" Prob: {prob_str}")
if m.volume:
print(f" Volume: ${m.volume:,.0f}")
if m.num_traders:
print(f" Traders/Forecasters: {m.num_traders}")
def display_dashboard(self, markets: list[NormalizedMarket]):
"""Display a unified dashboard of markets."""
try:
from tabulate import tabulate
use_tabulate = True
except ImportError:
use_tabulate = False
print(f"\n{'='*80}")
print(" MULTI-PLATFORM PREDICTION MARKET DASHBOARD")
print(f" Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f" Total markets: {len(markets)}")
print(f"{'='*80}\n")
if use_tabulate:
rows = []
for m in markets:
prob_str = f"{m.probability:.1%}" if m.probability else "N/A"
vol_str = f"${m.volume:,.0f}" if m.volume else "N/A"
question = m.question[:60] + "..." if len(m.question) > 60 else m.question
rows.append([
m.platform,
question,
prob_str,
vol_str,
])
headers = ["Platform", "Question", "Prob", "Volume"]
print(tabulate(rows, headers=headers, tablefmt="simple"))
else:
for m in markets:
prob_str = f"{m.probability:.1%}" if m.probability else "N/A"
vol_str = f"${m.volume:,.0f}" if m.volume else "N/A"
print(f"[{m.platform:12s}] {prob_str:>6s} | {m.question[:65]}")
def main():
dashboard = MultiPlatformDashboard()
# 1. Fetch top markets from all platforms
all_markets = dashboard.fetch_all_top_markets(limit_per_platform=5)
dashboard.display_dashboard(all_markets)
# 2. Cross-platform search
print("\n\n")
results = dashboard.search_across_platforms("AI", limit=3)
dashboard.display_search_results(results)
if __name__ == "__main__":
main()
This dashboard is a starting point. In a production setting, you would add caching, error handling, persistent storage, and a web frontend.
5.12 Practical Considerations
Before you choose a platform and start trading or forecasting, consider these practical factors:
Regulatory Risk
The regulatory landscape for prediction markets is evolving rapidly. Consider:
- Polymarket: Settled with the CFTC in 2022. Officially unavailable to U.S. users, but enforcement has been inconsistent. Regulatory risk for U.S.-based users remains significant.
- Kalshi: As a CFTC-regulated DCM, Kalshi has the most solid regulatory footing. However, new contract types still face regulatory challenges.
- Manifold/Metaculus: As play-money platforms, they face minimal regulatory risk.
- General trend: Regulatory clarity is improving, with courts and regulators increasingly recognizing prediction markets as legitimate.
Counterparty Risk
Who holds your money, and what happens if they fail?
- Polymarket: Non-custodial — your funds are in your own wallet. Smart contract risk exists but counterparty risk is minimal.
- Kalshi: Custodial — Kalshi holds your funds. As a regulated entity, customer funds should be segregated, but the risk is non-zero.
- PredictIt: Custodial, and the wind-down process illustrated the risks: some users had difficulty withdrawing funds.
- Manifold/Metaculus: No real money at risk.
Liquidity Fragmentation
The same event might be traded on multiple platforms with different prices. This creates challenges:
- Price discrepancies: A market might show 62% on Polymarket and 58% on Kalshi. Which is right?
- Arbitrage difficulty: Moving money between platforms is slow and costly, making cross-platform arbitrage impractical for most users.
- Information siloing: Each platform's market reflects only its user base's information.
Platform Lock-In
Consider how easy it is to leave a platform:
- Polymarket: Non-custodial, so exit is straightforward (just sell your positions and withdraw USDC).
- Kalshi: Standard withdrawal process to bank account.
- Data portability: Can you export your forecasting history? Metaculus and Manifold offer good data portability. Others vary.
Tax Implications
Prediction market profits may be taxable. In the U.S.:
- Kalshi: Issues 1099 forms for profits. Treated as regulated futures or event contracts.
- Polymarket: Crypto taxation rules apply. Users are responsible for self-reporting.
- PredictIt: Historically issued 1099-MISC for net profits.
- Play money: No tax implications (no real money changes hands).
Always consult a tax professional. This is not tax advice.
5.13 Chapter Summary
The prediction market landscape in 2025 is more diverse and accessible than at any point in history. Let us recap the major players:
Polymarket dominates by volume, offering the deepest liquidity in a crypto-native, non-custodial format. It is the platform of choice for serious traders outside the U.S. Its hybrid CLOB model and Conditional Token Framework make it technically sophisticated.
Kalshi provides the strongest regulatory protections as a CFTC-regulated exchange. It is the go-to platform for U.S.-based traders who want real-money exposure to event outcomes. Its regulatory journey has been groundbreaking.
Metaculus stands apart as a forecasting platform rather than a market. Its support for continuous distributions, rigorous scoring systems, and transparent track records make it the best platform for serious forecasting practice and research.
Manifold Markets democratizes prediction markets by letting anyone create a market on any topic. Its play-money model and open-source codebase make it ideal for learning, experimentation, and building applications.
PredictIt pioneered the modern era of U.S. prediction markets. While it is winding down, its legacy — in proving demand, generating research, and shaping regulation — is immense.
Each platform occupies a distinct niche, and the "best" platform depends entirely on your goals. Traders seek Polymarket and Kalshi. Researchers gravitate toward Metaculus. Builders love Manifold. And increasingly, sophisticated users maintain accounts on multiple platforms to take advantage of each one's strengths.
The APIs provided by these platforms open up exciting possibilities for data analysis, algorithmic trading, and building new tools on top of prediction market data. In the chapters ahead, we will use these APIs extensively as we explore trading strategies, calibration techniques, and advanced applications.
What's Next
In Chapter 6, we will explore Market Mechanics and Order Types — how orders are actually matched, what different order types mean, and how market microstructure affects your trading. We will build on the platform knowledge from this chapter with hands-on examples of placing orders, managing positions, and understanding the order book.
Chapter 5 of "Learning Prediction Markets — From Concepts to Strategies"