Why Kalshi Takers Lose Money (72M Trades Analyzed)
So recently, I was scrolling through Hacker News and saw this post entitled The Microstructure of Wealth Transfer in Prediction Markets. This title caught my eye. I was intrigued. The post is by Jon Becker, a software engineer at Coinbase, where I also briefly worked many years ago.
He analyzed over 72 million trades on Kalshi and showed mathematically how many retail traders are losing money in prediction markets due to well known biases that have been studied for decades. He also open sourced a Github repository complete with Python scripts and historical Kalshi trade data that you can use to perform your own analysis.
In this tutorial, I'm going to discuss the key findings from his post, and also set the stage for some follow up tutorials where we write some code to analyze Kalshi data and make some trades.
Longshot Bias
The first key point is that Kalshi bettors tend to overvalue longshots and undervalue favorites. He references a 1988 paper about horserace betting, Anomalies, by Thaler and Ziemba. The authors describe the longshot bias as an anomaly where bettors systematically overbet on horses that have a low probability of winning on favorites. They conclude that this behavior drives the expected return on longshots significantly lower than that of favorites. Bettors are willing to accept poor average returns in exchange for the "lottery ticket" potential of a massive payout.
Even though this paper was written in 1988 and is about horse racing, this makes even more sense when you apply it to the current market environment. Think about it. The WallStreetBets crowd loves to buy deep out of the money call options that expire tomorrow. The so called YOLO bet is popular because people want to show off the big 20 bagger gain porn. Do most of these YOLO bets win? Absolutely not.
Likewise, in sports, which is the #1 category for traders on Kalshi, it is common to bet on your favorite team to win it all, however unlikely that may be. I'm even guilty of this. I was born in the Houston area, so of course before the NBA season started I bought 7 cent contracts for the Houston Rockets to win the NBA Championship. The $40 bet would pay $600 if it hit, and I could show off to everyone on the internet that I was the one who called it.

Unfortunately those 7 cent contracts are now worth 4 cents, and I've lost nearly half of my money. If I wanted to get even more emotional with my betting, I would double down. Hey, the contract is even cheaper now! But perhaps the smarter bet, according to this paper, would have been to take the other side of the bet at the beginning of the season.
Becker actually looked at historical trades on Kalshi, 72 million of them. What he found is that contracts that were priced at 5 cents only won ~4% of the time. This means if you are repeatedly betting on these longshots, the math says you are going to lose in the long run, even if you may have hit one before.
With Becker's Github repository, you can run this analysis yourself by cloning the repository, installing the dependencies, and running:
make analyze win_rate_by_price If you want to just show the math on 5 cent contracts, you can run this script:
#!/usr/bin/env python3
from pathlib import Path
import duckdb
def main():
base_dir = Path(__file__).parent.parent.parent
trades_dir = base_dir / "data" / "trades"
markets_dir = base_dir / "data" / "markets"
con = duckdb.connect()
print("\nAnalyzing ALL 5-cent positions (Makers + Takers)")
df = con.execute(f"""
WITH resolved_markets AS (
SELECT ticker, result
FROM '{markets_dir}/*.parquet'
WHERE status = 'finalized'
AND result IN ('yes', 'no')
AND volume > 100
),
all_positions AS (
SELECT
CASE WHEN t.taker_side = 'yes' THEN t.yes_price ELSE t.no_price END as price,
CASE WHEN t.taker_side = m.result THEN 1 ELSE 0 END as won
FROM '{trades_dir}/*.parquet' t
JOIN resolved_markets m ON t.ticker = m.ticker
UNION ALL
SELECT
CASE WHEN t.taker_side = 'yes' THEN t.no_price ELSE t.yes_price END as price,
CASE WHEN t.taker_side != m.result THEN 1 ELSE 0 END as won
FROM '{trades_dir}/*.parquet' t
JOIN resolved_markets m ON t.ticker = m.ticker
)
SELECT
COUNT(*) as sample_size,
100.0 * SUM(won) / COUNT(*) as win_rate
FROM all_positions
WHERE price = 5
""").df()
print(f"Combined Win Rate: {df['win_rate'][0]:.2f}%")
if __name__ == "__main__":
main()Maker and Takers
The second finding is about how you trade. Becker's paper found that Makers (those who place limit orders and wait) earn +2.5% excess returns per trade. Takers (the people who spam the buy button) lose a corresponding amount.
This doesn't just apply to Kalshi. He references a 2025 study titled "Exploring Decentralized Prediction Markets" that analyzed 124 million trades on Polymarket. Reichenbach and Walther found the exact same thing. The "unskilled" retail traders are almost always Takers looking for instant gratification. The "Top Traders" in the study are Makers. They sit on the order book and let the trade come to them.
I decided to write a script to analyze how much takers lost in the NBA Finals.