Ongoing Data
You can request the latest data in three distinct ways via the API, depending on your needs for timing and granularity:
Type | Frequency | Availability (UTC) | Timezone Specific Times |
---|---|---|---|
Last Settlement | Daily | After midnight UTC | - London 16:30 |
Last Assessments | Daily (3 datapoints) | After midnight UTC | - Singapore 16:30 - London 16:30 - New York 14:30 |
Intraday | Every 15 mins | Real-time | - From 2:00 UTC to 20:00 UTC |
Last Settlement
The last settlement reflects the final published value for the day. It is captured daily at the following local time:
- 16:30 London (or 12:30 on early close days)
The data becomes available after midnight UTC.
Last Settlement for tenor
The last settlement data can be queried for a given tenor:
ExampleGET
/ongoing/last-settlement/0007f4dd-673a-5309-b606-178aadbd2d2c/11-15 Jun 25
{ "generatedOn": "2025-05-16T15:16:05.173", "price": 3.5788883413888546, "units": "$/mt", "tenor": "11-15 Jun 25", "dependencies": [ { "id": "dd758b98-0227-5e68-8529-b35307373d27", "name": "RAS LAFFAN - BARCELONA VIACAPE Jet-A1 LR2 - Dlvd Price by Load", "value": -0.5788883413888545, "units": "$/mt", "tenorName": "11-15 Jun 25" }, { "id": "cdc954af-529e-5f98-8a2e-c3543a2cbe81", "name": "RAS LAFFAN - BARCELONA VIACAPE Jet-A1 LR2 - Sales Price", "value": 3.0, "units": "$/mt", "tenorName": "21-25 Jul 25" } ], "metadata": [ { "name": "loadDate", "value": "2025-06-15T00:00:00.000Z" }, { "name": "deliveryDate", "value": "2025-07-25T00:00:00.000Z" } // ... ] }
Last Settlement for all tenors
The last settlement data can also be queried for all available tenors:
ExampleGET
/ongoing/last-settlement/03d82381-a711-5077-b8ba-f60b2047ae11
{ "items": [ { "generatedOn": "2025-08-15T15:15:00.000458", "price": 1.8, "units": "$/bbl", "tenor": "1-5 Dec 25", "dependencies": [ { "id": "c4b52b35-1bc1-5f12-9fc5-40bc9727bd09", "name": "Indonesia 92 RON Grade - SING", "value": 1.7771965966071783, "units": "$/bbl", "tenorName": "1-5 Dec 25" }, { "id": "bbad8d31-e1c0-5ac3-88e5-40ffcd17bc42", "name": "SING - Indonesia 92 RON - SING FOB - Freight Costs - By Load", "value": 0.03592, "units": "$/bbl", "tenorName": "1-5 Dec 25" } ], "metadata": [ { "name": "monthName", "value": "Dec 25" }, { "name": "monthNumber", "value": "12" }, // ... additional metadata ] }, // ... additional items ] }
Last Assessments
The last assessments are captured at a consistent daily time across three regional markets:
- 16:30 Singapore (12:30 early close)
- 16:30 London (12:30 early close)
- 14:30 New York (13:30 early close)
The latest assessment data is available after midnight UTC.
Last Assessments for tenor
The last assessments data can be queried for a given tenors:
ExampleGET
/ongoing/last-assessments/0007f4dd-673a-5309-b606-178aadbd2d2c/11-15 Jun 25
{ "singaporeSnapshot": { "generatedOn": "2025-05-16T08:16:04.515", "price": 5.615760777686308, "units": "$/mt", "tenor": "11-15 Jun 25", "dependencies": [ { "id": "dd758b98-0227-5e68-8529-b35307373d27", "name": "RAS LAFFAN - BARCELONA VIACAPE Jet-A1 LR2 - Dlvd Price by Load", "value": -2.615760777686308, "units": "$/mt", "tenorName": "11-15 Jun 25" }, { "id": "cdc954af-529e-5f98-8a2e-c3543a2cbe81", "name": "RAS LAFFAN - BARCELONA VIACAPE Jet-A1 LR2 - Sales Price", "value": 3.0, "units": "$/mt", "tenorName": "21-25 Jul 25" } ], "metadata": [ { "name": "loadDate", "value": "2025-06-15T00:00:00.000Z" }, { "name": "deliveryDate", "value": "2025-07-25T00:00:00.000Z" } // ... ] }, "londonSnapshot": { // ... }, "newYorkSnapshot": { // ... } }
Last Assessments for all tenors
The last assessments data can also be queried for all available tenors:
ExampleGET
/ongoing/last-assessments/03d82381-a711-5077-b8ba-f60b2047ae11
{ "items": [ { "tenor": "1-5 Dec 25", "singaporeSnapshot": { "generatedOn": "2025-08-15T08:15:00.001222", "price": 1.8, "units": "$/bbl", "tenor": "1-5 Dec 25", "dependencies": [ { "id": "c4b52b35-1bc1-5f12-9fc5-40bc9727bd09", "name": "Indonesia 92 RON Grade - SING", "value": 1.7609948473138717, "units": "$/bbl", "tenorName": "1-5 Dec 25" }, { "id": "bbad8d31-e1c0-5ac3-88e5-40ffcd17bc42", "name": "SING - Indonesia 92 RON - SING FOB - Freight Costs - By Load", "value": 0.03597, "units": "$/bbl", "tenorName": "1-5 Dec 25" } ], "metadata": [ { "name": "monthName", "value": "Dec 25" }, { "name": "monthNumber", "value": "12" }, // ... additional metadata ] }, "londonSnapshot": { // ... }, "newYorkSnapshot": { // ... } }, // ... additional items ] } > ```
Intraday
The intraday data provides the most granular view, offering historical and real-time updates.
- Physical data updates every 15 minutes.
- Dependencies (e.g. arbitrage routes, blends, premiums, cash differentials) also update within the same interval.
ExampleGET
/ongoing/intraday/0007f4dd-673a-5309-b606-178aadbd2d2c/11-15 Jun 25
{ "items": [ { "generatedOn": "2025-05-19T11:46:04.619", "price": 5.587244205568989, "units": "$/mt", "tenor": "11-15 Jun 25", "dependencies": [ { "id": "dd758b98-0227-5e68-8529-b35307373d27", "name": "RAS LAFFAN - BARCELONA VIACAPE Jet-A1 LR2 - Dlvd Price by Load", "value": -2.587244205568988, "units": "$/mt", "tenorName": "11-15 Jun 25" }, { "id": "cdc954af-529e-5f98-8a2e-c3543a2cbe81", "name": "RAS LAFFAN - BARCELONA VIACAPE Jet-A1 LR2 - Sales Price", "value": 3.0, "units": "$/mt", "tenorName": "21-25 Jul 25" } ], "metadata": [ { "name": "loadDate", "value": "2025-06-15T00:00:00.000Z" }, { "name": "deliveryDate", "value": "2025-07-25T00:00:00.000Z" } // ... ] } // Additional intraday items... ], "self": "https://api.sparta.app/v2/ongoing/intraday/0007f4dd-673a-5309-b606-178aadbd2d2c/11-15%20Jun%2025?&page=1&pageSize=100", "next": null, "prev": null, "last": "https://api.sparta.app/v2/ongoing/intraday/0007f4dd-673a-5309-b606-178aadbd2d2c/11-15%20Jun%2025?&page=1&pageSize=100" }
Bulk download last settlement and last assessments data
The last settlement and last assessments data can be downloaded in bulk for all tenors by leveraging the catalogue API.
For example, the python script below first retrieves the catalogue, then it asynchronously fetches the last assessments data.
NOTE: this is a code example only. Sparta does not provide guarantees or support this script.
import asyncio
import aiohttp
import time
import json
import requests
from urllib.parse import quote
def fetch_catalog(base_url, token):
"""Fetch complete catalog"""
catalog = []
url = f"{base_url}/v2/catalogue"
page_count = 0
print("📋 Fetching catalog...", end="")
while url:
page_count += 1
print(".", end="")
response = requests.get(url, headers={"Authorization": f"Bearer {token}"})
if response.status_code == 200:
data = response.json()
if "items" in data:
catalog.extend(data["items"])
url = data.get("next")
else:
print(f"\n❌ Failed to fetch catalog page {page_count}: {response.status_code}")
break
return catalog, page_count
async def fetch_assessment_data(session, base_url, token, item_id, item_name, semaphore):
"""Fetch last-assessment data for a single catalog item (async)"""
async with semaphore: # Limit concurrent requests
url = f"{base_url}/v2/ongoing/last-assessments/{item_id}"
try:
async with session.get(url, headers={"Authorization": f"Bearer {token}"}) as response:
if response.status == 200:
data = await response.json()
return {
'item_id': item_id,
'item_name': item_name,
'data': data,
'status': 'success'
}
else:
return {
'item_id': item_id,
'item_name': item_name,
'data': None,
'status': f'error_{response.status}'
}
except Exception as e:
return {
'item_id': item_id,
'item_name': item_name,
'data': None,
'status': f'exception_{str(e)[:50]}'
}
async def fetch_assessments_async(catalog_items, base_url, token, max_concurrent=50):
"""Async function to fetch all assessment data in parallel"""
# Create semaphore to limit concurrent requests
semaphore = asyncio.Semaphore(max_concurrent)
# Create aiohttp session with connection limits
connector = aiohttp.TCPConnector(limit=100, limit_per_host=max_concurrent)
timeout = aiohttp.ClientTimeout(total=30)
async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session:
print(f"⚡ Creating {len(catalog_items)} assessment fetch tasks...")
assessment_start = time.time()
# Create all tasks
tasks = []
for item in catalog_items:
task = fetch_assessment_data(
session,
base_url,
token,
item.get('id'),
item.get('name', 'Unknown'),
semaphore
)
tasks.append(task)
# Execute all tasks with progress tracking
print(f"🔄 Fetching assessment data (max {max_concurrent} concurrent)...")
# Process in batches for progress reporting
batch_size = 100
results = []
for i in range(0, len(tasks), batch_size):
batch = tasks[i:i + batch_size]
batch_results = await asyncio.gather(*batch, return_exceptions=True)
results.extend(batch_results)
completed = i + len(batch)
progress = (completed / len(tasks)) * 100
print(f" 📊 {completed:,}/{len(tasks):,} items processed ({progress:.1f}%)")
assessment_time = time.time() - assessment_start
return results, assessment_time
async def main_assessments():
"""Main async function to orchestrate the assessment data fetching"""
start_time = time.time()
# Configuration
MAX_CONCURRENT_REQUESTS = 5 # Adjust
base_url = os.getenv['customer_api_url']
token = os.getenv('JWT_TOKEN')
print("🚀 Starting assessment data fetching...")
# Step 1: Fetch catalog (synchronous - no benefit from async here)
catalog_start = time.time()
catalog_items, page_count = fetch_catalog(base_url, token)
catalog_time = time.time() - catalog_start
print(f" ✅ {len(catalog_items)} items ({page_count} pages) in {catalog_time:.2f}s")
# Step 2: Fetch assessment data (async for parallelization)
results, assessment_time = await fetch_assessments_async(catalog_items, base_url, token, MAX_CONCURRENT_REQUESTS)
total_time = time.time() - start_time
# Step 3: Analyze results and generate summary
print("\n📈 Analyzing results...")
success_count = 0
error_count = 0
errors = []
for result in results:
if isinstance(result, Exception):
error_count += 1
continue
status = result['status']
if status == 'success':
success_count += 1
else:
errors.append(f"Error for {result['item_name']} ({result['item_id'][:8]}): {status}")
error_count += 1
# Step 4: Display comprehensive summary
print("\n" + "="*60)
print("📊 ASSESSMENT DATA FETCH SUMMARY")
print("="*60)
print(f"⏱️ Total Time: {total_time:.2f}s")
print(f"📋 Catalog Fetch: {catalog_time:.2f}s ({len(catalog_items):,} items, {page_count} pages)")
print(f"⚡ Assessment Fetch: {assessment_time:.2f}s")
print(f"🔧 Max Concurrent: {MAX_CONCURRENT_REQUESTS} requests")
print()
print("📈 RESULTS BREAKDOWN:")
print(f"✅ Successful: {success_count:,} items ({success_count/len(catalog_items)*100:.1f}%)")
print(f"❌ Errors: {error_count:,} items ({error_count/len(catalog_items)*100:.1f}%)")
print(f"📊 Total Items: {len(catalog_items):,}")
print()
print(f"⚡ Requests/Second: {len(catalog_items)/assessment_time:.1f}")
print("="*60)
return results, errors
# Execute the main function using await (since Jupyter already has an event loop)
assessment_async_results, assessment_async_errors = await main_assessments()
Updated 16 days ago