Source: https://databento.com/docs/api-live


# API reference - Live

You can receive live data from Databento via our live APIs, namely the
Databento Raw API.

The Raw API is a simple socket-based, subscription-style protocol. Clients
communicate with our live data gateways through a regular TCP/IP socket.
To make it easier to integrate the API, we also provide official client
libraries that simplify the code you need to write.

You can use our live APIs to subscribe to real-time data in your
application. You can also use the APIs to request intraday historical
data and instrument definitions for any number of products in a venue.


## Basics


### Overview

Databento's live API offers both real-time subscriptions and [intraday replay](https://databento.com/docs/api-live/basics/intraday-replay.md) within the last 24 hours to
various market data [schemas](https://databento.com/docs/api-live/basics/schemas-and-conventions.md) and symbols.
Multiple subscriptions may be combined into a single session, such as trades, subsampled data
(second, minute, hour, daily aggregates), and definitions (expirations, settlement, etc.).
For an easy transition from backtesting to live trading, the live API supports the same schemas,
[datasets](https://databento.com/docs/api-live/basics/datasets.md), and
[symbology](https://databento.com/docs/api-live/basics/symbology.md) as the historical API and returns the same
[record structures](https://databento.com/docs/schemas/whats-a-schema.md).
Our live clients use our binary [DBN encoding](https://databento.com/docs/conventions/databento-binary-encoding.md) for
performant zero-copy market data decoding.


### Authentication

Databento uses API keys to authenticate requests. You can view and manage
your keys on the [API keys]($PLATFORM_HOSTNAME/portal/keys) page of your portal.

Each API key is a 32-character string. By default, our library uses the
environment variable `DATABENTO_API_KEY` as your API key. However, if you
pass an API key to the `Live` constructor through the `key` parameter,
then this value will be used instead.

Our Live API uses a challenge-response authentication mechanism to ensure that
your API key is never sent over the network.

Related: [Securing your API keys](https://databento.com/docs/portal/api-keys.md#securing-your-api-keys).

#### Example usage

```python
import databento as db

# Create a live client
client = db.Live(key="$YOUR_API_KEY")

# Authentication happens on the first subscribe
client.subscribe(
    dataset="GLBX.MDP3",
    schema="trades",
    stype_in="parent",
    symbols="ES.FUT",
)
```


### Sessions

Each instance of the [Live](https://databento.com/docs/api-live/client/live.md) client manages a single Raw API session.
Each session is associated with one [dataset](https://databento.com/docs/api-live/basics/datasets.md).

A session will begin streaming when [Live.start](https://databento.com/docs/api-live/client/start.md) is called.
A session can be stopped gracefully with [Live.stop](https://databento.com/docs/api-live/client/stop.md) or forcefully with [Live.terminate](https://databento.com/docs/api-live/client/terminate.md).

A session can also be stopped by specifying a timeout with [Live.block_for_close](https://databento.com/docs/api-live/client/block-for-close.md) for synchronous applications and [Live.wait_for_close](https://databento.com/docs/api-live/client/wait-for-close.md) for asynchronous applications.

> **See also**
>
> [Connection limits](https://databento.com/docs/api-live/basics/connection-limits.md) for more details.



### Schemas and conventions

A schema is a data record format represented as a collection of different
data fields. Our datasets support multiple schemas, such as order book,
trades, bar aggregates, and so on. You can get a dictionary describing
the fields of each schema from our [List of market data schemas](https://databento.com/docs/schemas/whats-a-schema.md).

You can get a list of all supported schemas for any given dataset using
the Historical client's [list_schemas](https://databento.com/docs/api-historical/metadata/metadata-list-schemas.md) method. The same information can also be
found on the dataset details pages on the [user portal]($PLATFORM_HOSTNAME).

The following table provides details about the data types and conventions used
for various fields that you will commonly encounter in the data.

| Name | Field | Description |
| Dataset | `dataset` | A unique string name assigned to each dataset by Databento. Full list of datasets can be found from the [metadata](https://databento.com/docs/api-historical/metadata/metadata-list-datasets.md). |
| Publisher ID | `publisher_id` | A unique 16-bit unsigned integer assigned to each publisher by Databento. Full list of publisher IDs can be found from the [metadata](https://databento.com/docs/api-historical/metadata/metadata-list-publishers.md). |
| Instrument ID | `instrument_id` | A unique 32-bit unsigned integer assigned to each instrument by the venue. Information about instrument IDs for any given dataset can be found in the [symbology](https://databento.com/docs/api-historical/symbology.md). |
| Order ID | `order_id` | A unique 64-bit unsigned integer assigned to each order by the venue. |
| Timestamp (event) | `ts_event` | The matching-engine-received timestamp expressed as the number of nanoseconds since the [UNIX epoch](https://en.wikipedia.org/wiki/Unix_time). |
| Timestamp (receive) | `ts_recv` | The capture-server-received timestamp expressed as the number of nanoseconds since the [UNIX epoch](https://en.wikipedia.org/wiki/Unix_time). |
| Timestamp delta (in) | `ts_in_delta` | The matching-engine-sending timestamp expressed as the number of nanoseconds before `ts_recv`. See [timestamping](https://databento.com/docs/architecture/timestamping-guide.md) guide. |
| Timestamp out | `ts_out` | The Databento gateway-sending timestamp expressed as the number of nanoseconds since the [UNIX epoch](https://en.wikipedia.org/wiki/Unix_time). See [timestamping](https://databento.com/docs/architecture/timestamping-guide.md) guide. |
| Price | `price` | The price expressed as signed integer where every 1 unit corresponds to 1e-9, i.e. 1/1,000,000,000 or 0.000000001. |
| Book side | `side` | The side that initiates the event. Can be **A**sk for a sell order (or sell aggressor in a trade), **B**id for a buy order (or buy aggressor in a trade), or **N**one where no side is specified by the original source. |
| Size | `size` | The order quantity. |
| Flag | `flag` | A bit field indicating event end, message characteristics, and data quality. |
| Action | `action` | The event type or order book operation. Can be **A**dd, **C**ancel, **M**odify, clea**R** book, **T**rade, **F**ill, or **N**one. |
| Sequence number | `sequence` | The original message sequence number from the venue. |


### Datasets

Databento provides time series datasets for a variety of markets, sourced from different
publishers. Our available datasets can be browsed through the [search]($PLATFORM_HOSTNAME)
feature on our site.

Each dataset is assigned a unique string identifier (dataset ID) in the form `PUBLISHER.DATASET`, such as `GLBX.MDP3`.
For publishers that are also markets, we use standard four-character ISO 10383 [Market Identifier Codes (MIC)](https://www.iso20022.org/market-identifier-codes).
Otherwise, Databento arbitrarily assigns a four-character identifier for the publisher.

These dataset IDs are also found on the [Data catalog](https://databento.com/docs/portal/data-catalog.md) and [Download request](https://databento.com/docs/portal/batch-download.md)
features of the Databento user portal.

When a publisher provides multiple data products with different levels of granularity,
Databento subscribes to the most-granular product. We then provide this dataset with
[alternate schemas](https://databento.com/docs/schemas/whats-a-schema.md) to
make it easy to work with the level of detail most appropriate for your application.

More information about different types of venues and publishers is available in
our [FAQs](https://databento.com/docs/faqs/venues-and-publishers.md).


### Symbology

Databento's live API supports several ways to select an instrument in a [dataset](https://databento.com/docs/api-historical/basics/datasets.md).
An instrument is specified using a **symbol** and a **symbology type**, also referred to as an **stype**.
The supported symbology types are:

- **[Raw symbology](https://databento.com/docs/conventions/symbology.md#raw-symbol)** (`raw_symbol`) original string symbols used by the publisher in the source data.
- **[Instrument ID symbology](https://databento.com/docs/conventions/symbology.md#instrument-id)** (`instrument_id`) unique numeric ID assigned to each instrument by the publisher.
- **[Parent symbology](https://databento.com/docs/conventions/symbology.md#parent)** (`parent`) groups instruments related to the market for the same underlying.
- **[Continuous contract symbology](https://databento.com/docs/conventions/symbology.md#continuous)** (`continuous`) proprietary symbology that specifies instruments based on certain systematic rules.

> **Info**
>
> In the live API, existing subscriptions to continuous contracts will not be remapped to different instruments.
> However, submitting a new identical subscription may result in a new mapping.

When subscribing to live data, an input symbology type can be specified.
By default, our client libraries will use raw symbology for the input type. Not all symbology types are supported for every dataset.

If one or more symbols in a subscription fail to resolve, the gateway emits an [`ErrorMsg`](https://databento.com/docs/api-live/basics/errors.md) record with `code=SYMBOL_RESOLUTION_FAILED` for each unresolved symbol and continues streaming data for any symbols that did resolve.
If a symbol later resolves (for example, a new listing from the publisher), the gateway publishes a `SymbolMappingMsg` and begins streaming data for that symbol.

For live data, symbology mappings are provided through [SymbolMappingMsg](https://databento.com/docs/conventions/symbology.md#symbolmappingmsg) records.
These records are sent after the session has started and can be used to map the `instrument_id` from a data record's header to a text symbol.

For more about symbology at Databento, see our [Standards and conventions](https://databento.com/docs/conventions/symbology.md).


### Dates and times

Our Python client library has several functions with timestamp arguments. These arguments will have type `pandas.Timestamp | datetime.date | str | int` and support a variety of formats.

It's recommended to use [pandas.Timestamp](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Timestamp.html), which fully supports timezones and nanosecond-precision. If a `datetime.date` is used, the time is set to midnight UTC. If an `int` is provided, the value is interpreted as [UNIX nanoseconds](https://en.wikipedia.org/wiki/Unix_time).

The client library also handles several string-based timestamp formats based on [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html).

- `yyyy-mm-dd`, e.g. `"2022-02-28"` (midnight UTC)
- `yyyy-mm-ddTHH:MM`, e.g. `"2022-02-28T23:50"`
- `yyyy-mm-ddTHH:MM:SS`, e.g. `"2022-02-28T23:50:59"`
- `yyyy-mm-ddTHH:MM:SS.NNNNNNNNN`, e.g. `"2022-02-28T23:50:59.123456789"`

Timezone specification is also supported.

- `yyyy-mm-ddTHH:MMZ`
- `yyyy-mm-ddTHH:MM±hh`
- `yyyy-mm-ddTHH:MM±hhmm`
- `yyyy-mm-ddTHH:MM±hh:mm`

**Bare dates**

Some parameters require a bare date, without a time. These arguments have type `datetime.date | str` and must either be a `datetime.date` object, or a string in `yyyy-mm-dd` format, e.g. `"2022-02-28"`.


### Intraday replay

Our live API offers intraday replay within the last 24 hours.
On weekends and other periods when data isn't being published, the gateway may report less than 24 hours of replay available.
Users can connect to the live service and request data from a particular start time.
Data will be filtered on `ts_event` for all schemas except CBBO and BBO, which will be filtered on `ts_recv`.

A different start time can be specified for each subscription.
There can be multiple subscriptions for the same schema, with each subscription having a different start time.
When the session starts, records will be immediately replayed for each schema.
A replay completed [SystemMsg](https://databento.com/docs/api-live/basics/system-messages.md) will be sent for each replayed schema once it catches up to real-time data.
Once a session has started, newly added subscriptions are not eligible for intraday replay.

As a special case for the `GLBX.MDP3` dataset, we also provide replay of the entire weekly session in the MBO and definition schemas
outside of the 24-hour window to aid with recovery, as these schemas are highly stateful.

Pass `start=0` to easily request the full replay history available for each schema.

Our Python client library supports several convenient date formats, such as [pd.Timestamp](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Timestamp.html), [Python datetime](https://docs.python.org/3/library/datetime.html#datetime-objects), [Python date](https://docs.python.org/3/library/datetime.html#date-objects), [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) strings, or [UNIX timestamps](https://en.wikipedia.org/wiki/Unix_time) in nanoseconds.
Refer to the [Dates and times](https://databento.com/docs/api-live/basics/dates-and-times.md) article for more information on how our client library handles timestamps.

#### Example usage

```python
import databento as db

# Create a live client
client = db.Live(key="$YOUR_API_KEY")

# Subscribe with a specified start time for intraday replay
client.subscribe(
    dataset="GLBX.MDP3",
    schema="trades",
    symbols="ES.FUT",
    stype_in="parent",
    start="2023-04-17T09:00:00",
)
```


### Snapshot

Users can request a snapshot for a live subscription to obtain the recent order book state without [replaying](https://databento.com/docs/api-live/basics/intraday-replay.md) the whole trading session.
This is only supported for the [MBO](https://databento.com/docs/schemas/mbo.md) schema.

More details can be found in this [article](https://databento.com/docs/conventions/mbo-snapshot.md).

#### Example usage

```python
import databento as db

# Create a live client
client = db.Live(key="$YOUR_API_KEY")

# Subscribe to live snapshot
client.subscribe(
    dataset="GLBX.MDP3",
    schema="mbo",
    symbols="ES.FUT",
    stype_in="parent",
    snapshot=True,
)
```


### System messages

Our live API uses a system record (`SystemMsg`) to indicate non-error information to clients.

One use is heartbeating, to ensure the TCP connection remains open and to help clients detect a connection issue.
A heartbeat will only be sent if no other data record was sent to the client during the heartbeat interval.
The interval between heartbeat messages can be configured with the `heartbeat_interval_s` parameter to [Live](https://databento.com/docs/api-live/client/live.md).
The `is_heartbeat()` method will return `True` if the record is a heartbeat.

The gateway sends an end-of-interval message (`END_OF_INTERVAL`) once it has published every record for one interval of an OHLCV, BBO, or CBBO schema.
Its `ts_event` is the exclusive end of that interval.
For OHLCV schemas, that is the bar's `ts_event` plus the bar interval, so an `ohlcv-1m` end-of-interval message with a `ts_event` of 14:31:00 follows the bars stamped 14:30:00.
For BBO and CBBO schemas, it equals the `ts_recv` of the records in the interval.
The gateway sends one end-of-interval message per schema and interval.

| Field | Type | Description |
| `msg` | str | The message from the gateway. |
| `code` | int | Describes the type of system message. See table below. |

#### System code variants

Corresponds with the `SystemCode` enum.

| Variant | `code` | Description |
| HEARTBEAT | `0` | A message sent in the absence of other records to indicate the connection remains open. |
| SUBSCRIPTION\_ACK | `1` | An acknowledgement of a subscription request. |
| SLOW\_READER\_WARNING | `2` | The gateway has detected this session is falling behind real-time data. |
| REPLAY\_COMPLETED | `3` | Indicates a replay subscription has caught up with real-time data. This message will be sent per schema. |
| END\_OF\_INTERVAL | `4` | Signals that all records for an interval-based schema have been published for the interval ending at `ts_event`. |


### Errors

Our live API uses an error record (`ErrorMsg`) to indicate failures to clients.
Error records are processed like any other record, and as such will be
passed on to any callbacks, streams, and iterators for the [Live](https://databento.com/docs/api-live/client/live.md) client.

| Field | Type | Description |
| `err` | str | The error message. |
| `code` | int | Describes the type of error message. See table below. |
| `is_last` | bool | `True` if this is the last in a series of error records. |

**Error code variants**

Corresponds with the `ErrorCode` enum.

| Variant | `code` | Fatal | Description |
| AUTH\_FAILED | `1` | ✓ | The authentication step failed. |
| API\_KEY\_DEACTIVATED | `2` | ✓ | The user account or API key were deactivated. |
| CONNECTION\_LIMIT\_EXCEEDED | `3` | ✓ | The user has exceeded their open connection limit. |
| SYMBOL\_RESOLUTION\_FAILED | `4` |  | A symbol in a subscription failed to resolve. Emitted per unresolved symbol. |
| INVALID\_SUBSCRIPTION | `5` | ✓ | There was an issue with a subscription request (other than symbol resolution). |
| INTERNAL\_ERROR | `6` | ✓ | An error occurred in the gateway. |
| SKIPPED\_RECORDS\_AFTER\_SLOW\_READING | `7` |  | A slow client was detected and records were skipped by the gateway to allow catching up. |
| REPLAY\_DATA\_AGED\_OUT | `8` | ✓ | Replay data is no longer retained and the subscription's schema is incompatible with skipping records. |

Fatal errors cause the gateway to close the session after sending the error record.
Non-fatal errors are informational and the session continues.

#### Logging

Our Python client library is fully compatible with the built-in [logging](https://docs.python.org/3/library/logging.html) module.

When using the live client to build an application, it is recommended to
enable logging in the `databento` module. This logging is disabled by default.


### Connection limits

With our live API, there is a limit of 10 simultaneous connections ([sessions](https://databento.com/docs/api-live/basics/sessions.md))
per ([dataset](https://databento.com/docs/api-live/basics/datasets.md)) per team for Standard plans.
Plus and Unlimited plans will be limited to 50 simultaneous connections per dataset per team.
Creating additional API keys will not affect the maximum number of connections per team.

In addition, a single gateway will allow at most five incoming connections per second from the same IP address.
If an IP address goes over this limit, incoming connections will be immediately closed by the
gateway -- existing connections will not be affected.
If this happens, clients should wait one second before retrying.

#### Subscription rate limits

[Subscription requests](https://databento.com/docs/api-live/client/live-blocking-subscribe.md) are throttled to prevent abuse and accidental performance impact on other users.
Subscriptions above the limit of 10 per second will be artificially delayed until the session is back under the rate limit, but not rejected;
the gateway will send a [subscription acknowledgement](https://databento.com/docs/api-live/basics/system-messages.md) when it has finished processing a subscription request.


### Error detection

When maintaining a connected [Live client](https://databento.com/docs/api-live/client/live.md), clients should monitor their connection for errors.

There are three main ways in which a session can enter an error state:
* Hung connection: The client is not receiving any data from the gateway
* Disconnect without error: The client is explicitly disconnected by the gateway, without receiving an error message
* Disconnect with error: The client is explicitly disconnected by the gateway.
  Immediately prior to being disconnected, the client will receive an [error record](https://databento.com/docs/api-live/basics/errors.md)

#### Hung connection

To detect hung connections, clients are instructed to make use of system heartbeats.
Clients can configure a heartbeat interval when creating the [Live client](https://databento.com/docs/api-live/client/live.md) by setting the `heartbeat_interval_s` parameter.
If the heartbeat interval is not set by the client, it will default to 30 seconds.

Once a session is started, if no data is sent by the gateway for the entirety of a heartbeat interval, the gateway will send a [system message](https://databento.com/docs/api-live/basics/system-messages.md) to the client to indicate a heartbeat.
If the gateway is regularly sending other messages to the client (for example, `MboMsg`), heartbeats will not be sent.

Once a session is started, if a client does not receive any messages from the gateway for the duration of one heartbeat interval plus ten seconds, the session can be considered hung.
Clients are instructed to disconnect from the gateway and reconnect upon detecting hung connections.

Clients with unstable internet connections may need larger intervals than ten seconds to ensure the connection is truly hung, as opposed to merely delayed.

#### Disconnect without error

From the point of view of the [Live client](https://databento.com/docs/api-live/client/live.md), a disconnect is detected when the underlying TCP session is closed.
When using [Live.block_for_close](https://databento.com/docs/api-live/client/block-for-close.md) or [Live.wait_for_close](https://databento.com/docs/api-live/client/wait-for-close.md), an exception will be raised if the TCP session was closed without an error.
Upon being disconnected, clients are instructed to wait one second and initiate a new connection.
Waiting too short an interval to reconnect may trigger the gateway's rate limiter.

> **See also**
>
> [Connection limits](https://databento.com/docs/api-live/basics/connection-limits.md) for more details.

#### Disconnect with error

From the point of view of the [Live client](https://databento.com/docs/api-live/client/live.md), a disconnect with error is detected when the underlying TCP session is closed after an `ErrorMsg` or a API error response is received.
Any `ErrorMsg` records received by the client can be consumed by the application, such as when [iterating](https://databento.com/docs/api-live/client/iter.md) or using a callback with [Live.add_callback](https://databento.com/docs/api-live/client/add-callback.md).
When using [Live.block_for_close](https://databento.com/docs/api-live/client/block-for-close.md) or [Live.wait_for_close](https://databento.com/docs/api-live/client/wait-for-close.md), any `ErrorMsg` records received will be raised in an exception.

Clients disconnected with an error are instructed to not reconnect automatically.
In the vast majority of cases, reconnecting and resubscribing with the same parameters will lead to the same errors being received again.
The error sent to the client will indicate the issue to be fixed prior to resubscribing.


### Versioning

Our historical and live APIs and their client libraries adopt `MAJOR.MINOR.PATCH` format
for version numbers. These version numbers conform to
[semantic versioning](https://semver.org). We are using major version `0` for
initial development, where our API is not considered stable.

Once we release major version `1`, our public API will be stable. This means that
you will be able to upgrade minor or patch versions to pick up new functionality,
without breaking your integration.

Starting with major versions after `1`, we will provide support for previous
versions for one year after the date of the subsequent major release.
For example, if version `2.0.0` is released on January 1, 2024, then all versions
`1.x.y` of the API and client libraries will be deprecated. However, they will
remain supported until January 1, 2025.

We may introduce backwards-compatible changes between minor versions in the form of:

- New data [encodings](https://databento.com/docs/api-historical/basics/encodings.md)
- Additional fields to existing data [schemas](https://databento.com/docs/api-historical/basics/schemas-and-conventions.md)
- Additional batch download [customizations](https://databento.com/docs/api-historical/batch.md)

Our [Release notes](https://databento.com/docs/release-notes/release-notes-python.md) will contain information about
both breaking and backwards-compatible changes in each release.

Our API and official client libraries are kept in sync with same-day releases
for major versions. For instance, `1.x.y` of the C++ client
library will use the same functionality found in any `1.x.y` version of the Python client.

Related: [Release notes](https://databento.com/docs/release-notes/release-notes-python.md).



### Compression

Databento provides options for compressing files from our API.

**ZSTD**

The `ZSTD` compression option uses the [Zstandard](http://facebook.github.io/zstd/) format.
This adds a slight performance cost to encoding and decoding.

Read more about [working with Zstandard-compressed files](https://databento.com/docs/conventions/working-with-zstandard.md).

**NONE**

The `NONE` compression option disables compression entirely, resulting in larger data transfer.
By default, live data is uncompressed.


### Recovering after a disconnection

When reconnecting to the gateway, clients should [resubscribe](https://databento.com/docs/api-live/client/subscribe.md) to all desired symbols.
In order to avoid missing data after a reconnection, there are three main approaches to recovery:
- Natural refresh
- Intraday replay
- Snapshot (MBO only)

The best approach to recovery will depend on the client's use case and specific needs.

#### Natural refresh

To recover via natural refresh, clients can resubscribe to all desired symbols without the `start` or `snapshot` parameters.
This means no data will be replayed, and the client will immediately receive the newest messages upon subscribing.

This recovery approach is the fastest (since there's no data replay), and is recommended for stateless schemas such as MBP-10, in cases where the client only requires the current state of each instrument.

#### Intraday replay

To recover via intraday replay, clients should store the last `ts_event` and the number of records received with that last timestamp, per schema and instrument.
The `ts_event` and record count should be continuously updated when processing incoming records.

When reconnecting, clients should set the `start` parameter of the resubscription to the lowest stored `ts_event` across all instruments for that schema.
The gateway will then send all records starting from that timestamp (including records with the exact same `ts_event`).

The resubscription may lead to duplicated data being sent to the client.
Clients who require that each message is delivered exactly once are instructed to:
- Discard all records with a lower `ts_event` than the stored one for the corresponding instrument
- Discard the first N records with the same `ts_event` as the stored one for the corresponding instrument, where N is the number of records already seen with that `ts_event` prior to the disconnection.
  This is important in case there are multiple events with the same `ts_event` and the client is disconnected halfway through processing those events

This recovery approach is recommended when clients require the uninterrupted history of records for the desired schema (for example, when using the Trades schema to construct a ticker tape).
However, this approach can take a longer time to synchronize with the live stream, depending on how long the client was disconnected.

For the CBBO and BBO schemas where filtering is based on `ts_recv`, clients should store the last `ts_recv` per instrument.
When reconnecting, clients should set the `start` parameter of the resubscription to the lowest stored `ts_recv` across all instruments.
The gateway will then send all records starting from that timestamp (including records with the same `ts_recv`).
Since CBBO and BBO are stateless schemas, you should always refer to the most recent record per instrument.

#### Snapshot (MBO only)

When resubscribing to the MBO schema, clients can request a [snapshot](https://databento.com/docs/conventions/mbo-snapshot.md) to receive the current state of the book after a disconnection.
This eliminates the need to replay the missed messages and leads to faster synchronization with the live stream.
This recovery approach is generally recommended over intraday replay when using the MBO schema.


### Maintenance schedule

We restart our live gateways at the following times:
- **CME Globex.** Saturday 02:15 CT
- **All ICE venues.** Sunday 09:45 UTC
- **All other datasets.** Sunday 10:30 UTC

All clients will be disconnected during this time.
It is recommended to wait 15 minutes after the scheduled restart time before reconnecting.

Additionally, we may restart our gateways mid-week.
While we generally post these mid-week restarts on our [status page](https://status.databento.com/), we may perform these restarts without notice due to an urgent fix.
You should configure your client to handle reconnecting automatically.

While some exchanges are closed on Saturday, our systems are still connected to the exchange feeds.
The exchange may send test data, and our gateways will disseminate this data to all connected clients.
If you are not interested in receiving this test data, we recommend you disconnect after the Friday close and reconnect on Sunday after the scheduled restart.

> **Info**
>
> Any test data sent through the Live API will not be seen in our historical data.


### Slow reader behavior

Occasionally, a client session's data processing may lag behind real-time data. This can happen due
to multiple reasons, such as a spike in messaging volume from the venue, network fluctuations
between the client and the server, or an inability of the client application to process messages
fast enough to keep up with the venue's message flow.

The live API allows clients to configure different behaviors when this happens via the
`slow_reader_behavior` parameter in the [Live constructor](https://databento.com/docs/api-live/client/live.md).
This parameter can be set to the values `skip` or `warn`, and defaults to `skip` when not set.
This parameter cannot be changed after the session is authenticated.

#### Skip

If the slow reader behavior is set to `skip`, whenever the gateway detects a client falling
behind real-time data, an `ErrorMsg` with error code `SKIPPED_RECORDS_AFTER_SLOW_READING`
will be sent to the client and the session will skip records until caught up with real-time
data.

This behavior only applies to subscriptions for the following schemas: MBP-1, MBP-10,
BBO-1s, BBO-1m, CMBP-1, CBBO-1s, and CBBO-1m. Subscriptions to other schemas will
always use the `warn` behavior.

#### Warn

If the slow reader behavior is set to `warn`, whenever the gateway detects a client falling
behind real-time data, a `SystemMsg` with system code `SLOW_READER_WARNING` will be sent
to the client. The session will not skip any records and will attempt to replay every
single record in the subscription.

In some cases, setting `warn` as the slow reader behavior can lead to increasing lag
between the session and real-time data.

#### Data aged out of retention

A replay can fall behind far enough that the data it was reading is removed, i.e. it now
exceeds the [supported replay window](https://databento.com/docs/api-live/basics/intraday-replay.md).
Sessions whose effective behavior is `skip` resume from the earliest retained records.
Sessions using `warn`, either by request or because the schema is incompatible with
skipping, receive a fatal `ErrorMsg` with error code `REPLAY_DATA_AGED_OUT` naming the
earliest available `start` time.


## Client


### Live

To access Databento's live API, first create an instance of the
`Live` client. The entire API for a streaming session is exposed
through instance methods of the client.

Databento's `Live` client is built with Python's [asyncio](https://docs.python.org/3/library/asyncio.html) module and can be
easily integrated into asynchronous applications.

Note that the API key can be passed as a parameter, which is
[not recommended for production applications](https://databento.com/docs/portal/api-keys.md#securing-your-api-keys).
Instead, you can leave out this parameter to pass your API key via the `DATABENTO_API_KEY` environment variable:

#### API method

```python
class Live(
    key: str | None = None,
    gateway: str | None = None,
    port: int | None = None,
    ts_out: bool = False,
    heartbeat_interval_s: int | None = None,
    reconnect_policy: ReconnectPolicy | str = ReconnectPolicy.NONE,
    slow_reader_behavior: SlowReaderBehavior | str | None = None,
    compression: Compression | str = Compression.NONE,
    loop: asyncio.AbstractEventLoop | None = None,
)
```

#### Example usage

```python
import databento as db

# Pass as parameter
client = db.Live(key="$YOUR_API_KEY")

# Or, pass as `DATABENTO_API_KEY` environment variable
client = db.Live()
```
#### Parameters

| Parameter | Type | Required | Description |
| `key` | str | optional | 32-character API key. Found on your [API keys]($PLATFORM_HOSTNAME/portal/keys) page. If `None` then `DATABENTO_API_KEY` environment variable is used. |
| `gateway` | str | optional | The url of the remote gateway to connect to. This is for advanced use. |
| `port` | int | optional | The port to connect to the remote gateway on. This is for advanced use. |
| `ts_out` | bool, default False | optional | Whether the gateway should append the send timestamp (`ts_out`) to each record. |
| `heartbeat_interval_s` | int, default None | optional | The interval in seconds at which the gateway will send [heartbeat records](https://databento.com/docs/api-live/basics/system-messages.md) if no other data records are sent. By default heartbeats will be sent at the gateway's default interval. Must be between 5 and 1800 seconds. |
| `reconnect_policy` | ReconnectPolicy or str, default None | optional | The reconnection policy for automatically resuming a live session when an unexpected disconnection occurs. |
| `slow_reader_behavior` | SlowReaderBehavior or str, default None | optional | How the gateway should handle a connection unable to keep up with realtime. |
| `compression` | Compression or str, default None | optional | Sets the [compression](https://databento.com/docs/api-live/basics/compression.md) mode for the read stream. Uncompressed by default. |
| `loop` | asyncio.AbstractEventLoop, default None | optional | The event loop to run the client connection in. If `None`, a shared event loop running on a background thread will be used. |


### Live.add\_callback

Add a callback to the live client. This callback must take a single record argument.
Refer to the [What's a schema](https://databento.com/docs/schemas/whats-a-schema.md) article for documentation on the fields contained with each record type.

A callback will receive error messages from the gateway with the `ErrorMsg` record type.
This indicates a problem occurred with the session.
Exceptions raised in a callback can be handled explicitly by specifying an `exception_callback`.

The callbacks are executed in the order they are added.

> **Info**
>
> It is recommended that callback functions be non-blocking to ensure the networking event loop remains running.

#### API method

```python
Live.add_callback(
    record_callback: Callable[[DBNRecord], None],
    exception_callback: Callable[[Exception], None] | None = None,
) -> None
```

#### Parameters

| Parameter | Type | Required | Description |
| `record_callback` | Callable[[DBNRecord], None] | required | A callback to dispatch records to. The callback must take a single record argument. If no exception callback is provided, any exceptions encountered will be logged and raised as warnings for visibility. |
| `exception_callback` | Callable[[Exception], None] | optional | A callback to dispatch exceptions to that are raised when executing `record_callback`. The callback must take a single exception argument. |

#### Example usage

```python
import databento as db

# Create a callback to handle DBN records
def user_callback(record: db.DBNRecord) -> None:
    print(f"callback run for {record}")

# Create a callback to handle exceptions from `user_callback`
def error_handler(exception: Exception) -> None:
    print(f"an error occurred {exception}")

# Create a live client
client = db.Live(key="$YOUR_API_KEY")

# Subscribe to the trades schema for all ES futures
client.subscribe(
    dataset="GLBX.MDP3",
    schema="trades",
    stype_in="parent",
    symbols="ES.FUT",
)

# Add the user_callback to the client
client.add_callback(
    record_callback=user_callback,
    exception_callback=error_handler,  # optional error handler
)
```


### Live.add\_stream

Add an output stream to the live client. The client will write binary DBN records to the stream.
This stream must be writable in bytes mode, or a path to a file that is writable.

A stream will receive error messages from the gateway with the `ErrMsg` record type.
This indicates a problem occurred with the session.
Exceptions raised in a callback can be handled explicitly by specifying an `exception_callback`.

The writes are performed in the order the streams were added.

> **See also**
>
> DBN records are optimized for stream-like processing.
>
> While pandas DataFrames are not well-suited for this due to their column-oriented format,
> they can still be used by first streaming DBN data to a file, then converting to a DataFrame with DBNStore.from_file().to_df().
> See [this example](https://databento.com/docs/examples/basics-live/live-stream-to-file.md) for more information.

#### API method

```python
Live.add_stream(
    stream: IO[bytes] | PathLike[str] | str,
    exception_callback: Callable[[Exception], None] | None = None,
) -> None
```

#### Parameters

| Parameter | Type | Required | Description |
| `stream` | IO[bytes] or PathLike[str] or str | required | An IO stream to write records to, or a writable file path. The stream must support writing bytes. |
| `exception_callback` | Callable[[Exception], None] | optional | An error handling callback to process exceptions that are raised when writing to the stream. The callback must take a single exception argument. If no exception callback is provided, any exceptions encountered will be logged and raised as warnings for visibility. |

#### Example usage

```python
import databento as db

# Open a file for writing
output = open("output.dbn", mode="wb")

# Create a callback to handle exceptions when writing to `output`
def error_handler(exception: Exception) -> None:
    print(f"an error occurred {exception}")

# Create a live client
client = db.Live(key="$YOUR_API_KEY")

# Subscribe to the trades schema for all ES futures
client.subscribe(
    dataset="GLBX.MDP3",
    schema="trades",
    stype_in="parent",
    symbols="ES.FUT",
)

# Add the output file stream to the client
client.add_stream(
    stream=output,
    exception_callback=error_handler,  # optional error handler
)
```


### Live.add\_reconnect\_callback

Add a reconnect callback to the live client. This callback must take two arguments.
When a reconnection policy is set on the `Live` client, this callback will be executed when a reconnection occurs with two arguments:
- The last received record's `ts_event` timestamp, or `start` timestamp from the session `Metadata` if no records were received yet.
- The `start` timestamp from the reconnected session's `Metadata`.

These values can be used to record any gaps in the received data due to a disconnection.
Exceptions raised in a callback can be handled explicitly by specifying an `exception_callback`.

The callbacks are executed in the order they are added.

> **Info**
> It is recommended that callback functions be non-blocking to ensure the networking event loop remains running.

#### API method

```python
Live.add_reconnect_callback(
    reconnect_callback: Callable[[pd.Timestamp, pd.Timestamp], None]
    exception_callback: Callable[[Exception], None] | None = None,
) -> None
```

#### Parameters

| Parameter | Type | Required | Description |
| `reconnect_callback` | Callable[[pd.Timestamp, pd.Timestamp], None] | required | A callback for handling reconnections. The callback must take two arguments. |
| `exception_callback` | Callable[[Exception], None] | optional | A callback to dispatch exceptions to that are raised when executing `reconnect_callback`. The callback must take a single exception argument. |

#### Example usage

```python
import databento as db

# Create a callback to handle reconnections
def reconnect_callback(start, end) -> None:
    print(f"reconnection gap from {start} to {end}")

# Create a callback to handle exceptions from `reconnect_callback`
def error_handler(exception: Exception) -> None:
    print(f"an error occurred {exception}")

# Create a live client with a reconnect policy
client = db.Live(
    key="$YOUR_API_KEY",
    reconnect_policy="reconnect",
)

# Subscribe to the trades schema for all ES futures
client.subscribe(
    dataset="GLBX.MDP3",
    schema="trades",
    stype_in="parent",
    symbols="ES.FUT",
)

# Add the reconnect callback to the client
client.add_reconnect_callback(
    reconnect_callback=reconnect_callback,
    exception_callback=error_handler,  # optional error handler
)
```


### Live.block\_for\_close

Block until the session closes or a timeout is reached.
A session will close when the remote gateway disconnects or after [Live.stop](https://databento.com/docs/api-live/client/stop.md) or [Live.terminate](https://databento.com/docs/api-live/client/terminate.md) are called.
In the event the connection is closed unexpectedly, a `BentoError` will be raised.

If a `timeout` is specified, [Live.terminate](https://databento.com/docs/api-live/client/terminate.md) will be called when the timeout is reached.

When this method unblocks, the session is guaranteed to be closed.

#### API method

```python
Live.block_for_close(
    timeout: float | None = None,
) -> None
```

#### Parameters

| Parameter | Type | Required | Description |
| `timeout` | float | optional | A duration in seconds to wait for the session to close. If `None`, wait forever. |

#### Example usage

```python
import databento as db

# Create a live client
client = db.Live(key="$YOUR_API_KEY")

# Subscribe to the trades schema for all ES futures
client.subscribe(
    dataset="GLBX.MDP3",
    schema="trades",
    stype_in="parent",
    symbols="ES.FUT",
)

# Start the session
client.start()

# Block for the session to close
client.block_for_close()
```


### Live.start

Start the session.

A client can only be started once, and after a successful connection is made by calling [Live.subscribe](https://databento.com/docs/api-live/client/subscribe.md).

A client can be gracefully stopped by calling [Live.stop](https://databento.com/docs/api-live/client/stop.md) or forcefully using [Live.terminate](https://databento.com/docs/api-live/client/terminate.md)

When iterating records with [Live.\_\_iter\_\_](https://databento.com/docs/api-live/client/iter.md) or [Live.\_\_aiter\_\_](https://databento.com/docs/api-live/client/aiter.md) it is not necessary to call [Live.start](https://databento.com/docs/api-live/client/start.md) and doing so before iterating will raise a `ValueError`.

> **Info**
>
> A session cannot be started more than once.

#### API method

```python
Live.start() -> None
```

#### Example usage

```python
import databento as db

# Create a live client
client = db.Live(key="$YOUR_API_KEY")

# Subscribe to the trades schema for all ES futures
client.subscribe(
    dataset="GLBX.MDP3",
    schema="trades",
    stype_in="parent",
    symbols="ES.FUT",
)

# Print records as they arrive
client.add_callback(print)

# Start the streaming session
client.start()

# Block until disconnection
client.block_for_close()
```



### Live.stop

Stop the session and finish processing received records.

A client can only be stopped after a successful connection is made by calling [Live.subscribe](https://databento.com/docs/api-live/client/subscribe.md).

This method does not block waiting for the connection to close.
If this is desired, use [Live.block\_for\_close](https://databento.com/docs/api-live/client/block-for-close.md) or [Live.wait\_for\_close](https://databento.com/docs/api-live/client/wait-for-close.md) to wait for the client to disconnect.

The connection will eventually close after calling this method.
Once the connection has closed, the `Live` client can be reused but the session state is not preserved.

#### API method

```python
Live.stop() -> None
```

#### Example usage

```python
import databento as db

# Create a live client
client = db.Live(key="$YOUR_API_KEY")

# Subscribe to the trades schema for all ES futures
client.subscribe(
    dataset="GLBX.MDP3",
    schema="trades",
    stype_in="parent",
    symbols="ES.FUT",
)

# Start the streaming session
client.start()

# Stop the streaming session
client.stop()
```


### Live.subscribe

Add a new subscription to the session.
All subscriptions must be for the same `dataset`.
The returned integer is the `subscription_id` which will match the id used by the gateway when acknowledging the subscription.

Supports multiple subscriptions for different schemas, which enables rich data streams containing mixed record types.

Specify an optional `start` time for [intraday replay](https://databento.com/docs/api-live/basics/intraday-replay.md) with subscriptions made before starting the session.

Please note there is no unsubscribe method.
Subscriptions end when the client disconnects or by calling [Live.stop](https://databento.com/docs/api-live/client/stop.md) or [Live.terminate](https://databento.com/docs/api-live/client/terminate.md)

#### API method

```python
Live.subscribe(
    dataset: Dataset | str,
    schema: Schema | str,
    symbols: Iterable[str | int] | str | int = "ALL_SYMBOLS",
    stype_in: SType | str = "raw_symbol",
    start: pd.Timestamp | datetime | date | str | int | None = None,
    snapshot: bool = False,
) -> int
```

#### Parameters

| Parameter | Type | Required | Description |
| `dataset` | Dataset or str | required | The [dataset](https://databento.com/docs/api-historical/basics/datasets.md) code (string identifier). Must be one of the values from [list\_datasets](https://databento.com/docs/api-historical/metadata/metadata-list-datasets.md). |
| `schema` | Schema or str | required | The data record [schema](https://databento.com/docs/schemas/whats-a-schema.md). Must be one of the values from [list\_schemas](https://databento.com/docs/api-historical/metadata/metadata-list-schemas.md). |
| `symbols` | Iterable[str \ | int] or str or int | optional | The product symbols to subscribe to. If `'ALL_SYMBOLS'` then will select **all** symbols. |
| `stype_in` | SType or str, default 'raw_symbol' | optional | The [symbology type](https://databento.com/docs/api-historical/basics/symbology.md) of input `symbols`. Must be one of 'raw_symbol', 'instrument_id', 'parent', or 'continuous'. |
| `start` | pd.Timestamp, datetime, date, str or int | optional | The inclusive start of subscription replay. Filters on `ts_event` except for the CBBO and BBO schemas, which filter on `ts_recv`. Takes [pd.Timestamp](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Timestamp.html), [Python datetime](https://docs.python.org/3/library/datetime.html#datetime-objects), [Python date](https://docs.python.org/3/library/datetime.html#date-objects), [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) string, or [UNIX timestamp](https://en.wikipedia.org/wiki/Unix_time) in nanoseconds. Assumes UTC as timezone unless otherwise specified. Must be within the last 24 hours. Pass `0` to request all available data. Cannot be specified after the [session](https://databento.com/docs/api-live/basics/sessions.md) is [started](https://databento.com/docs/api-live/client/start.md). |
| `snapshot` | bool, default False | optional | Request subscription with [snapshot](https://databento.com/docs/conventions/mbo-snapshot.md). Only supported with `mbo` schema. Defaults to `False`. Conflicts with the `start` parameter. |

#### Example usage

```python
import databento as db

# Create a live client
client = db.Live(key="$YOUR_API_KEY")

# Subscribe to the trades schema for all ES futures
client.subscribe(
    dataset="GLBX.MDP3",
    schema="trades",
    stype_in="parent",
    symbols="ES.FUT",
)
```


### Live.terminate

Terminate the session and stop processing records immediately.

A client can only be terminated after a successful connection is made by calling [Live.subscribe](https://databento.com/docs/api-live/client/subscribe.md).

Unlike [Live.stop](https://databento.com/docs/api-live/client/stop.md), the session will end immediately and received records will no longer be processed.

Once terminated, the `Live` client can be reused but the session state is not preserved.

#### API method

```python
Live.terminate() -> None
```

#### Example usage

```python
import databento as db

# Create a live client
client = db.Live(key="$YOUR_API_KEY")

# Subscribe to the trades schema for all ES futures
client.subscribe(
    dataset="GLBX.MDP3",
    schema="trades",
    stype_in="parent",
    symbols="ES.FUT",
)

# Start the streaming session
client.start()

# Terminate the streaming session
client.terminate()
```


### Live.wait\_for\_close

Wait until the session closes or a timeout is reached.
A session will close when the remote gateway disconnects, or after [Live.stop](https://databento.com/docs/api-live/client/terminate.md) or [Live.terminate](https://databento.com/docs/api-live/client/terminate.md) are called.
In the event the connection is closed unexpectedly, a `BentoError` will be raised.

If a `timeout` is specified, [Live.terminate](https://databento.com/docs/api-live/client/terminate.md) will be called when the timeout is reached.

When this method unblocks, the session is guaranteed to be closed.

#### API method

```python
Live.wait_for_close(
    timeout: float | None = None,
) -> None
```

> **Info**
>
> This method is a [coroutine](https://docs.python.org/3/library/asyncio-task.html#coroutines) and must be used with an [await](https://docs.python.org/3/reference/expressions.html#await) expression.

#### Parameters

| Parameter | Type | Required | Description |
| `timeout` | float | optional | A duration in seconds to wait for the session to close. If `None`, wait forever. |

#### Example usage

```python
import databento as db

# Create a live client
client = db.Live(key="$YOUR_API_KEY")

# Subscribe to the trades schema for all ES futures
client.subscribe(
    dataset="GLBX.MDP3",
    schema="trades",
    stype_in="parent",
    symbols="ES.FUT",
)

# Start the session
client.start()

# Wait for the session to end
await client.wait_for_close()
```


### Live.\_\_aiter\_\_
Using [async for](https://docs.python.org/3/reference/compound_stmts.html#the-async-for-statement); records will be yielded as they arrive.
Iteration will stop when the connection is closed and all records are processed.
This is best for integration into asynchronous applications.

Asynchronous iteration is only supported inside a [coroutine](https://docs.python.org/3/library/asyncio-task.html#coroutines).

Asynchronous iteration will automatically call [Live.start](https://databento.com/docs/api-live/client/start.md) if the session is connected but it has not been started.
Starting iteration after the session has started will cause a `ValueError`.

Asynchronous iteration will automatically call [Live.stop](https://databento.com/docs/api-live/client/stop.md) if the iterator is destroyed, such as when an async for loop is escaped with an exception or `break` statement.
To prevent this behavior, an iterator can be created explicitly using [aiter()](https://docs.python.org/3/library/functions.html#aiter).

#### API method

```python
Live.__aiter__() -> AsyncIterator[DBNRecord]
```

#### Example usage

```python
import databento as db

# Create a live client
client = db.Live(key="$YOUR_API_KEY")

# Subscribe to a data stream
client.subscribe(
    dataset="GLBX.MDP3",
    schema="trades",
    stype_in="parent",
    symbols="ES.FUT",
)

# Start streaming and asynchronously iterate the records
async for record in client:
    print(record)
```


### Live.\_\_iter\_\_
Using [for](https://docs.python.org/3/reference/compound_stmts.html#the-for-statement); records will be yielded as they arrive.
Iteration will stop when the connection is closed and all records are processed.
This is best for integration into simple synchronous applications.

Iteration will automatically call [Live.start](https://databento.com/docs/api-live/client/start.md) if the session is connected but it has not been started.
Starting iteration after the session has started will cause a `ValueError`.

Iteration will automatically call [Live.stop](https://databento.com/docs/api-live/client/stop.md) if the iterator is destroyed, such as when a for loop is escaped with an exception or `break` statement.
To prevent this behavior, an iterator can be created explicitly using [iter()](https://docs.python.org/3/library/functions.html#iter).

#### API method

```python
Live.__iter__() -> Iterator[DBNRecord]
```

#### Example usage

```python
import databento as db

# Create a live client
client = db.Live(key="$YOUR_API_KEY")

# Subscribe to a data stream
client.subscribe(
    dataset="GLBX.MDP3",
    schema="trades",
    stype_in="parent",
    symbols="ES.FUT",
)

# Start streaming and synchronously iterate the records
for record in client:
    print(record)
```
