What Kalshi Thinks Will Win the College Football Playoff

kalshi
prediction-markets
college-football

Reading a prediction market’s order book as a probability estimate, and the two ways it lies to you: a one-cent price floor on longshots, and a book that adds up to more than 100%.

Author

Ben Ballard

Published

August 20, 2026

Kalshi runs a market for who wins the 2026 season’s College Football Playoff National Championship: fifty separate contracts, one per team, each paying $1 if that team wins and $0 if it doesn’t. The price of a contract is denominated in cents, and if you squint, a cent is a percentage point — a contract trading at 9¢ is the market saying “9%.”

That’s the pitch for prediction markets: instead of asking an analyst for their gut feeling, you get a number people were willing to bet real money on. First question worth checking, before trusting that number for anything: does it actually behave like a probability?

Pulling the board

Code
import pandas as pd
from sitelib.kalshi import KalshiClient

client = KalshiClient()
markets = client.get_markets(series_ticker="KXNCAAF", status="open")

df = pd.DataFrame(
    {
        "team": m["yes_sub_title"],
        "bid": float(m["yes_bid_dollars"]),
        "ask": float(m["yes_ask_dollars"]),
        "last": float(m["last_price_dollars"]),
        "volume": float(m["volume_fp"]),
        "open_interest": float(m["open_interest_fp"]),
    }
    for m in markets
).sort_values("ask", ascending=False).reset_index(drop=True)

print(f"{len(df)} teams still have a contract on the board")
50 teams still have a contract on the board

Each row is a bid and an ask, same as any order book: the ask is what it costs to bet yes on that team right now, the bid is what someone will pay you to bet yes right now. The gap between them is the cost of trading immediately rather than waiting for a better price — call it the market’s estimate, plus a small tax for wanting an answer this second.

The favorites

Code
import matplotlib.pyplot as plt

top = df.head(10).iloc[::-1]

fig, ax = plt.subplots(figsize=(8, 5))
ax.barh(top["team"], top["ask"] * 100, color="#1f4e79")
ax.set_xlabel("Implied win probability (%)")
ax.spines[["top", "right"]].set_visible(False)
plt.show()
Figure 1: Implied win probability (ask price) for the ten shortest-odds teams in the CFP championship market.

Figure 1 is the market’s answer to “who’s going to win,” priced in real dollars rather than a preseason poll. It’ll be a different bar chart by January — that’s the point of pulling it from a live order book instead of writing down an opinion.

Where the probability story breaks down

Two things in this board don’t behave the way “price equals probability” would suggest.

The price floor. Kalshi won’t quote a contract below 1¢. Look at the bottom of the board:

Code
bottom = df.tail(8)[["team", "bid", "ask", "volume"]]
bottom
team bid ask volume
42 Clemson 0.0 0.01 211823.72
43 California 0.0 0.01 47647.64
44 Baylor 0.0 0.01 19676.03
45 BYU 0.0 0.01 117604.55
46 Auburn 0.0 0.01 145738.31
47 Arizona St. 0.0 0.01 9134.36
48 Arkansas 0.0 0.01 10684.40
49 Arizona 0.0 0.01 14638.93

Every team here is asking 1¢ with a 0¢ bid and little or no volume — not because the market has priced each of them at exactly a 1-in-100 shot, but because a cent is the smallest unit Kalshi trades in and nobody has bothered to trade these at all. A true probability estimate would let a hundred different longshots be a hundred different sizes of unlikely. This board can’t tell you if a team is a 1% shot or a 0.01% shot; both round to the same 1¢ floor.

The book doesn’t sum to 100%. Exactly one of these fifty teams will win, so a coherent set of probabilities should add up to 1.0.

Code
implied_total = df["ask"].sum()
print(f"sum of ask-price implied probabilities: {implied_total:.2f}")
sum of ask-price implied probabilities: 1.43

It doesn’t — it adds up to noticeably more than one. That gap is the same thing as the vig on a sportsbook line: paying the ask on every team simultaneously would cost more than $1 total, guaranteeing a loss no matter who wins. The overround is spread unevenly, too — thin, 1¢-floored longshots contribute more excess probability per team than liquid favorites do, because the floor stops their price from ever reading as low as their real chances.

What I’d check next

Whether the favorites list actually tracks something real — lining this up against a win-total or power-rating source partway through the season, to see whether the market or the model moves first when a team starts losing. And whether the overround shrinks as the season progresses and the field of fifty collapses to a handful of live contenders with real volume behind them.