metaculus

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Metaculus API

Metaculus API

Metaculus is a forecasting platform where users predict outcomes of real-world events. Questions range across science, technology, politics, economics, and more. The platform aggregates individual forecasts into community predictions and scores forecasters on accuracy.
Check this skill and the official API documentation FREQUENTLY for updates.
Feedback: Contact the Metaculus team at api-requests@metaculus.com with questions, ideas, or feedback.
Source code & issues: github.com/Metaculus/metaculus

Metaculus 是一个供用户预测现实世界事件结果的预测平台。问题涵盖科学、技术、政治、经济等多个领域。该平台会将个人预测汇总为社区预测,并根据准确性对预测者进行评分。
经常查看此技能文档和官方API文档以获取更新信息。
反馈: 如有问题、想法或反馈,请通过 api-requests@metaculus.com 联系Metaculus团队。
源代码与问题反馈: github.com/Metaculus/metaculus

Key Concepts (Glossary)

核心概念(术语表)

TermDefinition
PostThe primary feed entity. A post wraps a question, group of questions, conditional pair, or notebook. Posts have statuses, authors, projects, and comments.
QuestionA single forecastable item within a post. Types:
binary
,
multiple_choice
,
numeric
,
discrete
,
date
.
Group of QuestionsA post containing multiple related sub-questions displayed together (e.g., "What will GDP be in 2025, 2026, 2027?").
ConditionalA post with paired questions: "If [condition], what is P(child)?" — produces question_yes and question_no variants.
ForecastA user's prediction on a question. Format depends on question type: probability (binary), CDF (continuous), or distribution (multiple choice).
Community Prediction (CP)The aggregated forecast from all users, computed via various aggregation methods.
Aggregation MethodHow individual forecasts are combined:
recency_weighted
(default),
unweighted
,
metaculus_prediction
,
single_aggregation
.
ProjectA container for posts — can be a tournament, category, tag, question series, or site section.
TournamentA special project type with prize pools, start/close dates, and leaderboards.
CategoryA topic classification (e.g., "Nuclear Technology & Risks", "Health & Pandemics").
ResolutionThe actual outcome of a question once known. Values vary by type:
yes
/
no
(binary), a number, a date, or an option name.
Curation StatusEditorial status of a post:
draft
,
pending
,
rejected
,
approved
.
ScalingDefines how a continuous question's range maps to the CDF. Includes
range_min
,
range_max
,
zero_point
(for log scale), and bounds.
CDFCumulative Distribution Function — the format for continuous forecasts. A list of 201 floats (or
inbound_outcome_count + 1
for discrete).
Inbound Outcome CountNumber of possible outcomes within a question's range (excluding out-of-bounds). Default is 200 for continuous; smaller for discrete.

术语定义
Post(帖子)平台信息流中的核心实体。一个帖子可包含单个问题、一组相关问题、条件式问题对或笔记内容。帖子包含状态、作者、项目和评论等信息。
Question(问题)帖子中的单个可预测项。类型包括:
binary
(二元)、
multiple_choice
(多选)、
numeric
(数值型)、
discrete
(离散型)、
date
(日期型)。
Group of Questions(问题组)包含多个相关子问题的帖子(例如:“2025、2026、2027年的GDP将是多少?”)。
Conditional(条件式问题)包含配对问题的帖子:“如果[条件成立],则P(子问题)的概率是多少?”——会生成question_yes和question_no两种变体。
Forecast(预测)用户针对某个问题提交的预测内容。格式取决于问题类型:二元问题为概率值,连续型问题为CDF,多选问题为概率分布。
Community Prediction (CP)(社区预测)所有用户预测的汇总结果,通过多种聚合方法计算得出。
Aggregation Method(聚合方法)汇总个人预测的方式:
recency_weighted
(默认,近期预测权重更高)、
unweighted
(所有预测权重相等)、
metaculus_prediction
(Metaculus专有算法预测)、
single_aggregation
(测试版,仅管理员可用)。
Project(项目)帖子的容器——可以是锦标赛、分类、标签、问题系列或网站板块。
Tournament(锦标赛)特殊类型的项目,包含奖金池、开始/结束日期和排行榜。
Category(分类)主题分类(例如:“核技术与风险”、“健康与流行病”)。
Resolution(结果判定)问题的实际结果(当结果确定后)。值的类型取决于问题:二元问题为
yes
/
no
,数值型为数字,日期型为日期,多选问题为选项名称。
Curation Status(审核状态)帖子的编辑状态:
draft
(草稿)、
pending
(待审核)、
rejected
(已拒绝)、
approved
(已通过)。
Scaling(缩放规则)定义连续型问题的范围如何映射到CDF。包含
range_min
range_max
zero_point
(用于对数缩放)和边界设置。
CDF累积分布函数——连续型预测的格式。包含201个浮点数(离散型问题为
inbound_outcome_count + 1
个)。
Inbound Outcome Count(有效结果数量)问题范围内的可能结果数量(不包含超出边界的结果)。连续型问题默认值为200,离散型问题数值更小。

Base URL

基础URL

All endpoints are served from:
https://www.metaculus.com
All paths below are relative to this base (e.g.,
GET /api/posts/
means
GET https://www.metaculus.com/api/posts/
).

所有接口的基础地址为:
https://www.metaculus.com
以下所有路径均基于此基础地址(例如:
GET /api/posts/
对应
GET https://www.metaculus.com/api/posts/
)。

Authentication

身份验证

All API requests require authentication. Unauthenticated requests are rejected.
所有API请求均需要身份验证。 未验证的请求会被拒绝。

Getting Your Token

获取你的Token

  1. Log in to Metaculus.
  2. Go to your Account Settings → API Access.
  3. Copy (or generate) your API token.
  1. 登录 Metaculus
  2. 进入你的 账户设置 → API访问 页面。
  3. 复制(或生成)你的API Token。

Using the Token

使用Token

Add the
Authorization
header to every request. The token must be prefixed with the literal string
Token
followed by a space:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
在每个请求中添加
Authorization
请求头。Token必须以字符串
Token
开头,后跟一个空格:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

Example: curl

示例:curl

bash
curl -s "https://www.metaculus.com/api/posts/?limit=5&order_by=-published_at" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq .
bash
curl -s "https://www.metaculus.com/api/posts/?limit=5&order_by=-published_at" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq .

Example: Python

示例:Python

python
import os, requests

TOKEN = os.environ["METACULUS_API_TOKEN"]
HEADERS = {"Authorization": f"Token {TOKEN}"}
BASE = "https://www.metaculus.com"

resp = requests.get(f"{BASE}/api/posts/", headers=HEADERS, params={"limit": 5})
resp.raise_for_status()
data = resp.json()
python
import os, requests

TOKEN = os.environ["METACULUS_API_TOKEN"]
HEADERS = {"Authorization": f"Token {TOKEN}"}
BASE = "https://www.metaculus.com"

resp = requests.get(f"{BASE}/api/posts/", headers=HEADERS, params={"limit": 5})
resp.raise_for_status()
data = resp.json()

Environment Variables

环境变量

Never hardcode tokens. Store them as environment variables or in a
.env
file:
METACULUS_API_TOKEN=your-token-here

请勿硬编码Token。请将其存储为环境变量或保存在
.env
文件中:
METACULUS_API_TOKEN=your-token-here

Rate Limits

请求频率限制

Metaculus throttles requests to prevent abuse. If you receive a
429 Too Many Requests
response, implement exponential backoff before retrying.

Metaculus会对请求进行限流以防止滥用。如果收到
429 Too Many Requests
响应,请实现指数退避机制后再重试。

REST API Endpoints Overview

REST API接口概述

Feed (Posts)

信息流(帖子)

MethodEndpointDescriptionAuth
GET
/api/posts/
Retrieve paginated posts feed with filtersRequired
GET
/api/posts/{postId}/
Retrieve a single post with full detailsRequired
方法接口描述身份验证
GET
/api/posts/
获取带筛选条件的分页帖子信息流必填
GET
/api/posts/{postId}/
获取单个帖子的完整详情必填

Questions & Forecasts

问题与预测

MethodEndpointDescriptionAuth
POST
/api/questions/forecast/
Submit forecasts for one or more questionsRequired
POST
/api/questions/withdraw/
Withdraw active forecastsRequired
方法接口描述身份验证
POST
/api/questions/forecast/
提交一个或多个问题的预测必填
POST
/api/questions/withdraw/
撤回已提交的活跃预测必填

Comments

评论

MethodEndpointDescriptionAuth
GET
/api/comments/
Retrieve comments (filter by post or author)Required
POST
/api/comments/create/
Create a new comment on a postRequired
方法接口描述身份验证
GET
/api/comments/
获取评论(可按帖子或作者筛选)必填
POST
/api/comments/create/
在帖子下创建新评论必填

Utilities & Data

工具与数据

MethodEndpointDescriptionAuth
GET
/api/posts/{postId}/download-data/
Download question data as a ZIP of CSVsRequired
GET
/api/projects/{projectId}/download-data/
Download full project data as a ZIP of CSVsRequired (admin/whitelisted)

方法接口描述身份验证
GET
/api/posts/{postId}/download-data/
以ZIP压缩包(内含CSV文件)的形式下载问题数据必填
GET
/api/projects/{projectId}/download-data/
下载整个项目的完整数据(ZIP压缩包)必填(仅管理员或白名单用户可用)

Data Model

数据模型

Post → Question Hierarchy

帖子 → 问题层级关系

A Post is the top-level entity in the feed. Each post contains exactly one of:
  • question
    — a single question (binary, numeric, date, multiple choice, or discrete)
  • group_of_questions
    — multiple related sub-questions
  • conditional
    — a conditional pair (condition + child, producing question_yes and question_no)
  • A notebook (no question content)
The other fields will be
null
. For example, a post with a single binary question will have
question
populated and
conditional
/
group_of_questions
set to
null
.
帖子是信息流中的顶层实体。每个帖子仅包含以下内容之一:
  • question
    — 单个问题(适用于单问题帖子)
  • group_of_questions
    — 多个相关子问题
  • conditional
    — 条件式问题对(条件+子问题,生成question_yes和question_no两种变体)
  • 笔记内容(无问题相关内容)
其他字段将为
null
。例如,包含单个二元问题的帖子会填充
question
字段,而
conditional
/
group_of_questions
字段将设为
null

Post

帖子

FieldTypeDescription
id
integerUnique post ID
title
stringFull title
short_title
stringURL-friendly short title
slug
stringURL slug
author_id
integerAuthor's user ID
author_username
stringAuthor's username
projects
objectAssociated projects (see below)
created_at
datetimeWhen the post was created
published_at
datetime?When the post was published
open_time
datetime?When the question opened for forecasting
edited_at
datetimeLast edit timestamp
curation_status
string
draft
,
pending
,
rejected
, or
approved
comment_count
integerNumber of comments
status
string
open
,
upcoming
,
closed
,
resolved
,
draft
,
pending
,
rejected
nr_forecasters
integerNumber of unique forecasters
question
Question?Single question (if applicable)
conditional
Conditional?Conditional pair (if applicable)
group_of_questions
GroupOfQuestions?Question group (if applicable)
user_permission
string
forecaster
or
viewer
vote
object
{ score: int, user_vote: string? }
forecasts_count
integerTotal number of forecasts
字段类型描述
id
整数唯一帖子ID
title
字符串完整标题
short_title
字符串适合URL的短标题
slug
字符串URL别名
author_id
整数作者的用户ID
author_username
字符串作者的用户名
projects
对象关联的项目(详见下文)
created_at
日期时间帖子创建时间
published_at
日期时间(可选)帖子发布时间
open_time
日期时间(可选)问题开放预测的时间
edited_at
日期时间最后编辑时间戳
curation_status
字符串
draft
pending
rejected
approved
comment_count
整数评论数量
status
字符串
open
(开放预测)、
upcoming
(即将开放)、
closed
(停止预测)、
resolved
(已出结果)、
draft
pending
rejected
nr_forecasters
整数唯一预测者数量
question
Question(可选)单个问题(如适用)
conditional
Conditional(可选)条件式问题对(如适用)
group_of_questions
GroupOfQuestions(可选)问题组(如适用)
user_permission
字符串
forecaster
(可预测)或
viewer
(仅查看)
vote
对象
{ score: int, user_vote: string? }
forecasts_count
整数预测总数量

Post Projects Object

帖子关联项目对象

FieldTypeDescription
site_main
Project[]Site-level project associations
tournament
Project[]Tournaments this post belongs to
category
Category[]Categories
tag
Tag[]Tags
question_series
Project[]Question series
default_project
ProjectThe post's primary/default project
字段类型描述
site_main
Project[]网站级别的项目关联
tournament
Project[]帖子所属的锦标赛
category
Category[]分类
tag
Tag[]标签
question_series
Project[]问题系列
default_project
Project帖子的主要/默认项目

Project

项目

FieldTypeDescription
id
integerProject ID
type
string
site_main
,
tournament
, etc.
name
stringDisplay name
slug
string?URL slug
prize_pool
stringPrize pool amount (e.g., "0.00")
start_date
datetime?Start date
close_date
datetime?Close date
is_ongoing
boolean?Whether the project is ongoing
default_permission
stringDefault user permission (e.g., "forecaster")
visibility
string
normal
,
not_in_main_feed
,
unlisted
字段类型描述
id
整数项目ID
type
字符串
site_main
tournament
name
字符串显示名称
slug
字符串(可选)URL别名
prize_pool
字符串奖金池金额(例如:"0.00")
start_date
日期时间(可选)开始日期
close_date
日期时间(可选)结束日期
is_ongoing
布尔值(可选)项目是否正在进行中
default_permission
字符串默认用户权限(例如:"forecaster")
visibility
字符串
normal
(正常显示)、
not_in_main_feed
(不显示在主信息流)、
unlisted
(未列出)

Question

问题

FieldTypeDescription
id
integerUnique question ID (used in forecast submissions, not the post ID)
title
stringQuestion title
description
stringFull description (may be omitted unless
include_descriptions=true
)
type
string
binary
,
multiple_choice
,
numeric
,
discrete
,
date
status
string
upcoming
,
open
,
closed
,
resolved
resolution
string?Resolution value (null if unresolved)
resolution_criteria
stringHow the question will be resolved
fine_print
stringAdditional resolution details
created_at
datetimeCreation timestamp
open_time
datetimeWhen forecasting opens
scheduled_close_time
datetimeWhen forecasting is scheduled to close
actual_close_time
datetimeWhen forecasting actually closed
scheduled_resolve_time
datetimeWhen resolution is scheduled
actual_resolve_time
datetime?When it was actually resolved
options
string[]Current options (multiple choice only)
all_options_ever
string[]All options that have ever existed (multiple choice only)
open_upper_bound
booleanWhether the upper bound is open
open_lower_bound
booleanWhether the lower bound is open
inbound_outcome_count
integer?Number of discrete outcomes in range (default 200 for continuous)
unit
stringDisplay unit (e.g., "$", "°C")
label
string?Label for sub-questions
scaling
QuestionScalingRange and scaling parameters
aggregations
objectCommunity prediction aggregations (see below)
字段类型描述
id
整数唯一问题ID(提交预测时使用此ID,而非帖子ID
title
字符串问题标题
description
字符串完整描述(仅当
include_descriptions=true
时返回)
type
字符串
binary
multiple_choice
numeric
discrete
date
status
字符串
upcoming
open
closed
resolved
resolution
字符串(可选)结果值(未判定时为null)
resolution_criteria
字符串问题的结果判定规则
fine_print
字符串额外的结果判定细节
created_at
日期时间创建时间戳
open_time
日期时间开放预测的时间
scheduled_close_time
日期时间计划停止预测的时间
actual_close_time
日期时间实际停止预测的时间
scheduled_resolve_time
日期时间计划判定结果的时间
actual_resolve_time
日期时间(可选)实际判定结果的时间
options
string[]当前选项(仅多选问题)
all_options_ever
string[]所有曾出现过的选项(仅多选问题)
open_upper_bound
布尔值上边界是否为开放区间
open_lower_bound
布尔值下边界是否为开放区间
inbound_outcome_count
整数(可选)范围内的离散结果数量(连续型问题默认200)
unit
字符串显示单位(例如:"$", "°C")
label
字符串(可选)子问题的标签
scaling
QuestionScaling范围和缩放参数
aggregations
对象社区预测的聚合结果(详见下文)

QuestionScaling

问题缩放参数

FieldTypeDescription
range_min
float?Lower boundary of the input range
range_max
float?Upper boundary of the input range
zero_point
float?Log-scale zero point (null = linear scaling)
open_upper_bound
boolean?Whether upper bound is open
open_lower_bound
boolean?Whether lower bound is open
inbound_outcome_count
integer?Number of outcomes within range
continuous_range
string[]?Real-value locations where the CDF is evaluated
字段类型描述
range_min
浮点数(可选)输入范围的下边界
range_max
浮点数(可选)输入范围的上边界
zero_point
浮点数(可选)对数缩放的零点(null表示线性缩放)
open_upper_bound
布尔值(可选)上边界是否为开放区间
open_lower_bound
布尔值(可选)下边界是否为开放区间
inbound_outcome_count
整数(可选)范围内的结果数量
continuous_range
string[](可选)计算CDF时使用的实际值位置

Aggregations

聚合结果

Each question includes an
aggregations
object with up to four methods:
  • recency_weighted
    — Default; weights recent forecasts more heavily
  • unweighted
    — Equal weight for all forecasts
  • metaculus_prediction
    — Metaculus's proprietary prediction
  • single_aggregation
    — Beta; admin-only
Each method contains:
FieldTypeDescription
history
object[]Time series of aggregated forecasts
latest
object?Most recent aggregated forecast
score_data
object?Scoring information
Each history/latest entry contains:
FieldTypeDescription
start_time
datetimeWhen this aggregation period started
end_time
datetime?When this aggregation period ended
forecast_values
float[]The aggregated forecast (probability for binary, CDF for continuous)
forecaster_count
integerNumber of contributing forecasters
centers
float[]Median/center values
interval_lower_bounds
float[]Lower confidence bounds
interval_upper_bounds
float[]Upper confidence bounds
means
float?Mean values
每个问题的
aggregations
对象包含最多四种聚合方法的结果:
  • recency_weighted
    — 默认方法,近期预测权重更高
  • unweighted
    — 所有预测权重相等
  • metaculus_prediction
    — Metaculus专有算法的预测结果
  • single_aggregation
    — 测试版,仅管理员可用
每种方法包含以下内容:
字段类型描述
history
object[]聚合预测的时间序列数据
latest
对象(可选)最新的聚合预测结果
score_data
对象(可选)评分信息
history
latest
中的每个条目包含:
字段类型描述
start_time
日期时间此聚合周期的开始时间
end_time
日期时间(可选)此聚合周期的结束时间
forecast_values
float[]聚合后的预测结果(二元问题为概率,连续型问题为CDF)
forecaster_count
整数参与此聚合的预测者数量
centers
float[]中位数/中心值
interval_lower_bounds
float[]置信区间下边界
interval_upper_bounds
float[]置信区间上边界
means
浮点数(可选)平均值

Conditional

条件式问题

FieldTypeDescription
id
integerConditional ID
condition
QuestionThe condition question
condition_child
QuestionThe child question
question_yes
Question"If condition = Yes" variant
question_no
Question"If condition = No" variant
字段类型描述
id
整数条件式问题ID
condition
Question条件问题
condition_child
Question子问题
question_yes
Question"如果条件为Yes"的变体问题
question_no
Question"如果条件为No"的变体问题

GroupOfQuestions

问题组

FieldTypeDescription
id
integerGroup ID
description
stringGroup description
resolution_criteria
stringResolution criteria
fine_print
stringAdditional details
group_variable
stringThe variable that differs across sub-questions
graph_type
string
multiple_choice_graph
or
fan_graph
questions
Question[]The sub-questions
字段类型描述
id
整数问题组ID
description
字符串问题组描述
resolution_criteria
字符串结果判定规则
fine_print
字符串额外细节
group_variable
字符串子问题之间的差异变量
graph_type
字符串
multiple_choice_graph
fan_graph
questions
Question[]子问题列表

Comment

评论

FieldTypeDescription
id
integerComment ID
author
object
{ id, username, is_bot, is_staff }
parent_id
integer?Parent comment ID (for replies)
root_id
integer?Root comment ID in thread
created_at
datetimeCreation timestamp
text
stringComment content
on_post
integerPost ID the comment belongs to
included_forecast
booleanWhether the user's last forecast is included
is_private
booleanWhether the comment is private
vote_score
integerTotal vote score
user_vote
integerCurrent user's vote (-1, 0, 1)

字段类型描述
id
整数评论ID
author
对象
{ id, username, is_bot, is_staff }
parent_id
整数(可选)父评论ID(用于回复)
root_id
整数(可选)评论线程的根评论ID
created_at
日期时间创建时间戳
text
字符串评论内容
on_post
整数评论所属的帖子ID
included_forecast
布尔值是否包含用户的最新预测
is_private
布尔值评论是否为私有
vote_score
整数总投票分数
user_vote
整数当前用户的投票(-1, 0, 1)

Endpoints: Detailed Reference

接口:详细参考

GET /api/posts/ — Retrieve Posts Feed

GET /api/posts/ — 获取帖子信息流

Returns a paginated list of posts with extensive filtering and sorting.
Query Parameters:
ParameterTypeDescription
limit
integerPage size (default varies)
offset
integerPagination offset
tournaments
string[]Filter by tournament slugs (e.g.,
metaculus-cup
,
aibq3
)
statuses
string[]Filter by status:
upcoming
,
closed
,
resolved
,
open
forecast_type
string[]Filter by type:
binary
,
multiple_choice
,
numeric
,
discrete
,
date
,
conditional
,
group_of_questions
,
notebook
categories
string[]Filter by category slugs (e.g.,
nuclear
,
health-pandemics
)
forecaster_id
integerPosts where this user has forecasted
not_forecaster_id
integerPosts where this user has NOT forecasted
for_main_feed
booleanFilter for main feed suitability
with_cp
booleanInclude community predictions (default:
false
). For groups, returns CP for top 3 sub-questions only.
include_cp_history
booleanInclude full CP history per aggregation method (default:
false
)
include_descriptions
booleanInclude
description
,
fine_print
,
resolution_criteria
fields
order_by
stringSort field. Prefix with
-
for descending. Options below.
open_time__gt
datetimeOpen time greater than (also supports
__gte
,
__lt
,
__lte
)
published_at__gt
datetimePublished time greater than (also supports
__gte
,
__lt
,
__lte
)
scheduled_resolve_time__gt
datetimeScheduled resolve time greater than (also supports
__gte
,
__lt
,
__lte
)
order_by
options:
ValueDescription
published_at
Publication time
open_time
When forecasting opened
vote_score
Community vote score
comment_count
Number of comments
forecasts_count
Number of forecasts
scheduled_close_time
Scheduled close time
scheduled_resolve_time
Scheduled resolution time
user_last_forecasts_date
When the user last forecasted
unread_comment_count
Unread comments
weekly_movement
Weekly probability movement
divergence
Divergence metric
hotness
Composite trending score (decays after 3.5 days)
score
User forecasting performance (requires
forecaster_id
)
Response:
json
{
  "next": "https://www.metaculus.com/api/posts/?limit=20&offset=20",
  "previous": null,
  "results": [ /* array of Post objects */ ]
}
Example: Fetch open binary questions, newest first:
bash
curl -s "https://www.metaculus.com/api/posts/?statuses=open&forecast_type=binary&order_by=-published_at&limit=10&with_cp=true" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq '.results[] | {id, title, status}'
Example: Fetch questions from a tournament:
bash
curl -s "https://www.metaculus.com/api/posts/?tournaments=metaculus-cup&with_cp=true&limit=20" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq .
Example: Fetch questions you haven't forecasted on yet:
bash
undefined
返回带筛选和排序功能的分页帖子列表。
查询参数:
参数类型描述
limit
整数每页数量(默认值可变)
offset
整数分页偏移量
tournaments
string[]按锦标赛别名筛选(例如:
metaculus-cup
,
aibq3
statuses
string[]按状态筛选:
upcoming
,
closed
,
resolved
,
open
forecast_type
string[]按问题类型筛选:
binary
,
multiple_choice
,
numeric
,
discrete
,
date
,
conditional
,
group_of_questions
,
notebook
categories
string[]按分类别名筛选(例如:
nuclear
,
health-pandemics
forecaster_id
整数筛选该用户已预测过的帖子
not_forecaster_id
整数筛选该用户未预测过的帖子
for_main_feed
布尔值筛选适合显示在主信息流的帖子
with_cp
布尔值是否包含社区预测(默认:
false
)。对于问题组,仅返回前3个子问题的社区预测。
include_cp_history
布尔值是否包含完整的社区预测历史数据(默认:
false
include_descriptions
布尔值是否包含问题描述、判定规则等字段
order_by
字符串排序字段。前缀
-
表示降序。选项见下文。
open_time__gt
日期时间开放时间晚于指定时间(也支持
__gte
,
__lt
,
__lte
published_at__gt
日期时间发布时间晚于指定时间(也支持
__gte
,
__lt
,
__lte
scheduled_resolve_time__gt
日期时间计划判定时间晚于指定时间(也支持
__gte
,
__lt
,
__lte
order_by
选项:
描述
published_at
发布时间
open_time
开放预测时间
vote_score
社区投票分数
comment_count
评论数量
forecasts_count
预测数量
scheduled_close_time
计划停止预测时间
scheduled_resolve_time
计划判定结果时间
user_last_forecasts_date
用户最后一次预测的时间
unread_comment_count
未读评论数量
weekly_movement
每周概率变化幅度
divergence
分歧度指标
hotness
综合热度评分(3.5天后衰减)
score
用户预测表现分数(必须指定
forecaster_id
响应:
json
{
  "next": "https://www.metaculus.com/api/posts/?limit=20&offset=20",
  "previous": null,
  "results": [ /* 帖子对象数组 */ ]
}
示例:获取最新的开放二元问题:
bash
curl -s "https://www.metaculus.com/api/posts/?statuses=open&forecast_type=binary&order_by=-published_at&limit=10&with_cp=true" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq '.results[] | {id, title, status}'
示例:获取锦标赛中的问题:
bash
curl -s "https://www.metaculus.com/api/posts/?tournaments=metaculus-cup&with_cp=true&limit=20" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq .
示例:获取你尚未预测的问题:
bash
undefined

Replace YOUR_USER_ID with your actual Metaculus user ID

将YOUR_USER_ID替换为你的Metaculus用户ID

curl -s "https://www.metaculus.com/api/posts/?not_forecaster_id=YOUR_USER_ID&statuses=open&limit=10"
-H "Authorization: Token $METACULUS_API_TOKEN" | jq .

---
curl -s "https://www.metaculus.com/api/posts/?not_forecaster_id=YOUR_USER_ID&statuses=open&limit=10"
-H "Authorization: Token $METACULUS_API_TOKEN" | jq .

---

GET /api/posts/{postId}/ — Retrieve Post Details

GET /api/posts/{postId}/ — 获取帖子详情

Returns full details for a single post, including all sub-questions and aggregations.
Path Parameters:
ParameterTypeDescription
postId
integerThe post ID
Example:
bash
curl -s "https://www.metaculus.com/api/posts/12345/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq .

返回单个帖子的完整详情,包括所有子问题和聚合结果。
路径参数:
参数类型描述
postId
整数帖子ID
示例:
bash
curl -s "https://www.metaculus.com/api/posts/12345/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq .

POST /api/questions/forecast/ — Submit Forecasts

POST /api/questions/forecast/ — 提交预测

Submit one or more forecasts. The request body is a JSON array of forecast objects.
Important: The
question
field takes the question ID, not the post ID. Get the question ID from
post.question.id
,
post.group_of_questions.questions[].id
, or
post.conditional.question_yes.id
/
post.conditional.question_no.id
.
提交一个或多个预测。请求体为JSON数组,包含多个预测对象。
重要提示:
question
字段使用问题ID,而非帖子ID。可从
post.question.id
post.group_of_questions.questions[].id
post.conditional.question_yes.id
/
post.conditional.question_no.id
中获取问题ID。

Binary Forecast

二元问题预测

json
[
  {
    "question": 12345,
    "probability_yes": 0.63
  }
]
FieldTypeRequiredDescription
question
integerYesQuestion ID
probability_yes
floatYesProbability between 0 and 1
end_time
datetimeNoAuto-withdraw timestamp
json
[
  {
    "question": 12345,
    "probability_yes": 0.63
  }
]
字段类型必填描述
question
整数问题ID
probability_yes
浮点数0到1之间的概率值
end_time
日期时间自动撤回预测的时间戳

Multiple Choice Forecast

多选问题预测

json
[
  {
    "question": 12345,
    "probability_yes_per_category": {
      "Futurama": 0.5,
      "Paperclipalypse": 0.3,
      "Singularia": 0.2
    }
  }
]
FieldTypeRequiredDescription
question
integerYesQuestion ID
probability_yes_per_category
objectYesMap of option name → probability. Must sum to 1.0.
end_time
datetimeNoAuto-withdraw timestamp
json
[
  {
    "question": 12345,
    "probability_yes_per_category": {
      "Futurama": 0.5,
      "Paperclipalypse": 0.3,
      "Singularia": 0.2
    }
  }
]
字段类型必填描述
question
整数问题ID
probability_yes_per_category
对象选项名称→概率的映射。所有概率之和必须为1.0。
end_time
日期时间自动撤回预测的时间戳

Continuous Forecast (Numeric / Date / Discrete)

连续型问题预测(数值/日期/离散)

json
[
  {
    "question": 12345,
    "continuous_cdf": [0.0, 0.00005, 0.00010, "... 201 values total ...", 1.0]
  }
]
FieldTypeRequiredDescription
question
integerYesQuestion ID
continuous_cdf
float[]YesCDF array (see CDF generation section below)
distribution_input
objectNoSlider values for frontend display
end_time
datetimeNoAuto-withdraw timestamp
json
[
  {
    "question": 12345,
    "continuous_cdf": [0.0, 0.00005, 0.00010, "... 共201个值 ...", 1.0]
  }
]
字段类型必填描述
question
整数问题ID
continuous_cdf
float[]CDF数组(详见下文CDF生成部分)
distribution_input
对象用于前端显示的滑块值
end_time
日期时间自动撤回预测的时间戳

Conditional Forecast

条件式问题预测

Submit forecasts for both the "if Yes" and "if No" questions:
json
[
  { "question": 111, "probability_yes": 0.499 },
  { "question": 222, "probability_yes": 0.501 }
]
Where
111
is
conditional.question_yes.id
and
222
is
conditional.question_no.id
.
同时提交"if Yes"和"if No"两种变体问题的预测:
json
[
  { "question": 111, "probability_yes": 0.499 },
  { "question": 222, "probability_yes": 0.501 }
]
其中
111
conditional.question_yes.id
222
conditional.question_no.id

Group Forecast

问题组预测

Submit forecasts for multiple sub-questions in a single request:
json
[
  { "question": 1, "probability_yes": 0.11 },
  { "question": 2, "probability_yes": 0.22 },
  { "question": 3, "probability_yes": 0.33 }
]
Example: Submit a binary forecast with curl:
bash
curl -s -X POST "https://www.metaculus.com/api/questions/forecast/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{"question": 12345, "probability_yes": 0.75}]'
Responses:
StatusDescription
201
Forecasts submitted successfully
400
Invalid request format

在单个请求中提交多个子问题的预测:
json
[
  { "question": 1, "probability_yes": 0.11 },
  { "question": 2, "probability_yes": 0.22 },
  { "question": 3, "probability_yes": 0.33 }
]
示例:使用curl提交二元问题预测:
bash
curl -s -X POST "https://www.metaculus.com/api/questions/forecast/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{"question": 12345, "probability_yes": 0.75}]'
响应:
状态码描述
201
预测提交成功
400
请求格式无效

POST /api/questions/withdraw/ — Withdraw Forecasts

POST /api/questions/withdraw/ — 撤回预测

Withdraw active forecasts. The request body is a JSON array of withdrawal objects.
json
[
  { "question": 12345 },
  { "question": 12346 }
]
Example:
bash
curl -s -X POST "https://www.metaculus.com/api/questions/withdraw/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{"question": 12345}]'

撤回已提交的活跃预测。请求体为JSON数组,包含多个撤回对象。
json
[
  { "question": 12345 },
  { "question": 12346 }
]
示例:
bash
curl -s -X POST "https://www.metaculus.com/api/questions/withdraw/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{"question": 12345}]'

GET /api/comments/ — Retrieve Comments

GET /api/comments/ — 获取评论

Fetch comments with filters. Either
post
or
author
is required.
Query Parameters:
ParameterTypeRequiredDescription
post
integerOne of post/authorPost ID to filter by
author
integerOne of post/authorAuthor user ID to filter by
limit
integerNoNumber of comments to retrieve
offset
integerNoPagination offset
is_private
booleanNoFilter private vs public (default:
false
)
use_root_comments_pagination
booleanNoIf
true
, pagination applies to root comments only; all child comments are included
sort
stringNo
created_at
(ascending) or
-created_at
(descending)
focus_comment_id
integerNoPlace this comment at the top of results
Response:
json
{
  "total_count": 42,
  "count": 15,
  "next": "https://www.metaculus.com/api/comments/?post=123&limit=10&offset=10",
  "previous": null,
  "results": [ /* array of Comment objects */ ]
}
  • total_count
    — Total root + child comments
  • count
    — Total root comments only
Example:
bash
curl -s "https://www.metaculus.com/api/comments/?post=12345&sort=-created_at&limit=20" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq .

获取带筛选条件的评论。必须指定
post
author
参数之一。
查询参数:
参数类型必填描述
post
整数二选一按帖子ID筛选
author
整数二选一按作者用户ID筛选
limit
整数要获取的评论数量
offset
整数分页偏移量
is_private
布尔值筛选私有/公开评论(默认:
false
use_root_comments_pagination
布尔值如果为
true
,分页仅针对根评论,所有子评论都会包含在结果中
sort
字符串
created_at
(升序)或
-created_at
(降序)
focus_comment_id
整数将指定评论放在结果顶部
响应:
json
{
  "total_count": 42,
  "count": 15,
  "next": "https://www.metaculus.com/api/comments/?post=123&limit=10&offset=10",
  "previous": null,
  "results": [ /* 评论对象数组 */ ]
}
  • total_count
    — 根评论+子评论的总数
  • count
    — 仅根评论的数量
示例:
bash
curl -s "https://www.metaculus.com/api/comments/?post=12345&sort=-created_at&limit=20" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq .

POST /api/comments/create/ — Create a Comment

POST /api/comments/create/ — 创建评论

Request Body:
FieldTypeRequiredDescription
on_post
integerYesPost ID to comment on
text
stringYesComment content
included_forecast
booleanYesInclude the user's last forecast
is_private
booleanYesWhether the comment is private
parent
integerNoParent comment ID (for replies)
Example:
bash
curl -s -X POST "https://www.metaculus.com/api/comments/create/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "on_post": 12345,
    "text": "I updated my forecast based on the latest data.",
    "included_forecast": false,
    "is_private": false
  }'
Responses:
StatusDescription
201
Comment created successfully (returns Comment object)
400
Invalid request format

请求体:
字段类型必填描述
on_post
整数评论所属的帖子ID
text
字符串评论内容
included_forecast
布尔值是否包含用户的最新预测
is_private
布尔值评论是否为私有
parent
整数父评论ID(用于回复)
示例:
bash
curl -s -X POST "https://www.metaculus.com/api/comments/create/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "on_post": 12345,
    "text": "我根据最新数据更新了我的预测。",
    "included_forecast": false,
    "is_private": false
  }'
响应:
状态码描述
201
评论创建成功(返回评论对象)
400
请求格式无效

GET /api/posts/{postId}/download-data/ — Download Question Data

GET /api/posts/{postId}/download-data/ — 下载问题数据

Downloads forecast data as a ZIP file containing CSVs.
Path Parameters:
ParameterTypeDescription
postId
integerPost ID (the number after
/questions/
in the URL)
Query Parameters:
ParameterTypeRequiredDescription
sub_question
integerNoSub-question ID for group/conditional questions
aggregation_methods
string[]NoMethods to include:
recency_weighted
,
unweighted
,
metaculus_prediction
,
single_aggregation
. Default:
recency_weighted
only
include_bots
booleanNoInclude bot forecasts in aggregation recalculation
user_ids
string[]NoSpecific user IDs (whitelisted users only). Requires
aggregation_methods
.
minimize
booleanNoDefault:
true
. If
false
, includes all data points (may produce large files)
include_comments
booleanNoDefault:
false
. If
true
, adds
comment_data.csv
include_scores
booleanNoDefault:
false
. If
true
, adds
score_data.csv
ZIP Contents:
FileDescription
question_data.csv
Question metadata, scaling, resolution
forecast_data.csv
Individual and aggregated forecasts
comment_data.csv
Comments (if
include_comments=true
)
score_data.csv
Scores (if
include_scores=true
)
Example:
bash
curl -s "https://www.metaculus.com/api/posts/12345/download-data/?include_comments=true" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -o question_data.zip

以ZIP压缩包(内含CSV文件)的形式下载预测数据。
路径参数:
参数类型描述
postId
整数帖子ID(URL中
/questions/
后的数字)
查询参数:
参数类型必填描述
sub_question
整数问题组/条件式问题的子问题ID
aggregation_methods
string[]要包含的聚合方法:
recency_weighted
,
unweighted
,
metaculus_prediction
,
single_aggregation
。默认:仅
recency_weighted
include_bots
布尔值在重新计算聚合结果时是否包含机器人预测
user_ids
string[]指定用户ID(仅白名单用户可用)。需要同时指定
aggregation_methods
minimize
布尔值默认:
true
。如果为
false
,包含所有数据点(可能生成大文件)
include_comments
布尔值默认:
false
。如果为
true
,会添加
comment_data.csv
文件
include_scores
布尔值默认:
false
。如果为
true
,会添加
score_data.csv
文件
ZIP压缩包内容:
文件描述
question_data.csv
问题元数据、缩放规则、结果判定信息
forecast_data.csv
个人预测和聚合预测数据
comment_data.csv
评论数据(当
include_comments=true
时)
score_data.csv
评分数据(当
include_scores=true
时)
示例:
bash
curl -s "https://www.metaculus.com/api/posts/12345/download-data/?include_comments=true" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -o question_data.zip

GET /api/projects/{projectId}/download-data/ — Download Project Data

GET /api/projects/{projectId}/download-data/ — 下载项目数据

Downloads data for an entire project as a ZIP. Only available to site admins and whitelisted users.
Path Parameters:
ParameterTypeDescription
projectId
integerProject ID
Query Parameters:
ParameterTypeRequiredDescription
include_comments
booleanNoInclude comments CSV
include_scores
booleanNoInclude scores CSV

下载整个项目的完整数据(ZIP压缩包)。仅网站管理员和白名单用户可用。
路径参数:
参数类型描述
projectId
整数项目ID
查询参数:
参数类型必填描述
include_comments
布尔值是否包含评论CSV文件
include_scores
布尔值是否包含评分CSV文件

Generating Continuous CDFs

生成连续型CDF

Continuous, numeric, date, and discrete questions require forecasts as a CDF (Cumulative Distribution Function). This section explains how to generate valid CDFs.
连续型、数值型、日期型和离散型问题的预测需要以CDF(累积分布函数)格式提交。本节说明如何生成有效的CDF。

CDF Rules

CDF规则

  1. Length: The CDF must have exactly
    inbound_outcome_count + 1
    values. For most continuous questions, this is 201 values. For discrete questions, it depends on the question.
  2. Bounds:
    • If
      open_lower_bound == false
      (closed): first value must be 0.0
    • If
      open_lower_bound == true
      (open): first value must be ≥ 0.001 (at least 0.1% mass below lower bound)
    • If
      open_upper_bound == false
      (closed): last value must be 1.0
    • If
      open_upper_bound == true
      (open): last value must be ≤ 0.999 (at least 0.1% mass above upper bound)
  3. Monotonicity: The CDF must be strictly increasing by at least
    0.01 / inbound_outcome_count
    per step (i.e.,
    0.00005
    per step for the standard 200).
  4. Maximum step: No two adjacent values may differ by more than
    0.2 * (200 / inbound_outcome_count)
    .
  1. 长度: CDF必须包含恰好
    inbound_outcome_count + 1
    个值。对于大多数连续型问题,这个数量是201。对于离散型问题,数量取决于问题设置。
  2. 边界规则:
    • 如果
      open_lower_bound == false
      (闭区间):第一个值必须为0.0
    • 如果
      open_lower_bound == true
      (开区间):第一个值必须≥0.001(至少0.1%的概率质量低于下边界)
    • 如果
      open_upper_bound == false
      (闭区间):最后一个值必须为1.0
    • 如果
      open_upper_bound == true
      (开区间):最后一个值必须≤0.999(至少0.1%的概率质量高于上边界)
  3. 单调性: CDF必须严格递增,每一步的增量至少为
    0.01 / inbound_outcome_count
    (对于标准200的情况,每步至少0.00005)。
  4. 最大步长: 相邻两个值的差值不得超过
    0.2 * (200 / inbound_outcome_count)

Understanding Scaling

理解缩放规则

The CDF values correspond to evenly spaced points across the internal [0, 1] range. To map real-world values to CDF positions:
  • Linear scaling (
    zero_point
    is
    null
    ):
    internal = (value - range_min) / (range_max - range_min)
  • Logarithmic scaling (
    zero_point
    is set): requires log transformation (see function below)
  • Date questions: convert ISO dates to unix timestamps first, then apply scaling
CDF值对应内部[0,1]范围内的均匀间隔点。要将现实世界的值映射到CDF位置:
  • 线性缩放
    zero_point
    null
    ):
    internal = (value - range_min) / (range_max - range_min)
  • 对数缩放
    zero_point
    已设置):需要进行对数转换(见下文函数)
  • 日期问题:先将ISO日期转换为unix时间戳,再应用缩放规则

Python: Nominal Value to CDF Location

Python:实际值转CDF位置

python
import datetime
import numpy as np

def nominal_location_to_cdf_location(
    nominal_location: str | float,
    question_data: dict,
) -> float:
    """Takes a location in nominal format (e.g. 123, "123",
    or datetime in iso format) and scales it to metaculus's
    "internal representation" range [0,1] incorporating question scaling"""
    if question_data["type"] == "date":
        scaled_location = datetime.datetime.fromisoformat(
            nominal_location
        ).timestamp()
    else:
        scaled_location = float(nominal_location)
    scaling = question_data["scaling"]
    range_min = scaling.get("range_min")
    range_max = scaling.get("range_max")
    zero_point = scaling.get("zero_point")
    if zero_point is not None:
        # logarithmically scaled question
        deriv_ratio = (range_max - zero_point) / (range_min - zero_point)
        unscaled_location = (
            np.log(
                (scaled_location - range_min) * (deriv_ratio - 1)
                + (range_max - range_min)
            )
            - np.log(range_max - range_min)
        ) / np.log(deriv_ratio)
    else:
        # linearly scaled question
        unscaled_location = (scaled_location - range_min) / (
            range_max - range_min
        )
    return unscaled_location
python
import datetime
import numpy as np

def nominal_location_to_cdf_location(
    nominal_location: str | float,
    question_data: dict,
) -> float:
    """将实际格式的位置(例如123、"123"或ISO格式的日期)缩放为Metaculus的内部表示范围[0,1],并应用问题的缩放规则"""
    if question_data["type"] == "date":
        scaled_location = datetime.datetime.fromisoformat(
            nominal_location
        ).timestamp()
    else:
        scaled_location = float(nominal_location)
    scaling = question_data["scaling"]
    range_min = scaling.get("range_min")
    range_max = scaling.get("range_max")
    zero_point = scaling.get("zero_point")
    if zero_point is not None:
        # 对数缩放的问题
        deriv_ratio = (range_max - zero_point) / (range_min - zero_point)
        unscaled_location = (
            np.log(
                (scaled_location - range_min) * (deriv_ratio - 1)
                + (range_max - range_min)
            )
            - np.log(range_max - range_min)
        ) / np.log(deriv_ratio)
    else:
        # 线性缩放的问题
        unscaled_location = (scaled_location - range_min) / (
            range_max - range_min
        )
    return unscaled_location

Python: Generate CDF from Percentiles

Python:从分位数生成CDF

python
def generate_continuous_cdf(
    percentiles: dict,
    question_data: dict,
    below_lower_bound: float = None,
    above_upper_bound: float = None,
) -> list[float]:
    """
    Takes a set of percentiles and returns a corresponding CDF with
    inbound_outcome_count + 1 values (typically 201).

    percentiles: dict mapping percentile keys to nominal values
      Keys must end in a number interpretable as a float in (0, 100).
      Values are in the question's real-world scale.
      Example:
        {
          "percentile_05": 25,
          "percentile_25": 500,
          "percentile_50": 650,
          "percentile_75": 700,
          "percentile_95": 990,
        }

    below_lower_bound: probability mass below range_min (for open lower bound)
    above_upper_bound: probability mass above range_max (for open upper bound)
    """
    percentile_locations = []
    if below_lower_bound is not None:
        percentile_locations.append((0.0, below_lower_bound))
    if above_upper_bound is not None:
        percentile_locations.append((1.0, 1 - above_upper_bound))
    for percentile, nominal_location in percentiles.items():
        height = float(str(percentile).split("_")[-1]) / 100
        location = nominal_location_to_cdf_location(
            nominal_location, question_data
        )
        percentile_locations.append((location, height))
    percentile_locations.sort()
    first_point, last_point = percentile_locations[0], percentile_locations[-1]
    if (first_point[0] > 0.0) or (last_point[0] < 1.0):
        raise ValueError(
            "Percentiles must encompass bounds of the question"
        )

    def get_cdf_at(location):
        previous = percentile_locations[0]
        for i in range(1, len(percentile_locations)):
            current = percentile_locations[i]
            if previous[0] <= location <= current[0]:
                return previous[1] + (current[1] - previous[1]) * (
                    location - previous[0]
                ) / (current[0] - previous[0])
            previous = current

    n_points = (question_data.get("inbound_outcome_count") or 200) + 1
    continuous_cdf = [get_cdf_at(i / (n_points - 1)) for i in range(n_points)]
    return continuous_cdf
python
def generate_continuous_cdf(
    percentiles: dict,
    question_data: dict,
    below_lower_bound: float = None,
    above_upper_bound: float = None,
) -> list[float]:
    """
    根据分位数生成对应的CDF,包含inbound_outcome_count + 1个值(通常为201)。

    percentiles: 分位数键到实际值的映射
      键必须以可解析为(0,100)范围内浮点数的数字结尾。
      值为问题的现实世界单位。
      示例:
        {
          "percentile_05": 25,
          "percentile_25": 500,
          "percentile_50": 650,
          "percentile_75": 700,
          "percentile_95": 990,
        }

    below_lower_bound: 下边界以下的概率质量(用于开区间下边界)
    above_upper_bound: 上边界以上的概率质量(用于开区间上边界)
    """
    percentile_locations = []
    if below_lower_bound is not None:
        percentile_locations.append((0.0, below_lower_bound))
    if above_upper_bound is not None:
        percentile_locations.append((1.0, 1 - above_upper_bound))
    for percentile, nominal_location in percentiles.items():
        height = float(str(percentile).split("_")[-1]) / 100
        location = nominal_location_to_cdf_location(
            nominal_location, question_data
        )
        percentile_locations.append((location, height))
    percentile_locations.sort()
    first_point, last_point = percentile_locations[0], percentile_locations[-1]
    if (first_point[0] > 0.0) or (last_point[0] < 1.0):
        raise ValueError(
            "分位数必须覆盖问题的整个范围"
        )

    def get_cdf_at(location):
        previous = percentile_locations[0]
        for i in range(1, len(percentile_locations)):
            current = percentile_locations[i]
            if previous[0] <= location <= current[0]:
                return previous[1] + (current[1] - previous[1]) * (
                    location - previous[0]
                ) / (current[0] - previous[0])
            previous = current

    n_points = (question_data.get("inbound_outcome_count") or 200) + 1
    continuous_cdf = [get_cdf_at(i / (n_points - 1)) for i in range(n_points)]
    return continuous_cdf

Python: Standardize CDF for Submission

Python:标准化CDF以提交

This function ensures your CDF satisfies all validation rules. It adds a small linear component to guarantee monotonicity and respects bound constraints.
python
def standardize_cdf(cdf, question_data: dict):
    """
    Standardize a CDF for submission:
    - No mass outside closed bounds
    - Minimum mass outside open bounds
    - Strictly increasing by at least the minimum step
    - Caps maximum step size
    """
    lower_open = question_data["open_lower_bound"]
    upper_open = question_data["open_upper_bound"]
    inbound_outcome_count = question_data.get("inbound_outcome_count") or 200
    default_inbound_outcome_count = 200

    cdf = np.asarray(cdf, dtype=float)
    if not cdf.size:
        return []

    scale_lower_to = 0 if lower_open else cdf[0]
    scale_upper_to = 1.0 if upper_open else cdf[-1]
    rescaled_inbound_mass = scale_upper_to - scale_lower_to

    def standardize(F: float, location: float) -> float:
        rescaled_F = (F - scale_lower_to) / rescaled_inbound_mass
        if lower_open and upper_open:
            return 0.988 * rescaled_F + 0.01 * location + 0.001
        elif lower_open:
            return 0.989 * rescaled_F + 0.01 * location + 0.001
        elif upper_open:
            return 0.989 * rescaled_F + 0.01 * location
        return 0.99 * rescaled_F + 0.01 * location

    for i, value in enumerate(cdf):
        cdf[i] = standardize(value, i / (len(cdf) - 1))

    pmf = np.diff(cdf, prepend=0, append=1)
    cap = 0.2 * (default_inbound_outcome_count / inbound_outcome_count)

    def cap_pmf(scale: float) -> np.ndarray:
        return np.concatenate(
            [pmf[:1], np.minimum(cap, scale * pmf[1:-1]), pmf[-1:]]
        )

    def capped_sum(scale: float) -> float:
        return float(cap_pmf(scale).sum())

    lo = hi = scale = 1.0
    while capped_sum(hi) < 1.0:
        hi *= 1.2
    for _ in range(100):
        scale = 0.5 * (lo + hi)
        s = capped_sum(scale)
        if s < 1.0:
            lo = scale
        else:
            hi = scale
        if s == 1.0 or (hi - lo) < 2e-5:
            break

    pmf = cap_pmf(scale)
    pmf[1:-1] *= (cdf[-1] - cdf[0]) / pmf[1:-1].sum()
    cdf = np.cumsum(pmf)[:-1]
    cdf = np.round(cdf, 10)
    return cdf.tolist()
此函数确保你的CDF满足所有验证规则。它会添加一个小的线性分量以保证单调性,并遵守边界约束。
python
def standardize_cdf(cdf, question_data: dict):
    """
    标准化CDF以便提交:
    - 闭区间边界外无概率质量
    - 开区间边界外有最小概率质量
    - 严格递增且每步增量不小于最小值
    - 限制最大步长
    """
    lower_open = question_data["open_lower_bound"]
    upper_open = question_data["open_upper_bound"]
    inbound_outcome_count = question_data.get("inbound_outcome_count") or 200
    default_inbound_outcome_count = 200

    cdf = np.asarray(cdf, dtype=float)
    if not cdf.size:
        return []

    scale_lower_to = 0 if lower_open else cdf[0]
    scale_upper_to = 1.0 if upper_open else cdf[-1]
    rescaled_inbound_mass = scale_upper_to - scale_lower_to

    def standardize(F: float, location: float) -> float:
        rescaled_F = (F - scale_lower_to) / rescaled_inbound_mass
        if lower_open and upper_open:
            return 0.988 * rescaled_F + 0.01 * location + 0.001
        elif lower_open:
            return 0.989 * rescaled_F + 0.01 * location + 0.001
        elif upper_open:
            return 0.989 * rescaled_F + 0.01 * location
        return 0.99 * rescaled_F + 0.01 * location

    for i, value in enumerate(cdf):
        cdf[i] = standardize(value, i / (len(cdf) - 1))

    pmf = np.diff(cdf, prepend=0, append=1)
    cap = 0.2 * (default_inbound_outcome_count / inbound_outcome_count)

    def cap_pmf(scale: float) -> np.ndarray:
        return np.concatenate(
            [pmf[:1], np.minimum(cap, scale * pmf[1:-1]), pmf[-1:]]
        )

    def capped_sum(scale: float) -> float:
        return float(cap_pmf(scale).sum())

    lo = hi = scale = 1.0
    while capped_sum(hi) < 1.0:
        hi *= 1.2
    for _ in range(100):
        scale = 0.5 * (lo + hi)
        s = capped_sum(scale)
        if s < 1.0:
            lo = scale
        else:
            hi = scale
        if s == 1.0 or (hi - lo) < 2e-5:
            break

    pmf = cap_pmf(scale)
    pmf[1:-1] *= (cdf[-1] - cdf[0]) / pmf[1:-1].sum()
    cdf = np.cumsum(pmf)[:-1]
    cdf = np.round(cdf, 10)
    return cdf.tolist()

End-to-End Example: Submit a Continuous Forecast

端到端示例:提交连续型预测

python
import os, requests, numpy as np

TOKEN = os.environ["METACULUS_API_TOKEN"]
HEADERS = {"Authorization": f"Token {TOKEN}"}
BASE = "https://www.metaculus.com"
python
import os, requests, numpy as np

TOKEN = os.environ["METACULUS_API_TOKEN"]
HEADERS = {"Authorization": f"Token {TOKEN}"}
BASE = "https://www.metaculus.com"

1. Fetch the question

1. 获取问题详情

post_id = 12345 resp = requests.get(f"{BASE}/api/posts/{post_id}/", headers=HEADERS) resp.raise_for_status() post = resp.json() question = post["question"]
post_id = 12345 resp = requests.get(f"{BASE}/api/posts/{post_id}/", headers=HEADERS) resp.raise_for_status() post = resp.json() question = post["question"]

2. Define your percentile beliefs (in real-world units)

2. 定义你的分位数信念(现实世界单位)

percentiles = { "percentile_05": 25, "percentile_25": 40, "percentile_50": 55, "percentile_75": 70, "percentile_95": 90, }
percentiles = { "percentile_05": 25, "percentile_25": 40, "percentile_50": 55, "percentile_75": 70, "percentile_95": 90, }

3. Generate and standardize the CDF

3. 生成并标准化CDF

raw_cdf = generate_continuous_cdf( percentiles, question, below_lower_bound=0.01, above_upper_bound=0.01, ) final_cdf = standardize_cdf(raw_cdf, question)
raw_cdf = generate_continuous_cdf( percentiles, question, below_lower_bound=0.01, above_upper_bound=0.01, ) final_cdf = standardize_cdf(raw_cdf, question)

4. Submit

4. 提交预测

resp = requests.post( f"{BASE}/api/questions/forecast/", headers={**HEADERS, "Content-Type": "application/json"}, json=[{"question": question["id"], "continuous_cdf": final_cdf}], ) resp.raise_for_status() print("Forecast submitted!")

---
resp = requests.post( f"{BASE}/api/questions/forecast/", headers={**HEADERS, "Content-Type": "application/json"}, json=[{"question": question["id"], "continuous_cdf": final_cdf}], ) resp.raise_for_status() print("预测提交成功!")

---

Common Patterns

常见使用模式

Browse the Feed

浏览信息流

bash
undefined
bash
undefined

Newest open questions

最新的开放问题

curl -s "https://www.metaculus.com/api/posts/?statuses=open&order_by=-published_at&limit=10&with_cp=true"
-H "Authorization: Token $METACULUS_API_TOKEN" | jq '.results[] | {id, title, status}'
undefined
curl -s "https://www.metaculus.com/api/posts/?statuses=open&order_by=-published_at&limit=10&with_cp=true"
-H "Authorization: Token $METACULUS_API_TOKEN" | jq '.results[] | {id, title, status}'
undefined

Get Community Prediction for a Post

获取帖子的社区预测

bash
curl -s "https://www.metaculus.com/api/posts/12345/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  | jq '.question.aggregations.recency_weighted.latest'
bash
curl -s "https://www.metaculus.com/api/posts/12345/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  | jq '.question.aggregations.recency_weighted.latest'

Find Trending Questions

查找热门问题

bash
curl -s "https://www.metaculus.com/api/posts/?order_by=-hotness&statuses=open&limit=10&with_cp=true" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq '.results[] | {id, title}'
bash
curl -s "https://www.metaculus.com/api/posts/?order_by=-hotness&statuses=open&limit=10&with_cp=true" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq '.results[] | {id, title}'

Find Questions by Category

按分类查找问题

bash
curl -s "https://www.metaculus.com/api/posts/?categories=nuclear&statuses=open&with_cp=true&limit=10" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq '.results[] | {id, title}'
bash
curl -s "https://www.metaculus.com/api/posts/?categories=nuclear&statuses=open&with_cp=true&limit=10" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq '.results[] | {id, title}'

Find Questions in a Tournament

查找锦标赛中的问题

bash
curl -s "https://www.metaculus.com/api/posts/?tournaments=aibq3&with_cp=true&limit=50" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq '.results[] | {id, title, status}'
bash
curl -s "https://www.metaculus.com/api/posts/?tournaments=aibq3&with_cp=true&limit=50" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq '.results[] | {id, title, status}'

Submit a Binary Forecast

提交二元问题预测

bash
curl -s -X POST "https://www.metaculus.com/api/questions/forecast/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{"question": 12345, "probability_yes": 0.75}]'
bash
curl -s -X POST "https://www.metaculus.com/api/questions/forecast/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{"question": 12345, "probability_yes": 0.75}]'

Submit a Multiple Choice Forecast

提交多选问题预测

bash
curl -s -X POST "https://www.metaculus.com/api/questions/forecast/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{
    "question": 12345,
    "probability_yes_per_category": {
      "Option A": 0.4,
      "Option B": 0.35,
      "Option C": 0.25
    }
  }]'
bash
curl -s -X POST "https://www.metaculus.com/api/questions/forecast/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{
    "question": 12345,
    "probability_yes_per_category": {
      "选项A": 0.4,
      "选项B": 0.35,
      "选项C": 0.25
    }
  }]'

Withdraw a Forecast

撤回预测

bash
curl -s -X POST "https://www.metaculus.com/api/questions/withdraw/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{"question": 12345}]'
bash
curl -s -X POST "https://www.metaculus.com/api/questions/withdraw/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{"question": 12345}]'

Read Comments on a Post

查看帖子的评论

bash
curl -s "https://www.metaculus.com/api/comments/?post=12345&sort=-created_at&limit=20" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq '.results[] | {author: .author.username, text: .text}'
bash
curl -s "https://www.metaculus.com/api/comments/?post=12345&sort=-created_at&limit=20" \
  -H "Authorization: Token $METACULUS_API_TOKEN" | jq '.results[] | {author: .author.username, text: .text}'

Post a Comment

发布评论

bash
curl -s -X POST "https://www.metaculus.com/api/comments/create/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "on_post": 12345,
    "text": "My analysis suggests a higher probability because...",
    "included_forecast": true,
    "is_private": false
  }'
bash
curl -s -X POST "https://www.metaculus.com/api/comments/create/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "on_post": 12345,
    "text": "我的分析表明概率更高,因为...",
    "included_forecast": true,
    "is_private": false
  }'

Reply to a Comment

回复评论

bash
curl -s -X POST "https://www.metaculus.com/api/comments/create/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "on_post": 12345,
    "parent": 67890,
    "text": "Good point — I updated my forecast accordingly.",
    "included_forecast": false,
    "is_private": false
  }'
bash
curl -s -X POST "https://www.metaculus.com/api/comments/create/" \
  -H "Authorization: Token $METACULUS_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "on_post": 12345,
    "parent": 67890,
    "text": "好观点——我已相应更新了我的预测。",
    "included_forecast": false,
    "is_private": false
  }'

Python: Paginate Through All Open Questions

Python:分页获取所有开放问题

python
import os, requests

TOKEN = os.environ["METACULUS_API_TOKEN"]
HEADERS = {"Authorization": f"Token {TOKEN}"}
BASE = "https://www.metaculus.com"

all_posts = []
offset = 0
limit = 100

while True:
    resp = requests.get(
        f"{BASE}/api/posts/",
        headers=HEADERS,
        params={
            "statuses": "open",
            "limit": limit,
            "offset": offset,
            "with_cp": True,
        },
    )
    resp.raise_for_status()
    data = resp.json()
    results = data["results"]
    all_posts.extend(results)
    if data["next"] is None:
        break
    offset += limit

print(f"Fetched {len(all_posts)} open posts")
python
import os, requests

TOKEN = os.environ["METACULUS_API_TOKEN"]
HEADERS = {"Authorization": f"Token {TOKEN}"}
BASE = "https://www.metaculus.com"

all_posts = []
offset = 0
limit = 100

while True:
    resp = requests.get(
        f"{BASE}/api/posts/",
        headers=HEADERS,
        params={
            "statuses": "open",
            "limit": limit,
            "offset": offset,
            "with_cp": True,
        },
    )
    resp.raise_for_status()
    data = resp.json()
    results = data["results"]
    all_posts.extend(results)
    if data["next"] is None:
        break
    offset += limit

print(f"已获取{len(all_posts)}个开放帖子")

Python: Find Questions with Large Movement

Python:查找变化较大的问题

python
import os, requests

TOKEN = os.environ["METACULUS_API_TOKEN"]
HEADERS = {"Authorization": f"Token {TOKEN}"}
BASE = "https://www.metaculus.com"

resp = requests.get(
    f"{BASE}/api/posts/",
    headers=HEADERS,
    params={
        "statuses": "open",
        "order_by": "-weekly_movement",
        "forecast_type": "binary",
        "with_cp": True,
        "limit": 10,
    },
)
resp.raise_for_status()
for post in resp.json()["results"]:
    q = post.get("question")
    if q and q.get("aggregations"):
        latest = q["aggregations"].get("recency_weighted", {}).get("latest")
        if latest:
            prob = latest.get("centers", [None])[0]
            print(f"[{post['id']}] {post['title']} — CP: {prob}")

python
import os, requests

TOKEN = os.environ["METACULUS_API_TOKEN"]
HEADERS = {"Authorization": f"Token {TOKEN}"}
BASE = "https://www.metaculus.com"

resp = requests.get(
    f"{BASE}/api/posts/",
    headers=HEADERS,
    params={
        "statuses": "open",
        "order_by": "-weekly_movement",
        "forecast_type": "binary",
        "with_cp": True,
        "limit": 10,
    },
)
resp.raise_for_status()
for post in resp.json()["results"]:
    q = post.get("question")
    if q and q.get("aggregations"):
        latest = q["aggregations"].get("recency_weighted", {}).get("latest")
        if latest:
            prob = latest.get("centers", [None])[0]
            print(f"[{post['id']}] {post['title']} — 社区预测概率: {prob}")

Question Type Quick Reference

问题类型速查

TypeForecast FormatKey Fields
binary
probability_yes: float
(0–1)
multiple_choice
probability_yes_per_category: {option: float}
(sum = 1.0)
options
,
all_options_ever
numeric
continuous_cdf: float[]
(201 values)
scaling
,
open_lower_bound
,
open_upper_bound
,
unit
date
continuous_cdf: float[]
(201 values)
scaling
(range_min/max are unix timestamps)
discrete
continuous_cdf: float[]
(
inbound_outcome_count + 1
values)
inbound_outcome_count
,
scaling

类型预测格式关键字段
binary
probability_yes: float
(0–1)
multiple_choice
probability_yes_per_category: {option: float}
(总和=1.0)
options
,
all_options_ever
numeric
continuous_cdf: float[]
(201个值)
scaling
,
open_lower_bound
,
open_upper_bound
,
unit
date
continuous_cdf: float[]
(201个值)
scaling
(range_min/range_max为unix时间戳)
discrete
continuous_cdf: float[]
inbound_outcome_count + 1
个值)
inbound_outcome_count
,
scaling

Post Status Lifecycle

帖子状态生命周期

draft → pending → approved → open → closed → resolved
                → rejected
StatusDescription
draft
Author is still editing
pending
Submitted for curation review
rejected
Rejected by curators
open
Approved and accepting forecasts
upcoming
Approved but not yet open for forecasting
closed
No longer accepting forecasts; awaiting resolution
resolved
Final outcome determined

draft → pending → approved → open → closed → resolved
                → rejected
状态描述
draft
作者仍在编辑中
pending
已提交等待审核
rejected
被审核人员拒绝
open
已通过审核并开放预测
upcoming
已通过审核但尚未开放预测
closed
停止接受预测,等待结果判定
resolved
已确定最终结果

Error Handling

错误处理

Status CodeMeaningAction
200
Success
201
Created
400
Bad requestCheck request format, CDF validity, required fields
401
UnauthorizedCheck your
Authorization: Token ...
header
403
ForbiddenYou don't have permission (e.g., project data download)
404
Not foundCheck the post/question/project ID
429
Rate limitedImplement exponential backoff and retry
500
Server errorRetry after a delay; if persistent, contact Metaculus

状态码含义处理方式
200
请求成功
201
创建成功
400
请求格式错误检查请求格式、CDF有效性、必填字段
401
未授权检查
Authorization: Token ...
请求头
403
禁止访问你无此权限(例如:下载项目数据)
404
资源不存在检查帖子/问题/项目ID
429
请求频率超限实现指数退避机制后重试
500
服务器错误延迟后重试;如果持续出现,联系Metaculus团队

Usage Tips

使用技巧

  • Always pass
    with_cp=true
    when listing posts if you need community predictions — aggregations are empty by default.
  • Use
    include_cp_history=true
    only when you need historical CP data — it increases response size significantly.
  • Use
    include_descriptions=true
    only when needed — descriptions can be large.
  • Question ID ≠ Post ID — Forecasts use the
    question.id
    , not the
    post.id
    . Always fetch the post first to get the question ID.
  • For group posts,
    with_cp=true
    on the list endpoint only returns CP for the top 3 sub-questions. Use the detail endpoint (
    /api/posts/{postId}/
    ) for all sub-questions.
  • CDF generation is the trickiest part — use the provided Python functions or adapt them. Always run
    standardize_cdf()
    before submitting.
  • Combine filters for targeted queries — e.g.,
    statuses=open&forecast_type=binary&categories=nuclear
    narrows results efficiently.
  • Paginate responsibly — use
    limit
    and
    offset
    . Don't fetch all posts at once.
  • The
    order_by=score
    sort requires
    forecaster_id
    — it ranks questions by a specific user's performance.
  • Date questions use unix timestamps in
    scaling.range_min
    and
    scaling.range_max
    — convert ISO dates to timestamps before mapping to CDF locations.
  • Respect rate limits — implement backoff when you receive 429 responses.

  • 始终添加
    with_cp=true
    :如果你需要社区预测,在列出帖子时必须添加此参数——聚合结果默认是空的。
  • 仅在需要时使用
    include_cp_history=true
    :它会显著增加响应大小。
  • 仅在需要时使用
    include_descriptions=true
    :描述内容可能很大。
  • 问题ID ≠ 帖子ID:提交预测时使用
    question.id
    ,而非
    post.id
    。请始终先获取帖子详情以获取问题ID。
  • 对于问题组帖子:列表接口的
    with_cp=true
    仅返回前3个子问题的社区预测。如需所有子问题的社区预测,请使用详情接口(
    /api/posts/{postId}/
    )。
  • CDF生成是最复杂的部分:使用提供的Python函数或进行适配。提交前请务必运行
    standardize_cdf()
  • 组合筛选条件以进行精准查询——例如:
    statuses=open&forecast_type=binary&categories=nuclear
    可高效缩小结果范围。
  • 合理分页:使用
    limit
    offset
    参数。请勿一次性获取所有帖子。
  • order_by=score
    排序需要
    forecaster_id
    :它会按特定用户的预测表现对问题排序。
  • 日期问题的
    scaling.range_min
    scaling.range_max
    使用unix时间戳
    :在映射到CDF位置前,请将ISO日期转换为时间戳。
  • 遵守请求频率限制:当收到429响应时,请实现退避机制。

Resources

资源

ResourceURL
Metaculus Platformmetaculus.com
API Documentationmetaculus.com/api
Account Settings (API Token)metaculus.com/accounts/settings
GitHub Issuesgithub.com/Metaculus/metaculus
Contactapi-requests@metaculus.com
资源URL
Metaculus平台metaculus.com
API文档metaculus.com/api
账户设置(API Token)metaculus.com/accounts/settings
GitHub问题反馈github.com/Metaculus/metaculus
联系方式api-requests@metaculus.com