Support

Volume, open interest, and settlement prices

The statistics schema provides official summary statistics of each instrument that's published by the venue. Each statistics record contains the value or values associated with only a single statistics type, indicated by the stat_type field. This makes the schema flexible and forwards-compatible, but can make it harder to work with.

Overview

In this example we will use the Historical client to retrieve daily statistics for a parent symbol.

We'll download statistics data for a parent symbol and use the StatType enum to filter for cleared volume, open interest, and settlement price statistics. Next, we'll filter for statistics on outright futures only, using data found in the definition schema. Then, we'll group statistics by symbol and date to create a table for each date and symbol.

In the end, we'll generate a plot which shows open interest and cleared volume over time.

ts_ref

Many statistics are published daily or refer to a specific trading session. When provided by the publisher, the trading session associated with the statistic is indicated with the ts_ref field.

Depending on the dataset, statistics can be published at various times, so you may need to look at the next UTC date for a given statistic. For statistics that are published multiple times, you should always refer to the most recently published value.

Example

import databento as db
import matplotlib.pyplot as plt

# Set parameters
dataset = "GLBX.MDP3"
product = "ZC"
start = "2025-05-04"
end = "2025-05-19"

# Create a historical client
client = db.Historical(key="$YOUR_API_KEY")

# Request definition data and convert to DataFrame
def_df = client.timeseries.get_range(
    dataset=dataset,
    schema="definition",
    symbols=f"{product}.FUT",
    stype_in="parent",
    start=start,
    end=end,
).to_df()

# Filter for outright futures only and keep the last definition
def_df = def_df[def_df["instrument_class"] == db.InstrumentClass.FUTURE]
def_df = def_df[["instrument_id", "raw_symbol", "expiration"]]
def_df = def_df.drop_duplicates(subset=["instrument_id"], keep="last")

# Request statistics data and convert to DataFrame
stats_df = client.timeseries.get_range(
    dataset=dataset,
    schema="statistics",
    symbols=f"{product}.FUT",
    stype_in="parent",
    start=start,
    end=end,
).to_df()

# Filter for daily statistics on outright futures
stats_df = stats_df.merge(def_df, on="instrument_id")
stats_df = stats_df.rename(columns={"raw_symbol": "Symbol"})

# Only keep the date component of `ts_ref`
stats_df["Trade date"] = stats_df["ts_ref"].dt.date

# Create columns for each statistic
stats_df["Settlement price"] = stats_df[stats_df["stat_type"] == db.StatType.SETTLEMENT_PRICE]["price"]
stats_df["Cleared volume"] = stats_df[stats_df["stat_type"] == db.StatType.CLEARED_VOLUME]["quantity"]
stats_df["Open interest"] = stats_df[stats_df["stat_type"] == db.StatType.OPEN_INTEREST]["quantity"]

# Groupby and keep the last published record for each statistic
stats_df = stats_df.groupby(["Trade date", "Symbol"]).agg("last").sort_values(["Trade date", "expiration"])

stats_df["Cleared volume"] = stats_df["Cleared volume"].fillna(0).astype(int)
stats_df["Open interest"] = stats_df["Open interest"].fillna(0).astype(int)
stats_df = stats_df[["Settlement price", "Cleared volume", "Open interest"]]

print(stats_df)

# Now, we'll plot aggregated volume and open interest statistics for this product
date_df = stats_df[["Cleared volume", "Open interest"]].groupby("Trade date").agg("sum")

ax_vol = date_df["Cleared volume"].plot.bar(ylabel="Cleared volume")
ax_oi = date_df["Open interest"].reset_index().plot.line(
    ax=ax_vol,
    color="C1",
    marker="o",
    ylabel="Open interest",
    secondary_y=True,
    mark_right=False,
    legend=False,
)

plt.gcf().legend(bbox_to_anchor=(0, 1), loc="upper left", bbox_transform=ax_vol.transAxes)
plt.setp([ax_vol.get_xticklabels(), ax_oi.get_xticklabels()], rotation=45)
plt.title(f"{product} cleared volume and open interest")
plt.tight_layout()
plt.show()

Result

                   Settlement price  Cleared volume  Open interest
Trade date Symbol
2025-05-02 ZCK5              461.25            2624           1966
           ZCN5              469.00          163656         665836
           ZCU5              440.00           60030         314718
           ZCZ5              450.25           93701         432738
           ZCH6              464.50           10615          50264
           ZCK6              473.50            3864          24780
           ZCN6              479.25            2904          18456
           ZCU6              463.25             199           3027
           ZCZ6              465.50             965          20458
           ZCH7              476.75              23           2194
           ZCK7              482.50               0            213
           ZCN7              485.00               0            128
           ZCU7              460.75               0              5
           ZCZ7              461.00               0            594
           ZCN8              478.00               0              0
           ZCZ8              461.50               0             18
...

The table is similar to the one found on the CME website that shows these statistics for every active contract.

The plot shows the aggregated volume and open interest for all active contracts for a product.

Statistics plot