Create forecasts in bulk from a template
Validate a CSV of company names, preview every rendered draft, then create the forecasts one at a time with a resumable checkpoint.
Create one forecast per row of a spreadsheet from a single template, using the draft-then-create steps for each row.
Full script: bulk_create_questions.py.
Drafts can't be event, so a yes/no forecast is a categorical draft with Yes and No categories.
Prepare the CSV
Export the spreadsheet as a UTF-8 CSV with a company_name column:
company_name
ASML Holding
Novo Nordisk
Siemens EnergyDefine the template
question_for renders one draft body per company. Write the resolution criteria in clarifications; creation fails without them:
return {
"title": f"Will {company_name} announce a share buyback before 31 December 2027?",
"type": "categorical",
"categories": ["Yes", "No"],
"supplementary_information": (
f"Use announcements made by {company_name} or its investor-relations team."
),
"clarifications": (
"Resolve Yes if the company publicly announces a new share-buyback "
"authorisation on or before 2027-12-31 23:59:59 UTC. Exclude routine "
"purchases under an authorisation announced before the question was created; "
"otherwise resolve No."
),
}Validate and preview
The script checks the CSV for a missing column, blank names and duplicates before sending anything. Without --apply, it prints every rendered title and stops:
python bulk_create_questions.py companies.csvCheck them before you continue.
Create the forecasts
With --apply, the script creates a draft for each company that does not have one yet, and saves its ID to question_creation_results.csv straight away. For a draft saved by an earlier run, it replaces the draft with the current template using PUT /beta/question-drafts/{question_draft_id}, so fixes to the template reach the draft:
if not result["draft_id"]:
response = client.request("POST", "/beta/question-drafts", json=question_for(company))
result["draft_id"] = str(response.json()["id"])
results[company] = result
write_results(results_path, results)
else:
# A saved draft from an earlier run: replace it with the current template
draft_path = f"/beta/question-drafts/{result['draft_id']}"
client.request("PUT", draft_path, json=question_for(company))It then creates the forecast from that draft with POST /beta/questions and saves the new forecast's question_id:
response = client.request(
"POST", "/beta/questions", json={"question_draft_id": int(result["draft_id"])}
)
result["question_id"] = str(response.json()["id"])
write_results(results_path, results)
print(f"Created {company}: forecast {result['question_id']}")python bulk_create_questions.py companies.csv --applyA rerun skips companies that already have a forecast.
Handle failures
Don't auto-retry POST /beta/question-drafts: after a dropped connection you can't tell whether the draft was saved, and a retry can create a second one. Check GET /beta/question-drafts and rerun.
When POST /beta/questions fails, the script stops with an exception:
422: the draft is not ready, for example it has no clarifications. Fix the template and rerun; the rerun sends the fixed template to the saved draft.409: the draft has already created a forecast. Thedetailusually names itsquestion_id; add it toquestion_creation_results.csv, then rerun.429: you've used your forecast-creation allowance; waitRetry-Afterseconds, then rerun.