Batch processing
Use batch processing for large portfolios or high-volume workloads that should be processed asynchronously in the background.
The batch API accepts the same payload as POST /portfolios, returns a batch_id, and lets you track progress until processing completes.
Overview
The typical flow is:
- Submit a portfolio to
POST /portfolios/batch - Poll
GET /portfolios/batch/{batch_id}until the batch reaches a terminal state - Fetch the resulting account outputs from
GET /results/accounts - Filter those results to the account codes that belonged to the submitted batch
This workflow is useful when:
- the portfolio is large
- you want background processing instead of waiting on a synchronous response
- you want queueing and progress tracking
How It Works
Batch submission returns:
{
"batch_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
You then poll the batch status endpoint until status becomes one of:
completedfailedcompleted_with_errors
Once the batch completes, the results are written into the user's live portfolio store. The updated public Python example then retrieves the latest per-account results using GET /results/accounts.
Submit the batch
POST /portfolios/batch accepts the same JSON payload as POST /portfolios.
Example request:
{
"calculation_type": "margins",
"vendor_symbology": "clearing",
"portfolio": [
{
"account_code": "account_0000",
"exchange_code": "ICE.EU",
"contract_code": "B",
"contract_type": "FUT",
"contract_expiry": "203212",
"net_position": "100",
"account_type": "H"
}
]
}
The batch endpoint also supports the x-processing-mode header:
fifopriorityreplace_all
Poll batch status
Use GET /portfolios/batch/{batch_id} to check progress.
Example response:
{
"batch_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "processing",
"queue_position": 0,
"created_at": "2025-01-03T09:31:14Z",
"completed_at": null,
"runtime_ms": 4523,
"completed_pct": 67.5
}
Poll until status is:
completedfailedcompleted_with_errors
If the batch fails, stop there and do not attempt to fetch results.
Fetch results
The updated public Python example shows the next step after completion:
results_response = requests.get(f"{C9_API_ENDPOINT}/results/accounts", headers=HEADERS)
results_response.raise_for_status()
accounts = results_response.json()
submitted = set(account_codes)
batch_accounts = [a for a in accounts if a["account_code"] in submitted]
This means:
GET /results/accountsreturns the latest calculation for every live account owned by the caller- your client should keep track of the submitted
account_codevalues - after the batch completes, filter the returned accounts down to the ones from that batch
The public example then:
- prints how many account results were fetched
- calculates total initial margin across the batch
- lists the top 5 accounts by initial margin
Because GET /results/accounts returns the caller's live account results,
you should explicitly filter by the account codes that were submitted in the
batch.