ManticDocs
Economic releases

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 None

Then 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.0

On this page