# Prediction markets — methodology

**The dataset:** `prediction-market-mentions.csv` — 2,623 settled Polymarket
"What will ⟨Trump⟩ say at ⟨event⟩?" markets across 224 speeches, 2024-06 to
2026-08. Every row is a market that closed and resolved, and that had a real
traded price before it closed.

---

## Where the numbers come from

**The venue.** Polymarket, harvested through its public Gamma and CLOB APIs
under the tags `mention-markets` (100343) and `trump-speech-mentions` (105481).

**The universe, and how it narrows.** Reported honestly, because the sample is
a choice and every step of it throws something away:

| slice | n |
|---|---|
| all settled word-markets, all speakers | 19,715 across 1,066 events |
| Trump only | 8,558 across 445 events |
| real single speeches (not "this week", not a date range) | 3,803 across 314 |
| **…that also have a real pre-close price — this dataset** | **2,623 across 224** |

The last cut is the one that matters: a market with no traded price cannot tell
you whether the price was any good, which is the entire question.

**The price** is `price_1h`, the CLOB midpoint one hour before the market
closed. One hour, not the close, because the last minutes of these markets
often trade on the speech already happening. `price_24h`, `price_close` and
`price_first` are included so you can check whether that choice matters. It
does not: the calibration result holds on all four.

**The outcome** is exact-term matching against the speech transcript.
Pluralisation counts, compounds count, other inflections do not. `threshold` is
how many times the word had to be said — most markets are 1, some are "3+
times". Resolution is mechanical, which is why this corpus is usable at all:
nobody is adjudicating intent.

---

## The three claims in the video, and how to rebuild them

**1 · The market is calibrated — the price is right to about two cents.**

Bucket by `price_1h`, then compare each bucket's mean price to the share of its
markets where `resolved_yes = 1`.

```python
import pandas as pd
d = pd.read_csv("prediction-market-mentions.csv")
edges = [0, .05, .10, .20, .35, .50, .65, .80, .90, .95, 1.001]
d["bucket"] = pd.cut(d.price_1h, edges, right=False)
g = d.groupby("bucket").agg(n=("price_1h","size"),
                            price=("price_1h","mean"),
                            actual=("resolved_yes","mean"))
g["gap"] = g.actual - g.price
print(g, "\nmean |gap| =", g.gap.abs().mean())      # 0.0204
```

**The binning changes the headline, so it is stated rather than hidden.** These
edges give a mean absolute gap of **0.0204**. Ten even bins give **0.0234**;
fifteen give 0.0231. All of them support "about two cents"; none of them is the
only defensible choice.

**The honest caveat: the coin flip is the worst band.** The 319 markets priced
between 45¢ and 55¢ happened just **43.3%** of the time — off by 6.4¢, three
times the average. That is not a footnote, it is the setup: it is exactly where
the fee is largest.

**2 · The fee is a parabola that peaks at 50¢.**

Both venues charge on `price × (1 − price)`. Kalshi publishes
`0.07 × contracts × P × (1−P)`; Polymarket's "Mentions" category peaks at 1.56%
of notional, which is the same curve with a coefficient of 0.0624. The
`fee_cents_per_contract` column is that second one evaluated at each row's own
price. It peaks at **1.56¢** at exactly 50¢ and falls to nearly nothing at both
ends.

**Where the trading is.** By market count this corpus is U-shaped — the 0-10¢
and 90-100¢ bins hold the most markets. **By volume it is centre-weighted:
60.5% of all trading sits between 25¢ and 75¢**, where the fee is still at
least 75% of its peak. A market priced at 3¢ is settled, and nobody trades a
settled market. "Where everybody trades" is a claim about money, so it is
measured in money.

**3 · A calibrated price plus a fee is a negative expectation, and it
compounds.**

If the price is the true probability, both sides of the bet are worth the same
and expected profit is exactly zero: `p(1−p) − (1−p)p = 0`. Then subtract the
fee.

At 50¢ with fee `f` you stake `0.5 + f` to win 1, so a bet returns
`+1/(0.5+f) − 1` with probability 0.5 and `−1` otherwise. At the Mentions rate
(`f = 0.0156`) the per-bet mean is **−0.0303** with sd **0.9697**, so

```
P(ahead after N bets) ≈ Φ( −0.0312 · √N )
```

| bets | you are ahead |
|---|---|
| 100 | 37.8% |
| 1,000 | 16.2% |
| 10,000 | **0.090%** — about 1 in 1,100 |

Cross-checked against a 40,000-path simulation at the Kalshi rate: theory
13.42% vs simulated 13.23% at N = 1,000.

---

## What we looked for and did NOT find

Published because a methodology that only lists its wins is an advertisement.

- **No edge survives costs.** Selling every market indiscriminately returns
  +4.25% ROI (+0.0208 per contract). At a 2¢ spread that is +0.0008 — nothing.
- **The favourite–longshot bias is not in this data.** Fading longshots
  (p < 0.10) returns +2.41%, *worse* than selling indiscriminately. The classic
  story does not hold here.
- **A "+21% selling the joke" result was leverage, not skill.** Profit per
  contract is flat at ~2¢ across the price range while ROI% swings from 2% to
  19%, purely because a cheap NO position divides by a small number. Always
  read profit per contract next to any ROI%.
- **Residual YES-overpricing is not significant.** −2.4 points, but markets
  inside one speech are correlated: clustered p = 0.060, bootstrap CI
  [−0.049, +0.001].
- **A real model lost to the price, 30 times out of 30.** A latent-exposure
  Poisson model fitted by maximum likelihood scored Brier 0.2338 against the
  market's 0.1589. Even had it won, it needed to win by more than the fee.

---

## The claim this is careful about

"Prediction markets always take your money" is literally false, and the video
says so. **Makers pay no fee and collect a rebate funded by taker fees**, and a
genuinely better-informed trader can win.

The narrower claim is the one the arithmetic supports: **the taker loses by
construction.** If you are tapping buy in an app, you are the taker, every time.

---

## Reuse

Free to use, including commercially. A credit to **reelgorithm.py** is
appreciated but not required. Prices and outcomes are Polymarket's; the
derived columns and the analysis are ours.

Questions or a correction: reply to any newsletter email.
