diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f2ae57..082e81e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 0.75.0 - 2026-04-07 + +#### Enhancements +- Upgraded `databento-dbn` to 0.53.0: + - Made `ts_out` a permanent field on all Python record types, replacing the + dynamic `__dict__` attribute. `ts_out` returns an `int` (`UNDEF_TIMESTAMP` when + not set) + - Removed `__dict__` from all Python record classes, eliminating a separate + per-instance allocation + ## 0.74.1 - 2026-03-31 #### Enhancements diff --git a/README.md b/README.md index 8f2f29f..ba27456 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ The library is fully compatible with distributions of Anaconda 2023.x and above. The minimum dependencies as found in the `pyproject.toml` are also listed below: - python = "^3.10" - aiohttp = "^3.8.3" -- databento-dbn = "~0.52.1" +- databento-dbn = "~0.53.0" - numpy = ">=1.23.5" - pandas = ">=1.5.3" - pip-system-certs = ">=4.0" (Windows only) diff --git a/databento/common/dbnstore.py b/databento/common/dbnstore.py index 4504ee3..205bc04 100644 --- a/databento/common/dbnstore.py +++ b/databento/common/dbnstore.py @@ -1244,6 +1244,9 @@ def to_ndarray( schema_rtype = RType.from_schema(schema) schema_filter = filter(lambda r: r.rtype == schema_rtype, self) + if self._metadata.ts_out: + schema_dtype.append(("ts_out", "u8")) + reader = self.reader reader.seek(self._metadata_length) ndarray_iter = NDArrayBytesIterator( @@ -1256,9 +1259,6 @@ def to_ndarray( schema_struct = self._schema_struct_map[self.schema] schema_dtype = schema_struct._dtypes - if self._metadata.ts_out: - schema_dtype.append(("ts_out", "u8")) - if schema is not None and schema != self.schema: # This is to maintain identical behavior with NDArrayBytesIterator ndarray_iter = iter([np.empty([0, 1], dtype=schema_dtype)]) diff --git a/databento/common/publishers.py b/databento/common/publishers.py index ea453e5..4f8a204 100644 --- a/databento/common/publishers.py +++ b/databento/common/publishers.py @@ -553,7 +553,7 @@ class Dataset(StringyMixin, str, Enum): XCIS_TRADES NYSE National Trades. MEMX_MEMOIR - MEMX Memoir Depth. + MEMX MEMOIR Depth. EPRL_DOM MIAX Pearl Depth. FINN_NLS @@ -603,7 +603,7 @@ class Dataset(StringyMixin, str, Enum): XEEE_EOBI European Energy Exchange EOBI. XCBF_PITCH - Cboe Futures Exchange PITCH. + CFE Depth. OCEA_MEMOIR Blue Ocean ATS MEMOIR Depth. @@ -862,7 +862,7 @@ def description(self) -> str: if self == Dataset.XCIS_TRADES: return "NYSE National Trades" if self == Dataset.MEMX_MEMOIR: - return "MEMX Memoir Depth" + return "MEMX MEMOIR Depth" if self == Dataset.EPRL_DOM: return "MIAX Pearl Depth" if self == Dataset.FINN_NLS: @@ -912,7 +912,7 @@ def description(self) -> str: if self == Dataset.XEEE_EOBI: return "European Energy Exchange EOBI" if self == Dataset.XCBF_PITCH: - return "Cboe Futures Exchange PITCH" + return "CFE Depth" if self == Dataset.OCEA_MEMOIR: return "Blue Ocean ATS MEMOIR Depth" raise ValueError("Unexpected Dataset value") @@ -953,7 +953,7 @@ class Publisher(StringyMixin, str, Enum): XCIS_TRADES_XCIS NYSE National Trades. MEMX_MEMOIR_MEMX - MEMX Memoir Depth. + MEMX MEMOIR Depth. EPRL_DOM_EPRL MIAX Pearl Depth. XNAS_NLS_FINN @@ -1133,9 +1133,9 @@ class Publisher(StringyMixin, str, Enum): XEEE_EOBI_XOFF European Energy Exchange EOBI - Off-Market Trades. XCBF_PITCH_XCBF - Cboe Futures Exchange. + Cboe Futures Exchange (CFE). XCBF_PITCH_XOFF - Cboe Futures Exchange - Off-Market Trades. + Cboe Futures Exchange (CFE) - Off-Market Trades. OCEA_MEMOIR_OCEA Blue Ocean ATS MEMOIR. @@ -2166,7 +2166,7 @@ def description(self) -> str: if self == Publisher.XCIS_TRADES_XCIS: return "NYSE National Trades" if self == Publisher.MEMX_MEMOIR_MEMX: - return "MEMX Memoir Depth" + return "MEMX MEMOIR Depth" if self == Publisher.EPRL_DOM_EPRL: return "MIAX Pearl Depth" if self == Publisher.XNAS_NLS_FINN: @@ -2346,9 +2346,9 @@ def description(self) -> str: if self == Publisher.XEEE_EOBI_XOFF: return "European Energy Exchange EOBI - Off-Market Trades" if self == Publisher.XCBF_PITCH_XCBF: - return "Cboe Futures Exchange" + return "Cboe Futures Exchange (CFE)" if self == Publisher.XCBF_PITCH_XOFF: - return "Cboe Futures Exchange - Off-Market Trades" + return "Cboe Futures Exchange (CFE) - Off-Market Trades" if self == Publisher.OCEA_MEMOIR_OCEA: return "Blue Ocean ATS MEMOIR" raise ValueError("Unexpected Publisher value") diff --git a/databento/live/session.py b/databento/live/session.py index d5cb9a9..072413d 100644 --- a/databento/live/session.py +++ b/databento/live/session.py @@ -6,7 +6,6 @@ import logging import math import queue -import struct import threading from collections.abc import Iterable from functools import partial @@ -267,16 +266,14 @@ def _dispatch_callbacks(self, record: DBNRecord) -> None: def _dispatch_writes(self, record: DBNRecord) -> None: record_bytes = bytes(record) - ts_out_bytes = struct.pack("Q", record.ts_out) if self._metadata.has_ts_out else b"" for stream in self._user_streams: try: stream.write(record_bytes) - stream.write(ts_out_bytes) except Exception as exc: logger.error( "error writing %s record (%d bytes) to `%s` stream", type(record).__name__, - len(record_bytes) + len(ts_out_bytes), + len(record_bytes), stream.stream_name, exc_info=exc, ) diff --git a/databento/version.py b/databento/version.py index e4742d1..a25b7a6 100644 --- a/databento/version.py +++ b/databento/version.py @@ -1 +1 @@ -__version__ = "0.74.1" +__version__ = "0.75.0" diff --git a/pyproject.toml b/pyproject.toml index abc0049..1ee7449 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "databento" -version = "0.74.1" +version = "0.75.0" description = "Official Python client library for Databento" readme = "README.md" requires-python = ">=3.10" @@ -10,7 +10,7 @@ dynamic = [ "classifiers" ] dependencies = [ "aiohttp>=3.8.3,<4.0.0; python_version < '3.12'", "aiohttp>=3.9.0,<4.0.0; python_version >= '3.12'", - "databento-dbn~=0.52.1", + "databento-dbn~=0.53.0", "numpy>=1.23.5; python_version < '3.12'", "numpy>=1.26.0; python_version >= '3.12'", "pandas>=1.5.3,<4.0.0", diff --git a/tests/test_historical_data.py b/tests/test_historical_data.py index b535c08..200d076 100644 --- a/tests/test_historical_data.py +++ b/tests/test_historical_data.py @@ -15,6 +15,7 @@ def test_mbo_fields() -> None: fields.remove("record_size") fields.remove("size_hint") fields.remove("ts_index") + fields.remove("ts_out") # Act difference = fields.symmetric_difference(struct._ordered_fields) @@ -45,6 +46,7 @@ def test_mbp_fields( fields.remove("record_size") fields.remove("size_hint") fields.remove("ts_index") + fields.remove("ts_out") # Act difference = fields.symmetric_difference(struct._ordered_fields) @@ -78,6 +80,7 @@ def test_ohlcv_fields( fields.remove("record_size") fields.remove("size_hint") fields.remove("ts_index") + fields.remove("ts_out") # Act difference = fields.symmetric_difference(struct._ordered_fields) @@ -97,6 +100,7 @@ def test_trades_struct() -> None: fields.remove("record_size") fields.remove("size_hint") fields.remove("ts_index") + fields.remove("ts_out") # Act difference = fields.symmetric_difference(struct._ordered_fields) @@ -116,6 +120,7 @@ def test_definition_struct() -> None: fields.remove("record_size") fields.remove("size_hint") fields.remove("ts_index") + fields.remove("ts_out") # Act difference = fields.symmetric_difference(struct._ordered_fields) @@ -135,6 +140,7 @@ def test_imbalance_struct() -> None: fields.remove("record_size") fields.remove("size_hint") fields.remove("ts_index") + fields.remove("ts_out") # Act difference = fields.symmetric_difference(struct._ordered_fields) @@ -154,6 +160,7 @@ def test_statistics_struct() -> None: fields.remove("record_size") fields.remove("size_hint") fields.remove("ts_index") + fields.remove("ts_out") # Act difference = fields.symmetric_difference(struct._ordered_fields)