Compare conditional outcomes
Compare a forecast's yes and no scenario branches, and sample both conditional distributions at the same value.
A scenario shows a forecast twice: if a related event happens, and if it does not. These are the scenarios on a forecast's page in the Mantic web app.
Full script: conditional_outcomes.py.
Suppose the base forecast is the Bank of Japan's (BoJ) policy rate after a meeting, and the condition forecast is whether the Federal Reserve (Fed) will cut rates before then. A scenario gives you three things:
base: a run of the BoJ forecast, without any condition;condition: a run of the forecast for whether the Fed cuts, withcondition.questionidentifying that forecast;outcomes.yesandoutcomes.no: the BoJ distribution if the Fed does or does not cut.
Scenarios describe conditional outcomes, not causal effects. Read each branch as "the base forecast, given this condition".
Find the conditional outcomes
Call GET /questions/{question_id}/scenarios with the base forecast's question_id:
curl --get "https://api.mantic.com/questions/QUESTION_ID/scenarios" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
--data-urlencode "show_forecasts=true"Each item in scenarios looks like this:
{
"id": 731,
"base": {
"id": 12041,
"date": "2026-09-22T08:12:00Z",
"type": "numerical",
"percentiles": { "25": 0.25, "50": 0.5, "75": 0.75 },
"thresholds": null,
"intervals": null
},
"condition": {
"question": {
"id": 19008,
"title": "Will the Federal Reserve cut rates before the BoJ's December meeting?",
"url": "https://app.mantic.com/question/19008"
},
"id": 12042,
"date": "2026-09-22T08:12:00Z",
"type": "event",
"probability": 0.46,
"by": "2026-12-17T23:59:59Z"
},
"outcomes": {
"yes": {
"label": "The Fed cuts rates before the BoJ meeting",
"forecast": {
"date": "2026-09-22T08:12:00Z",
"type": "numerical",
"percentiles": { "25": 0.25, "50": 0.5, "75": 0.75 },
"thresholds": null,
"intervals": null
}
},
"no": {
"label": "The Fed does not cut rates before the BoJ meeting",
"forecast": {
"date": "2026-09-22T08:12:00Z",
"type": "numerical",
"percentiles": { "25": 0.5, "50": 0.75, "75": 1.0 },
"thresholds": null,
"intervals": null
}
}
}
}Show each branch's label; it says what the branch assumes. The condition's probability is the chance the Fed cuts, not the chance of either branch.
Most forecasts have no scenarios, so an empty scenarios array is normal. The script reads every page and keeps scenarios whose base and both branches are numerical:
scenarios = paginate(
client,
f"/questions/{question_id}/scenarios",
"scenarios",
{"show_forecasts": "true"},
)
return [
scenario
for scenario in scenarios
if scenario["base"] is not None
and scenario["base"]["type"] == "numerical"
and all(
outcome["forecast"] is not None and outcome["forecast"]["type"] == "numerical"
for outcome in scenario["outcomes"].values()
)
]Sample both conditional distributions
The outcome summaries give percentiles. To get the probability at the same threshold for both branches, call GET /scenarios/{scenario_id}/cdfs with ticks as a JSON-encoded array:
curl --get "https://api.mantic.com/scenarios/731/cdfs" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
--data-urlencode 'ticks=[0.5,0.75]'{
"outcomes": {
"yes": { "cdf": { "0.5": 0.69, "0.75": 0.86 } },
"no": { "cdf": { "0.5": 0.38, "0.75": 0.61 } }
}
}Each value is the chance the BoJ rate is at or below the tick, in that branch. Keys are strings, so match them as numbers:
outcomes = client.request(
"GET",
f"/scenarios/{scenario_id}/cdfs",
params={"ticks": json.dumps([threshold])},
).json()["outcomes"]
return {
branch: next(
probability for tick, probability in outcome["cdf"].items() if float(tick) == threshold
)
for branch, outcome in outcomes.items()
}This endpoint works only when the base forecast is numerical.
Render the if–then table
The probability strictly above a tick is 1 - CDF(tick). The script builds one row per branch, with the branch label, its median and that probability:
lines = [
f"| If… | Then the base median is… | P(above {threshold:g}) |",
"| --- | ---: | ---: |",
]
for branch in ("yes", "no"):
outcome = scenario["outcomes"][branch]
median = outcome["forecast"]["percentiles"].get("50")
shown = "unavailable" if median is None else f"{median:g}"
lines.append(f"| {outcome['label']} | {shown} | {1.0 - at_or_below[branch]:.0%} |")
return "\n".join(lines)Run it with the base forecast's question_id and your threshold:
python conditional_outcomes.py QUESTION_ID --threshold 0.5At 0.5, the example response gives:
| If… | Then the base median is… | P(above 0.5) |
|---|---|---|
| The Fed cuts rates before the BoJ meeting | 0.5 | 31% |
| The Fed does not cut rates before the BoJ meeting | 0.75 | 62% |
Weight the branches by your own probability
Mantic reconciles each scenario's branches with the base forecast. Weighting the branches by the condition's own probability, p, gives back the base forecast exactly: p × CDF_yes + (1 − p) × CDF_no = CDF_base. In the example, 0.46 × 0.69 + 0.54 × 0.38 = 0.52, the base forecast's chance that the BoJ rate is at or below 0.5.
Use a different probability to see the base forecast under your view of the condition:
return chance * at_or_below["yes"] + (1.0 - chance) * at_or_below["no"]Pass it with --chance:
python conditional_outcomes.py QUESTION_ID --threshold 0.5 --chance 0.8If you think the Fed is 80% likely to cut, the chance the BoJ rate is above 0.5 is 1 − (0.8 × 0.69 + 0.2 × 0.38) = 37%, compared with 48% at the condition's own 46%.
--chance is your probability for the yes label. A numerical condition has percentiles, not a probability; its yes label says what your number refers to.
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.
Forecast with your own context
Run a forecast that takes your facts or assumptions into account, wait for it to complete, and compare it with the forecast without them.