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.