İçeriğe geç

7,426 forecasts against Polymarket: exactly where the market beat our models

NeuPortal ResearchEn yeniler4 dk okumaYazının dili: İngilizce

Öne çıkanlar

On the 7,048 calls that have resolved, the market scores 0.161 and our models score 0.194. The market wins. This post is about where it wins, because the answer is more specific, and more useful, than "markets are efficient".

Since September our statistical models have made 7,426 probability calls on Polymarket questions. Each call is stored next to the market price at the moment it was made, and the file holding it is timestamped into Bitcoin with OpenTimestamps. When the market resolves, both numbers are scored with the Brier score (lower is better).

On the 7,048 calls that have resolved, the market scores 0.161 and our models score 0.194. The market wins. This post is about where it wins, because the answer is more specific, and more useful, than "markets are efficient".

Everything below can be reproduced from the public dataset in a few lines of pandas (code at the end).

Headline numbers

trackresolved callsour Briermarket Brier
weather6,1280.2040.166
crypto6670.0990.094
sports1650.2130.208
markets520.1960.147
politics230.1400.201
tech130.3500.309
all7,0480.1940.161

Weather is 87% of the sample, so it dominates the total. Without weather the gap is small (0.130 vs 0.123 on 920 calls). The only track where we are ahead is politics, on 23 calls, which proves nothing.

One more number worth keeping in mind: our call scored better than the market price on 50.5% of individual questions. We win about half the coin flips, and lose the total anyway. The losses are bigger than the wins, and the rest of this post is about why.

Finding 1: we were far too sure that unlikely things would not happen

Take every call where our model said 10% or less. There are 2,176 of them.

  • our average probability: 3.8%
  • the market's average price on the same questions: 16.5%
  • how often the event actually happened: 17.0%

The market was almost exactly right; we were off by a factor of four. Most of these are weather "band" questions (will the high temperature land in a given 2-degree range). Our models put a narrow, confident distribution on the temperature and gave neighbouring bands almost nothing. Reality was wider than the model.

The market's own calibration, by contrast, is close to the diagonal everywhere it has data:

market price bucketcallsavg pricehappened
0-10%1,6165.4%5.3%
10-20%1,20115.1%13.7%
20-30%1,15825.3%26.3%
30-40%1,20635.3%35.2%
40-50%93645.0%45.7%

And ours:

our probability bucketcallsavg ourshappened
0-10%2,1763.8%17.0%
10-20%1,21614.9%23.8%
30-40%1,03435.2%31.4%
40-50%71045.2%35.4%
50-60%35655.0%41.3%
60-70%13365.0%43.6%

So the error runs both ways: too low at the bottom, too high in the middle. That is the signature of a model that is overconfident about which band wins, not one that is biased in a single direction.

Finding 2: the more we disagreed with the market, the worse we did

Group the calls by the gap between our probability and the market price:

gap between us and the marketcallsour Briermarket Brierwe beat the price
up to 5 points2,0850.1160.11657%
5-10 points1,2900.1530.14954%
10-20 points1,8570.2120.18648%
20-30 points1,0700.2490.19347%
over 30 points7460.3600.19537%

When we roughly agreed with the price, we tied it. Every step of disagreement cost us, and the large disagreements, the ones that would have looked like "edge", were the worst calls in the set.

Finding 3: mixing our model into the price only made it worse

A natural rescue is to blend: take some weighted average of our probability and the market's. If the model carried any information the price did not, some blend should beat the price alone.

weight on our modelBrier of the blend
0% (market only)0.161
25%0.163
50%0.169
75%0.180
100% (model only)0.194

Every amount of our model hurt. On this sample, the honest conclusion is that the models added nothing the price did not already know.

What we are not claiming

  • This is one set of models, mostly on one kind of question. It says little about forecasting in general and nothing about other teams.
  • Our first batch (calls from 14 to 26 September, 1,613 of them) was sealed late, on 26 September, after 1,394 had already resolved. Those rows are flagged sealed_before_resolution = false and are not evidence of forecasting in advance. They do not flatter us: on the 5,654 resolved calls sealed before their outcome, the result is the same (0.196 vs 0.160). Since 26 September every call is sealed minutes after it is made.
  • Nothing here is a trading signal or advice. It is a record of misses, kept so it cannot be edited later.

Reproduce it

import pandas as pd
from datasets import load_dataset

f = load_dataset("neuportal/forecasts-vs-market", split="train").to_pandas()
f = f[f.status == "final"]

# headline
print(f[["brier_model", "brier_market"]].mean())

# finding 1: our 0-10% calls
low = f[f.our_p <= 0.10]
print(len(low), low.our_p.mean(), low.market_p_at_call.mean(), low.outcome.mean())

# finding 2: by disagreement
gap = (f.our_p - f.market_p_at_call).abs()
bins = pd.cut(gap, [0, .05, .1, .2, .3, 1], include_lowest=True)
print(f.groupby(bins)[["brier_model", "brier_market"]].mean())

# finding 3: blends
for w in [0, .25, .5, .75, 1]:
    p = w * f.our_p + (1 - w) * f.market_p_at_call
    print(w, ((p - f.outcome) ** 2).mean())

To check that a call existed when we say it did, open its proof_file in the proofs repository and drop the .ots file, then the .json, on opentimestamps.org. The Bitcoin block it reports is the latest moment that call could have been written.

Educational transparency data, not financial advice.

Sıradaki yazı

Herkesin önünde puanladığımız tahminler

Her tahmin olaydan önce yazıya dökülür ve olaydan sonra puanlanır; isabetler de ıskalar da.

Yapay zekâ terminallerinin ve ödeme ağ geçidinin çalışmasını sağlamak ve doğrulamayı tamamlamak için çerezler kullanıyoruz. Sitede kalarak Çerez Politikamızı ve Gizlilik Politikamızı kabul etmiş olursunuz.

“Kabul et ve devam et” seçeneğini seçerek reklamlarımızı ölçmek için kullanılan Google Ads reklam çerezlerine de izin vermiş olursunuz. Bu çerezler kullanıcı hesabında asla kullanılmaz.