Forecast the next release
Find a country's upcoming economic releases, read a release's forecast, and compare it with consensus, the prior value and the published actual.
An economic indicator is a recurring series, such as US CPI. Each scheduled release can have a Mantic forecast.
Full script: next_release.py.
Find a release
Call GET /economics/indicators with the exact country name that Mantic stores:
curl --get "https://api.mantic.com/economics/indicators" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
--data-urlencode "country=United States" \
--data-urlencode "show_forecasts=true"The response pairs each indicator with its next release, the nearest one whose planned_release_date is now or later:
{
"indicators": [
{
"id": 41,
"name": "Consumer Price Index",
"country": "United States",
"unit": "% YoY",
"frequency": "monthly",
"next_release": {
"id": 8032,
"planned_release_date": "2026-10-13T12:30:00Z",
"reference_period_date": "2026-09-01",
"latest_forecast": null
}
}
],
"next": {
"next_release_at": "2026-10-13T12:30:00Z",
"id": 41
}
}reference_period_date is the period measured (September); planned_release_date is when it is published (13 October).
Indicators come soonest release first, 25 per page; those with no upcoming release follow, with next_release: null. country must match exactly: United States, not US.
To collect every upcoming release, page until next is null:
from mantic_client import ManticClient, paginate
client = ManticClient()
params = {"country": "United States", "show_forecasts": "true"}
try:
indicators = paginate(client, "/economics/indicators", "indicators", params)
upcoming = [indicator for indicator in indicators if indicator["next_release"] is not None]
finally:
client.close()
for indicator in upcoming:
release = indicator["next_release"]
unit = indicator["unit"] or "unit not supplied"
cadence = f"({indicator['frequency']}, {unit})"
print(release["planned_release_date"], indicator["name"], cadence)Read the release forecast
Fetch a release by its ID (next_release.id above) with GET /economics/releases/{release_id} and forecast values:
curl --get "https://api.mantic.com/economics/releases/RELEASE_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
--data-urlencode "show_forecasts=true"latest_forecast is the newest run of the release's forecast, usually numerical; latest_forecast.question is the forecast itself:
{
"indicator": {
"id": 41,
"name": "Consumer Price Index",
"country": "United States",
"unit": "% YoY",
"frequency": "monthly"
},
"id": 8032,
"planned_release_date": "2026-10-13T12:30:00Z",
"reference_period_date": "2026-09-01",
"latest_forecast": {
"id": 9918,
"date": "2026-10-12T08:15:00Z",
"type": "numerical",
"percentiles": { "25": 2.8, "50": 3.0, "75": 3.2 },
"thresholds": null,
"intervals": null,
"question": {
"id": 22104,
"title": "What will US CPI be for September 2026?",
"url": "https://app.mantic.com/question/22104"
}
}
}Values are in the indicator's unit, e.g. 3.0 % YoY. latest_forecast is null until the first run completes.
Compare with consensus and the prior value
The API doesn't supply consensus or the prior value; bring your own, in the indicator's unit.
To get exact probabilities, sample the latest run's CDF at both values in one request, using latest_forecast.id. Suppose consensus is 3.1 and the prior release was 3.0, both in % YoY:
curl --get "https://api.mantic.com/forecasts/9918/cdf" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
--data-urlencode 'ticks=[3.1,3.0]'{
"cdf": {
"3.0": 0.5,
"3.1": 0.64
}
}The CDF gives the probability at or below each value, so the probability of a release above consensus is 1 - 0.64 = 36%, and above the prior value 50%.
Keys are strings, so match them as numbers:
cdf = client.request(
"GET", f"/forecasts/{forecast_id}/cdf", params={"ticks": json.dumps(values)}
).json()["cdf"]
at_or_below = {float(tick): probability for tick, probability in cdf.items()}
return {value: 1.0 - at_or_below[float(value)] for value in values}Compare with the actual after publication
The published actual is the forecast's resolution. After the release, fetch the forecast with GET /questions/{question_id}, using latest_forecast.question.id:
curl "https://api.mantic.com/questions/22104" \
-H "Authorization: Bearer $ACCESS_TOKEN"resolution is null until the forecast resolves. Then it looks like this:
{
"resolution": {
"resolved_at": "2026-10-13T12:31:20Z",
"value": "3.2",
"notes": "Published value for the September 2026 reference period."
}
}value is a string, because forecasts can resolve to non-numerical outcomes. Parse it only after checking it is a number:
try:
question = client.request("GET", f"/questions/{question_id}").json()
except httpx.HTTPStatusError as error:
if error.response.status_code == 404:
return None # Not found, or no completed run yet.
raise
resolution = question["resolution"]
if resolution is None or resolution["value"] is None:
return None
try:
return Decimal(resolution["value"])
except InvalidOperation:
raise ValueError(f"Resolution {resolution['value']!r} is not a number") from NoneThen compare the actual with the run's median, consensus and prior value, using Decimal to avoid floating-point noise:
try:
actual = actual_value(client, forecast["question"]["id"])
except ValueError as error:
print(f"Can't compare with the actual: {error}")
return
if actual is None:
print("Actual not published yet")
return
print(f"Actual: {actual} {unit}".rstrip())
median = forecast["percentiles"].get("50")
if median is None:
print("Median unavailable for this run")
else:
print(f"Actual minus median: {actual - Decimal(str(median))}")
print(f"Actual minus consensus: {actual - Decimal(str(args.consensus))}")
print(f"Actual minus prior: {actual - Decimal(str(args.prior))}")Run the full script with your consensus and prior values:
python next_release.py RELEASE_ID --consensus 3.1 --prior 3.0Check past forecasts against outcomes
Rebuild what a numerical forecast said on each day before its outcome, and measure how often the outcome fell inside its ranges.
Compare conditional outcomes
Compare a forecast's yes and no scenario branches, and sample both conditional distributions at the same value.