Docs/Guides/Composite Time Series

Ingesting OHLCV bars with composite time series

Composite time series values let you bundle multiple named fields (open, high, low, close, volume) into a single timestamped record. This guide covers ingesting daily OHLCV bars and querying them efficiently.

What is a composite value?

A composite time series value is a parent record containing multiple named items. Each item corresponds to a field defined on the composite series type schema. For OHLCV bars, the schema defines five fields: open, high, low, close, and volume.

Benefits over separate scalar series:

  • All five values for one day are a single API call (and a single billable database item)
  • Archiving or restoring a composite value affects all its items atomically
  • The schema enforces required fields — you can’t accidentally post an incomplete bar

Discover the schema first

Before creating values, fetch the composite series type to understand its required fields:

type_resp = client.get("/series/ohlcv-daily").json() fields_resp = client.post("/time-series-type-fields/filter", json={ "filter": {"and": [{ "field": "type_id", "op": "eq", "value": "ohlcv-daily" }]} }).json() required_fields = [f["field_key"] for f in fields_resp["data"] if f["is_required"]] # ['open', 'high', 'low', 'close', 'volume']

Ingest OHLCV bars

Create one composite value per instrument per day. All items are submitted in a single request:

def ingest_ohlcv(ticker: str, date: str, bar: dict): return client.post("/composite-time-series-values", json={ "instrument_id": ticker, "type_id": "ohlcv-daily", "timestamp": f"{date}T00:00:00Z", "items": [ { "field_key": "open", "value": str(bar["open"]) }, { "field_key": "high", "value": str(bar["high"]) }, { "field_key": "low", "value": str(bar["low"]) }, { "field_key": "close", "value": str(bar["close"]) }, { "field_key": "volume", "value": str(bar["volume"]) } ] }{) # Ingest a batch of bars for ticker, date, bar in bars: ingest_ohlcv(ticker, date, bar)
If any required field is missing from items, the API returns 422 Unprocessable Entity. Validate your source data before calling the API to avoid partial failures.

Querying composite values

Retrieve bars for a date range. Each result includes all items:

OHLCV bars for BHP in Q1 2026
POST /composite-time-series-values/filter { "filter": { "and": [ { "field": "instrument_id", "op": "eq", "value": "bhp.ax" }, { "field": "type_id", "op": "eq", "value": "ohlcv-daily" }, { "field": "timestamp", "op": "gte", "value": "2026-01-01T00:00:00Z" }, { "field": "timestamp", "op": "lt", "value": "2026-04-01T00:00:00Z" } ] }, "sort": [{ "field": "timestamp", "direction": "asc" }] }

Correcting a bar

To correct an existing bar, PATCH the composite value. Only include the items you want to change — other items are left unchanged:

# Find the record to correct existing = client.post("/composite-time-series-values/filter", json={ "filter": {"and": [ { "field": "instrument_id", "op": "eq", "value": "bhp.ax" }, { "field": "timestamp", "op": "eq", "value": "2026-04-15T00:00:00Z" } ]}}).json() value_id = existing["data"][0]["id"] # Patch only the close price client.patch(f"/composite-time-series-values/{value_id}", json={ "items": [{ "field_key": "close", "value": "45.82" }] })
PrivacyTermsStatus© 2025 Ptolemy Pty Ltd