# cryptofeed: one normalized Python feed over thirty crypto exchanges

> AGPL Python that subscribes to Binance, Coinbase, Kraken and a couple of dozen others, then hands your callbacks a single data shape, or writes it straight to Kafka, Redis, InfluxDB or a pcap. The 3.0 release moved the floor to Python 3.13 and added a recorded-replay story.

**bmoscon/cryptofeed** — Cryptocurrency Exchange Websocket Data Feed Handler

- Repository: https://github.com/bmoscon/cryptofeed
- Stars: 2,908 · Forks: 765
- Language: Python
- License: NOASSERTION
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/bmoscon-cryptofeed

## Thirty exchanges, one object shape

Every exchange publishes market data in its own format, with its own channel names, its own trade-side convention and its own idea of what a book update means. cryptofeed's job is to sit in front of that and present a single normalized type per event, delivered to a callback you register.

The supported list is long enough to shape a decision: Binance in four flavours including Delivery, Futures and US, Coinbase, Kraken plus Kraken Futures, Bitfinex, Bitstamp, Gemini, OKX, KuCoin, Bybit, Bitget, Deribit, Hyperliquid, dYdX v4, Gate.io and its futures venue, HTX and HTX Swap, MEXC, Phemex, Poloniex, Upbit, bitFlyer, Bithumb, Crypto.com and Independent Reserve.

The channels are the second axis. `L1_BOOK` is top of book, `L2_BOOK` is price-aggregated sizes, `L3_BOOK` is price-aggregated individual orders, and there are `TRADES`, `TICKER`, `FUNDING`, `OPEN_INTEREST`, `LIQUIDATIONS`, `INDEX` and `CANDLES`. Two warnings in the README are worth internalising because they will otherwise surprise you. L2 and L3 are partial on some venues, so depth is not comparable across exchanges without checking. And `TRADES` reports the taker's side even on exchanges that publish the maker's side, which is the right default for computing aggressor flow but means your volume-at-price differs from what the venue shows.

Transports are websockets where available and REST polling where a venue offers no websocket, so a single handler covers venues with different capabilities.

## Wiring up a FeedHandler

The API is three calls: construct a `FeedHandler`, add feeds with channels and callbacks, run. Callbacks are coroutines taking the normalized object plus the timestamp cryptofeed received the message at.

```python
from cryptofeed import FeedHandler
# not all imports shown for clarity

fh = FeedHandler()

# ticker, trade and book are user defined coroutine functions, each taking the
# normalized object and the timestamp cryptofeed received the message at:
#
#     async def trade(t, receipt_timestamp):
#         print(f'{t.exchange} {t.symbol} {t.side} {t.amount} @ {t.price}')
#
# a callback must be async - wrap a synchronous one in cryptofeed.callback.ExecutorCallback
ticker_cb = {TICKER: ticker}
trade_cb = {TRADES: trade}
gemini_cb = {TRADES: trade, L2_BOOK: book}


fh.add_feed(Coinbase(symbols=['BTC-USD'], channels=[TICKER], callbacks=ticker_cb))
fh.add_feed(Bitfinex(symbols=['BTC-USD'], channels=[TICKER], callbacks=ticker_cb))
fh.add_feed(Poloniex(symbols=['BTC-USDT'], channels=[TRADES], callbacks=trade_cb))
fh.add_feed(Gemini(symbols=['BTC-USD', 'ETH-USD'], channels=[TRADES, L2_BOOK], callbacks=gemini_cb))

fh.run()
```

One constraint bites early: callbacks must be async. The README's fix for a synchronous function is `cryptofeed.callback.ExecutorCallback`, which wraps it rather than making you rewrite it as a coroutine.

Symbol naming is normalised too, which is the thing that removes most per-exchange boilerplate. `BTC-USD` and `BTC-USDT` work across venues that spell the same instrument differently, so subscribing to the same symbol on four exchanges reads as four similar lines.

There is also a synthetic feed for cross-venue best bid and offer, aggregated from feeds you nominate, which is a small feature that removes a category of code people otherwise write and get wrong.

## Recording to pcap and replaying it offline

The data capture feature is the one that separates cryptofeed from a thin API wrapper, and the 3.0-era README describes it in more detail than most. A `record` argument on the handler takes a pcap file path or a directory, and `examples/record.py` in the tree wraps it into a small recording tool.

```python
from cryptofeed import FeedHandler

# `record` is a pcap file path or a directory
fh = FeedHandler(record='sample_data/')
fh.add_feed('COINBASE', symbols=['BTC-USD'], channels=[TRADES, L2_BOOK], callbacks=...)
fh.run()
```

Two implementation choices matter here. The pcaps are zstandard compressed by default, and the README notes that Wireshark and tshark open them natively with playback decompression transparent. Metadata lives in a `.meta.json` file alongside. So the capture format is inspectable with tools you already have rather than a proprietary blob, which means when your strategy breaks you can open the raw feed in a packet analyser and see what actually arrived.

There is a `sample_data/` directory at the repository root, so recorded material ships with the project. For a backtesting setup, that is the difference between a replay harness you can develop against offline and one that needs a live account with real money and a working network to test.

The C extension angle shows up here too. `pyproject.toml` declares `order_book>=1.1.0` and `msgspec>=0.19.0` as dependencies, and the README's performance table reports JSON decode rates both with msgspec and with the standard library fallback. The fast path exists; the slow path still runs.

## Backends that skip the callback layer entirely

Some consumers do not want Python objects at all, and the backends exist for them. Redis in sorted sets, streams and keys, ZeroMQ, UDP sockets, TCP sockets, Unix domain sockets, InfluxDB v2, MongoDB, Kafka, PostgreSQL and QuestDB are all listed.

The difference from a callback is worth being precise about. A backend callback writes directly to storage or another interface, so a message goes from the exchange socket to the destination without your Python function executing per event. If your workload is persistence rather than computation, that removes your code from the hot path entirely, which is the difference between keeping up on a busy pair and not.

InfluxDB and QuestDB are the time-series-native options, and QuestDB is the one worth a second look for market data specifically because it is built for append-heavy numeric time series. Kafka covers the case where downstream consumers live in other languages or other teams. Redis streams suit a queue you want to replay. PostgreSQL is the odd one out in that list, and for tick data it is the option you want only after you have thought about write volume.

Optional dependencies are installed individually or all at once with the `all` extra, so you can keep a production image small by pulling only the backend you use.

## Version 3.0 moved the floor to Python 3.13

The 3.0.0 tag was published on 2026-09-22, the same date as the last push to the repository, and the release body on the tag itself is empty. v2.5.0 from 2026-08-09 says only that it is the last 2.x before the major release. So the version history tells you a major boundary was crossed but not, from the release notes, what moved.

The repository does answer it. `pyproject.toml` sets `requires-python` to `>=3.13` and lists classifiers for Python 3.13 and 3.14, along with a free-threading beta classifier and POSIX Linux and macOS as the supported operating systems. The README states the same requirement in plain words and repeats that cryptofeed needs Python 3.13 or newer.

That floor is the main upgrade decision for anyone on 3.11 or 3.12. There are also version-conditional dependencies worth noting, since `zstandard` is pinned to `python_version<'3.14'`, meaning Python 3.14 builds take a different path for the compression layer that the pcap recording feature depends on.

The build requires `setuptools>=77.0.3` and `Cython>=3.1`, which tells you the package is not pure Python at install time. `build-wheels.sh` and `wheels.sh` at the root are the wheel build scripts, and development uses uv with `uv.lock` committed, so `uv sync` from a clone is the reproducible setup path.

## The performance table, read as claims

The README publishes a throughput table measured on Python 3.14.6 over real recorded exchange traffic, which is more than most projects bother with, and it is worth reading carefully because the numbers describe two different things.

Per-object construction is where Python overhead shows: a `Trade` construct is 102 ns, `to_dict` 214 ns, `from_dict` 277 ns, and `Ticker`, `Candle` and `Funding` construct at 70, 118 and 141 ns. A single-level book update is 89 ns, a delete 124 ns, a top-of-book read 140 ns.

The frame-rate rows are the ones that matter for sizing a subscription: message handling is 161k frames per second for Kraken, 134k for Bybit, 122k for KuCoin and around 100k for Kraken Futures. JSON decode with `Decimal` runs at 1.39M messages per second through msgspec and 0.60M through the stdlib fallback, a little over twice the rate for the compiled decoder. Book serialization is the cost centre, with `to_dict` at 2.4 microseconds for ten levels per side and 22.2 for a hundred.

That last row is the practical lesson. Serializing a full book dominates everything else, which is why a backend that writes straight to Kafka or QuestDB can outperform one that converts to Python objects first. The figures are the project's own, on one Python build, on recorded traffic rather than a live exchange, so treat them as a shape of cost rather than a number to plan capacity against.

## Conclusion

cryptofeed earns its place when you need one data shape across several exchanges rather than a single venue's official client, particularly if you also want to record and replay the raw feed for backtesting. It is the wrong tool for placing orders: the README covers public data channels only, and anything authenticated belongs in the exchange SDKs themselves. Install with `pip install cryptofeed` inside a virtual environment on Python 3.13 or newer, add your exchanges with `add_feed`, and read the `pyproject.toml` dependency list before you start, because msgspec, order_book and uvloop are not incidental and Python 3.14 changes which zstandard path you get.

## FAQ

### What is cryptofeed and what does it do?

It is a Python library that connects to websocket or REST data feeds from around thirty cryptocurrency exchanges and returns normalized objects to callbacks you register. Events include trades, ticker updates, funding, open interest, liquidations, index values, candlesticks and L1, L2 and L3 order books, all in one shape regardless of the venue's native format.

### How do I install cryptofeed?

It requires Python 3.13 or newer and installs from PyPI, ideally into a virtual environment: `pip install cryptofeed`. Optional backend dependencies come separately or all at once with `pip install cryptofeed[all]`, and development from a clone uses uv with `uv sync` at the repository root.

### Can cryptofeed place trades or is it read-only?

The documented channels are public data only: books, trades, ticker, funding, open interest, liquidations, index and candles. Nothing in the README describes authenticated endpoints or order placement, so for execution you would use each exchange's own trading SDK alongside cryptofeed's market data feed.

### How does cryptofeed handle exchange-specific book depths and trade sides?

It normalizes rather than equalizes. The README notes that some exchanges provide only a subset of L2 depth and partial L3 depth, and that the trades channel reports the taker's side even on venues that publish the maker's side. Both are deliberate, and both mean you should not compare depth or volume figures across venues without accounting for the difference.

## Sources

- [bmoscon/cryptofeed on GitHub](https://github.com/bmoscon/cryptofeed)
- [Issues](https://github.com/bmoscon/cryptofeed/issues)
- [README](https://github.com/bmoscon/cryptofeed/blob/master/README.md)
- [Releases](https://github.com/bmoscon/cryptofeed/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/bmoscon-cryptofeed
