Prediction markets are emerging as a legitimate alternative to traditional sportsbooks for betting on NBA games. Platforms like Kalshi and Polymarket allow you to buy and sell contracts based on game outcomes, often with different pricing than what you'd find at DraftKings or FanDuel.
This tutorial explains how prediction markets work, shows you how to convert prediction market prices to American odds, and walks through building a Python tool that compares odds across both market types using the BALLDONTLIE API.
If you haven't set up your API key yet, see our Getting Started guide.
What Are Prediction Markets?
Prediction markets are exchanges where participants buy and sell contracts based on the outcome of future events. Unlike traditional sportsbooks where you bet against the house, prediction markets are peer-to-peer: you're trading contracts with other market participants.
How Prediction Market Contracts Work
On platforms like Kalshi and Polymarket, contracts are priced between $0.00 and $1.00. The price directly represents the market's implied probability of that outcome occurring.
For example, if you see a contract for "Lakers to beat Celtics" priced at $0.65:
- The market implies a 65% probability the Lakers win
- You pay $0.65 to buy one contract
- If the Lakers win, your contract pays out $1.00 (profit of $0.35)
- If the Lakers lose, your contract is worth $0.00 (loss of $0.65)
This is fundamentally different from traditional sportsbooks where odds are presented in American format (-150, +200, etc.) and include the house's built-in margin (vig or juice).
Key Prediction Market Platforms
Kalshi is a CFTC-regulated prediction market based in the United States. It offers contracts on sports, politics, economics, and other events. Because it's federally regulated, Kalshi is legal in most US states where sports betting might otherwise be restricted.
Polymarket is a crypto-based prediction market that operates globally. Users trade with USDC (a stablecoin pegged to the US dollar) and can access markets on a wide range of events. Polymarket gained significant attention during recent election cycles for its accurate polling predictions.
Prediction Markets vs Traditional Sportsbooks
| Aspect | Prediction Markets | Traditional Sportsbooks |
|---|---|---|
| Pricing | $0.00 - $1.00 (probability) | American odds (-150, +200) |
| Counterparty | Other traders (peer-to-peer) | The sportsbook (house) |
| Vig/Juice | Spread between buy/sell prices | Built into the odds |
| Regulation | CFTC (Kalshi), Crypto (Polymarket) | State gaming commissions |
| Availability | Broader (Kalshi legal in 40+ states) | Limited to legal betting states |
Converting Prediction Market Prices to American Odds
To compare prediction market contracts with sportsbook lines, you need to convert between probability and American odds formats.
The Conversion Formulas
For favorites (probability >= 50%):
American odds = -(100 × probability) / (1 - probability)
For underdogs (probability < 50%):
American odds = 100 × (1 - probability) / probability
Conversion Examples
| Contract Price | Probability | American Odds | Interpretation |
|---|---|---|---|
| $0.60 | 60% | -150 | Risk $150 to win $100 |
| $0.40 | 40% | +150 | Risk $100 to win $150 |
| $0.75 | 75% | -300 | Risk $300 to win $100 |
| $0.25 | 25% | +300 | Risk $100 to win $300 |
| $0.52 | 52% | -108 | Slight favorite |
| $0.48 | 48% | +108 | Slight underdog |
Let's verify the math for a 60% probability:
American odds = -(100 × 0.60) / (1 - 0.60)
= -60 / 0.40
= -150
And for 40% probability:
American odds = 100 × (1 - 0.40) / 0.40
= 100 × 0.60 / 0.40
= 60 / 0.40
= +150
The Reverse: American Odds to Probability
To convert American odds back to implied probability:
For negative odds (favorites):
Probability = |odds| / (|odds| + 100)
For positive odds (underdogs):
Probability = 100 / (odds + 100)
Building a Prediction Market Comparison Tool
Now let's build a Python script that fetches NBA odds from both prediction markets and traditional sportsbooks, then compares them side by side.
Prerequisites
- Python 3.8+
- A BALLDONTLIE API key (sign up here)
Step 1: Project Setup
Create a new directory and install dependencies:
mkdir nba-prediction-markets
cd nba-prediction-markets
pip install requests tabulate
Step 2: Core Conversion Functions
First, let's implement the conversion functions:
def probability_to_american(probability: float) -> int:
"""
Convert a probability (0-1) to American odds.
Examples:
0.60 -> -150
0.40 -> +150
0.75 -> -300
"""
if probability >= 0.5:
# Favorite: negative odds
return round((-100 * probability) / (1 - probability))
else:
# Underdog: positive odds
return round((100 * (1 - probability)) / probability)
def american_to_probability(odds: int) -> float:
"""
Convert American odds to implied probability.
Examples:
-150 -> 0.60
+150 -> 0.40
-300 -> 0.75
"""
if odds < 0:
return abs(odds) / (abs(odds) + 100)
else:
return 100 / (odds + 100)
Step 3: Fetch NBA Games and Odds
The BALLDONTLIE API returns odds from both prediction markets and sportsbooks in the same endpoint:
import requests
from datetime import date
API_KEY = "your-api-key"
BASE_URL = "https://api.balldontlie.io"
def get_headers():
return {"Authorization": API_KEY}
def fetch_games(target_date: str) -> list:
"""Fetch NBA games for a specific date."""
response = requests.get(
f"{BASE_URL}/nba/v1/games",
headers=get_headers(),
params={"dates[]": target_date}
)
response.raise_for_status()
return response.json()["data"]
def fetch_odds(target_date: str) -> list:
"""Fetch betting odds for a specific date."""
response = requests.get(
f"{BASE_URL}/nba/v2/odds",
headers=get_headers(),
params={"dates[]": target_date}
)
response.raise_for_status()
return response.json()["data"]
Step 4: Separate Prediction Markets from Sportsbooks
The API returns odds with a vendor field. We can use this to categorize the data:
PREDICTION_MARKETS = ["kalshi", "polymarket"]
SPORTSBOOKS = ["draftkings", "fanduel", "caesars", "betmgm", "betrivers"]
# Fetch odds
odds = fetch_odds(date.today().isoformat())
# Separate by type
pm_odds = [o for o in odds if o["vendor"] in PREDICTION_MARKETS]
sb_odds = [o for o in odds if o["vendor"] in SPORTSBOOKS]
Step 5: Compare and Display Results
Here's the complete comparison logic:
from tabulate import tabulate
from typing import Optional
def format_odds(odds: Optional[int]) -> str:
"""Format American odds with +/- prefix."""
if odds is None:
return "-"
return f"+{odds}" if odds >= 0 else str(odds)
def compare_markets_for_game(game: dict, odds_list: list):
"""Compare prediction markets vs sportsbooks for a game."""
home = game["home_team"]["abbreviation"]
away = game["visitor_team"]["abbreviation"]
# Separate by market type
pm_odds = [o for o in odds_list if o["vendor"] in PREDICTION_MARKETS]
sb_odds = [o for o in odds_list if o["vendor"] in SPORTSBOOKS]
print(f"\n{game['visitor_team']['full_name']} @ {game['home_team']['full_name']}")
print("=" * 60)
# Display prediction markets
print("\nPREDICTION MARKETS")
print("-" * 40)
headers = ["Platform", f"{home} ML", "Implied %", f"{away} ML", "Implied %"]
rows = []
for odds in pm_odds:
home_odds = odds.get("moneyline_home_odds")
away_odds = odds.get("moneyline_away_odds")
rows.append([
odds["vendor"].upper(),
format_odds(home_odds),
f"{american_to_probability(home_odds) * 100:.1f}%" if home_odds else "-",
format_odds(away_odds),
f"{american_to_probability(away_odds) * 100:.1f}%" if away_odds else "-"
])
print(tabulate(rows, headers=headers, tablefmt="simple"))
# Display sportsbooks
print("\nTRADITIONAL SPORTSBOOKS")
print("-" * 40)
rows = []
for odds in sb_odds:
home_odds = odds.get("moneyline_home_odds")
away_odds = odds.get("moneyline_away_odds")
rows.append([
odds["vendor"].upper(),
format_odds(home_odds),
f"{american_to_probability(home_odds) * 100:.1f}%" if home_odds else "-",
format_odds(away_odds),
f"{american_to_probability(away_odds) * 100:.1f}%" if away_odds else "-"
])
print(tabulate(rows, headers=headers, tablefmt="simple"))
Example Output
Running this script produces output like:
Philadelphia 76ers @ Memphis Grizzlies
============================================================
PREDICTION MARKETS
----------------------------------------
Platform MEM ML Implied % PHI ML Implied %
---------- -------- ----------- -------- -----------
POLYMARKET +102 49.5% -102 50.5%
KALSHI +102 49.5% -102 50.5%
TRADITIONAL SPORTSBOOKS
----------------------------------------
Sportsbook MEM ML Implied % PHI ML Implied %
------------ -------- ----------- -------- -----------
FANDUEL -104 51.0% -112 52.8%
DRAFTKINGS -105 51.2% -115 53.5%
CAESARS -105 51.2% -115 53.5%
BETRIVERS -103 50.7% -120 54.5%
COMPARISON: BEST AVAILABLE ODDS
----------------------------------------
Team Best Sportsbook Kalshi Polymarket Prob. Diff
------ ----------------- -------- ------------ ------------
MEM -103 (betrivers) +102 +102 +1.2%
PHI -112 (fanduel) -102 -102 +2.3%
Finding Value: Sportsbooks vs Prediction Markets
The comparison reveals interesting discrepancies. In the example above:
- Sportsbooks have Memphis as a slight favorite (-103 to -105)
- Prediction markets have it as a coin flip (+102 for Memphis)
This 1-2% probability difference represents potential value. Sportsbooks include vig in their lines, while prediction markets reflect pure market sentiment.
Why Prediction Markets Sometimes Differ
- Different liquidity pools: Prediction markets may have less volume, leading to less efficient pricing
- Different participant bases: Sportsbooks attract professional bettors; prediction markets attract a broader audience
- No vig structure: Prediction markets don't need to guarantee a profit margin on every market
- Regulatory arbitrage: Prediction markets may be legal where sportsbooks aren't, attracting different bettors
Extending This Further
Here are ideas to build on this foundation:
- Arbitrage alerts: Notify when prediction market prices diverge significantly from sportsbook lines
- Historical tracking: Store snapshots to analyze how markets converge before game time
- Multi-sport comparison: The API includes NFL, NHL, and EPL prediction market odds as well
- Automated trading signals: Build a system that identifies when prediction markets lag sportsbook moves
Check out our AI-assisted development guide to quickly generate these extensions using ChatGPT or Claude.
API Endpoints Used
This tutorial uses the BALLDONTLIE betting odds endpoint:
- GET /nba/v2/odds: Returns odds from both prediction markets and sportsbooks
- Vendors include:
kalshi,polymarket,draftkings,fanduel,caesars,betmgm,betrivers, and more - Filter by date with
dates[]parameter - Returns moneylines, spreads, and totals
- Vendors include:
The same endpoint structure is available for NFL, NHL, EPL, MLB, WNBA, NCAAF, and NCAAB.
Important Notes
The BALLDONTLIE API provides current odds only. We do not store historical betting data. This means the data is ideal for:
- Live comparison between prediction markets and sportsbooks
- Real-time monitoring of price discrepancies
- Building alerts when markets diverge
It is not suitable for historical backtesting of trading strategies.
Next Steps
- Compare player props: Learn to compare player prop odds across sportsbooks
- Line shopping basics: See our guide to finding value across sportsbooks
- Build a scoreboard: Check out our NFL scoreboard tutorial
- Explore the docs: See all available endpoints in our API documentation
Need help? Join our Discord community or browse the full documentation.
Ready to compare prediction markets with sportsbooks? Sign up for a free API key and start building.