Skip to content

Makeph/binance-fapi-ws

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

binance-fapi-ws

A small, robust async reader for the Binance USDⓈ-M Futures market-data WebSocket. One dependency (websockets), ~150 lines, battle-tested running 24/7 on a live trading bot.

Python 3.9+ tests License: MIT

Most "connect to Binance WS" snippets work for five minutes in a notebook and then silently die in production. This handles the boring, painful parts:

  • Silent dead connections — relies on the WS ping/pong protocol, with a recv timeout longer than the ping interval so a slow-but-alive stream doesn't trigger a false reconnect.
  • Reconnect forever, with backoff — exponential, capped, and reset once a connection actually delivers data.
  • Streams that lie — defaults to the streams that actually deliver on fstream (see GOTCHAS).

Install

pip install websockets
git clone https://github.com/Makeph/binance-fapi-ws

Use it

import asyncio
from binance_fapi_ws import FapiStream, Trade, BookTicker

async def main():
    cvd = 0.0
    async for ev in FapiStream("BTCUSDT").__aiter__():
        if isinstance(ev, Trade):
            cvd += ev.signed_qty          # +qty for buys, -qty for sells
        elif isinstance(ev, BookTicker):
            print(f"mid={ev.mid:,.2f}  spread={ev.spread_bps:.2f}bps  CVD={cvd:+.3f}")

asyncio.run(main())

Multiple symbols, or your own stream set:

FapiStream(["BTCUSDT", "ETHUSDT"])                    # trade + bookTicker each
FapiStream("BTCUSDT", streams=["btcusdt@kline_1m"])   # whatever you want

Runnable demo: examples/print_mid_and_cvd.py.

GOTCHAS (the reason this repo exists)

⚠️ aggTrade and markPrice@1s can deliver zero messages on fstream

Depending on region, the aggregated futures streams (<sym>@aggTrade, <sym>@markPrice@1s) connect successfully and then send nothing — no error, no close, just silence. A naive client looks "connected" forever and your strategy starves.

The fix: use the raw streams, which always deliver:

  • @trade — every individual print. Has the same p/q/m fields, so CVD and trade-flow math are unchanged (just per-trade instead of pre-aggregated).
  • @bookTicker — top-of-book bid/ask; use mid = (bid+ask)/2 in place of the mark price.

This client defaults to @trade + @bookTicker for exactly this reason.

Other things baked in from production pain:

Symptom Cause What this does
Reconnect storm every few seconds recv timeout < ping interval clamps recv_timeout ≥ 1.5 × ping_interval
"Connected" but frozen TCP open, server silent ping/pong + recv timeout force a reconnect
Hammering the API after an outage fixed-delay retry exponential backoff capped at 30s, reset on data
Truncated large frames default max_size max_size=None

API

  • FapiStream(symbols, streams=None, base_url=..., ping_interval=20, ping_timeout=20, recv_timeout=90, max_backoff=30) — async-iterate to get Trade / BookTicker events; call .stop() to end.
  • Trade(symbol, price, qty, buyer_is_maker, ts_ms) with .signed_qty.
  • BookTicker(symbol, bid, ask, bid_qty, ask_qty) with .mid, .spread_bps.
  • parse_message(raw) — pure, network-free frame parser (unit-tested).

Tests

python -m pytest -q     # 8 tests, no network required

Scope & disclaimer

Market data only — no orders, no authentication, no account streams. It's a read-only feed reader. Not affiliated with Binance. MIT licensed.

About

Robust async reader for the Binance USDS-M Futures market-data WebSocket: auto-reconnect with backoff, dead-connection detection, and the streams that actually deliver (aggTrade can be silent on fstream).

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages