Binance Python SDK
Project description
binance-sdk
binance-sdk is an unofficial Binance SDK for Python 3.9+, which:
- Based on Binance Official API Docs v3.
- Routes every request/response call (general, market-data, account and trading) over the Binance WebSocket API (
wss://ws-api.binance.com) for low latency, while keeping a genericclient.get/post/put/deleteREST escape hatch for arbitrary endpoints. - Uses TWO WebSocket connections: a market-data stream connection (
subscribe(...)) and a shared WS-API connection (request/response calls + user-data-stream subscription). - Returns
StockDataFrame(fromstock-pandas) for stream payloads with renamed columns. - Based on Python
async/await - Manages the order book for you (handled by
OrderBookHandlerBase), so that you need not to worry about websocket reconnection and message losses. For details, see the sectionOrderBookHandlerBase - Supports changing API endpoints, so that you can use faster API hosts.
Prices and quantities must be strings. The SDK rejects
floatparams at the API boundary because Python'sstr(float)can produce scientific notation (1e-08) or imprecise decimal representations that silently corrupt price/quantity fields. Pass strings (e.g.price='0.00000001') or format withDecimal.
Install
pip install binance-sdk
Basic Usage
#!/usr/bin/env python
import asyncio
from binance import Client
client = Client()
async def main():
print(await client.get_exchange_info())
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Handling messages
Binance-sdk provides handler-based APIs to handle all websocket messages, and you are able to not worry about websockets.
#!/usr/bin/env python
from binance import Client, TickerHandlerBase, SubType
client = Client(api_key)
async def main():
# Implement your own TickerHandler.
class TickerPrinter(TickerHandlerBase):
async def receive(self, payload):
"""The function to receive ticker streams.
The function could either be sync or async
Args:
payload (dict): the raw stream payload which is
message['data'] of the original stream message
"""
# `ticker_df` is a StockDataFrame with columns renamed
ticker_df = super().receive(payload)
# Just print the ticker
print(ticker_df)
# Register the handler for `SubType.TICKER`
client.handler(TickerPrinter())
# Subscribe to ticker change for symbol BTCUSDT
await client.subscribe(SubType.TICKER, 'BTCUSDT')
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
# Run the loop forever to keep receiving messages
loop.run_forever()
# It prints a StockDataFrame for each message
# type event_time symbol open high low ...
# 0 24hrTicker 1581597461196 BTCUSDT 10328.26000000 10491.00000000 10080.00000000 ...
# ...(to be continued)
Subscribe to more symbol pairs and types
# This will subscribe to
# - bnbusdt@aggTrade
# - bnbusdt@depth
# - bnbbtc@aggTrade
# - bnbbtc@depth
await client.subscribe(
# We could also subscribe multiple types
# for both `BNBUSDT` and 'BNBBTC'
[
SubType.AGG_TRADE,
SubType.ORDER_BOOK
],
# We could subscribe more than one symbol pairs at a time
[
# Which is equivalent to `BNBUSDT`
'BNB_USDT',
'BNBBTC'
]
)
And since we subscribe to THREE new types of messages, we need to set the handlers each of which should isinstance() of one of
TradeHandlerBaseAggTradeHandlerBaseBlockTradeHandlerBaseReferencePriceHandlerBaseBookTickerHandlerBasePartialOrderBookHandlerBaseAvgPriceHandlerBaseWindowTickerHandlerBaseOrderBookHandlerBaseKlineHandlerBaseMiniTickerHandlerBaseTickerHandlerBaseAllMarketMiniTickersHandlerBaseAllMarketWindowTickersHandlerBaseAccountPositionHandlerBaseBalanceUpdateHandlerBaseOrderUpdateHandlerBaseOrderListStatusHandlerBaseExternalLockUpdateHandlerBaseEventStreamTerminatedHandlerBaseHandlerExceptionHandlerBasea special handler to handle stream exceptionsStreamErrorHandlerBasea special handler for post-reconnect resubscribe andsession.logonfailures; receives aStreamErrorwithstream/phase/exception/recoveringfields
client.handler(MyTradeHandler(), MyOrderBookHandler(), MyKlineHandler())
Subscribe to user streams
# Before subscribing to the user stream, provide credentials via the constructor.
# HMAC (deprecated by Binance):
client = Client(api_key=api_key, api_secret=api_secret)
# Asymmetric key (recommended — Ed25519 enables session.logon for zero
# per-request signing overhead):
client = Client(api_key=api_key, private_key='/path/to/ed25519.pem')
# binance-sdk handles user stream subscription internally via the
# WebSocket API `userDataStream.subscribe.signature` method.
# With an Ed25519 private_key the WS-API connection also issues
# session.logon automatically after (re)connect.
await client.subscribe(SubType.USER)
Subscribe to handler exceptions
Binance-sdk receives stream messages in background tasks, so sometimes it is difficult to detect the exceptions raised in receive function of user handlers.
Fortunately, we could use HandlerExceptionHandlerBase
from binance import (
HandlerExceptionHandlerBase,
KlineHandlerBase
)
class KlineHandler(KlineHandlerBase):
def receive(self, payload):
raise RuntimeError('this will ruin my day')
class HandlerExceptionHandler(HandlerExceptionHandlerBase):
async def receive(self, exception):
# By calling `super().receive(exception)`,
# it will print the error stack.
super().receive(exception)
await send_to_monitor(exception)
client.handler(KlineHandler())
client.handler(HandlerExceptionHandler())
If you just want to print error stacks, we could:
client.handler(HandlerExceptionHandlerBase())
Handle stream-control errors (resubscribe / logon failures)
After a WebSocket reconnect, the SDK automatically replays all subscriptions. If
that replay (or the WS-API session.logon) fails, the SDK:
- logs the failure at
ERRORlevel, - calls
receiveon every registeredStreamErrorHandlerBase, and - schedules a
recycle()on the affected stream so aioretry starts a fresh reconnect cycle.
from binance import StreamErrorHandlerBase
class MyStreamErrors(StreamErrorHandlerBase):
async def receive(self, error):
# error.stream -> 'data' | 'user'
# error.phase -> 'resubscribe' | 'logon'
# error.exception -> the underlying exception
# error.recovering -> True (SDK is recycling the stream)
await alert_ops_team(
f"Stream {error.stream!r} {error.phase} failed: {error.exception}"
)
client.handler(MyStreamErrors())
APIs
Client(**kwargs)
All arguments of the constructor Client are keyword arguments and all optional.
- api_key?
str=NoneBinance API key - api_secret?
str=NoneBinance API secret for HMAC-SHA256 signing (deprecated by Binance; prefer asymmetric keys viaprivate_key) - private_key?
str|bytes=NoneEd25519 or RSA PEM private key (PEM content or file path). When provided, used for request signing instead ofapi_secret. Binance recommends Ed25519 (fastest) or RSA over the deprecated HMAC keys. With an Ed25519 key the WS-API connection issuessession.logonautomatically after each (re)connect, allowing subsequent signed requests to omitapiKey/signatureentirely. - private_key_pass?
str|bytes=Nonepassword to decrypt an encrypted PEM private key;Nonefor unencrypted keys - request_params?
dict=Noneglobal request params for aiohttp (REST escape hatch) - stream_retry_policy?
Callable[[int, Exception], Tuple[bool, int, bool]]retry policy for websocket streams. For details, see RetryPolicy - stream_timeout?
int=30seconds of stream silence before the SDK pings to probe a possibly-dead connection - rate_limit_guard?
bool=TruewhenTrue, the client proactively throttles requests with a client-side weight/raw/order budget to stay under Binance's per-IP and per-account caps. WhenFalse, usage is still tracked (so monitoring works) but requests are never delayed. See Rate Limits. - rate_limiter?
RateLimiter=Noneinject a sharedRateLimiterinstance so multipleClientobjects on the same IP share one IP-level pool. WhenNone(default) a private limiter is built fromrate_limit_guard. - request_timeout?
float=10total seconds before an aiohttp REST request (via the genericget/post/... escape hatch) is abandoned. - recv_window?
int=NonedefaultrecvWindow(ms) injected into every signed WS-API request that does not already supply one. Clamped to at most 60000 ms.Noneuses Binance's server-side default (5000 ms). Can always be overridden per-call by passingrecvWindow=<value>to any signed method. - time_unit?
str=NoneWebSocket-API timestamp unit.None(default) or'millisecond'keeps Binance's millisecond default;'microsecond'(case-insensitive) opts the whole WS-API connection into microsecond-precision timestamps (appends?timeUnit=MICROSECONDto the connection URL). - api_host?
str='https://api.binance.com'REST host for the genericget/post/put/deleteescape hatch. - stream_host?
str='wss://stream.binance.com'host for the market-data stream connection (subscribe(...)). - ws_api_host?
str='wss://ws-api.binance.com/ws-api/v3'host for the shared WS-API connection (request/response calls + user-data-stream subscription).
Create a binance client.
Each API method accepts only keyworded arguments (kwargs) and has verbosed Python doc strings (Google style) which you could check out when you are coding.
The following example shows how to create a new order.
from binance import (
OrderSide,
OrderType,
TimeInForce
)
# All arguments are keyword arguments.
await client.create_order(
symbol='BTCUSDT',
# Use the built-in enum types to avoid spelling mistakes.
side=OrderSide.BUY,
type=OrderType.LIMIT,
timeInForce=TimeInForce.GTC,
# IMPORTANT: pass prices and quantities as STRINGS, not Python floats.
# The SDK rejects float params — str(float) can produce scientific
# notation ('1e-08') or imprecise decimals that silently corrupt orders.
quantity='10',
price='7000.1'
)
Every request/response call is sent over Binance's WebSocket API (a single
shared connection, opened lazily) rather than REST, while keeping the same
method names and keyword arguments. The public market-data streams
(subscribe(...)) are a separate push mechanism and are unchanged.
General / market-data (public, no credentials):
ping()/get_server_time()/get_exchange_info()get_orderbook(**kwargs)/get_klines(**kwargs)/get_ui_klines(**kwargs)/get_average_price(**kwargs)get_recent_trades(**kwargs)/get_historical_trades(**kwargs)/get_aggregate_trades(**kwargs)get_historical_block_trades(**kwargs)— historical block trades for a symbolget_ticker(**kwargs)/get_ticker_price(**kwargs)/get_orderbook_ticker(**kwargs)get_rolling_window_ticker(**kwargs)— rolling-window price statistics (1m–7d window)get_trading_day_ticker(**kwargs)— trading-day price statistics for a symbol or listget_execution_rules(**kwargs)— per-symbol execution rules (price bands, order limits)get_reference_price(**kwargs)— current reference price for a symbolget_reference_price_calculation(**kwargs)— methodology used to compute the reference price
Account (signed):
get_account(**kwargs)/get_trades(**kwargs)get_commission(**kwargs)— current account commission ratesget_order_rate_limit(**kwargs)— current unfilled order count per order rate limitget_prevented_matches(**kwargs)— orders expired by self-trade preventionget_allocations(**kwargs)— allocations resulting from SOR order placementget_order_amendments(**kwargs)— amendment history for a single orderget_my_filters(**kwargs)— account-relevant filters including MAX_ASSET limits
Trading (signed):
create_order(**kwargs)/create_test_order(**kwargs)get_order(**kwargs)/get_open_orders(**kwargs)/get_all_orders(**kwargs)cancel_order(**kwargs)/cancel_all_orders(**kwargs)cancel_replace_order(**kwargs)— cancel an order and place a new one atomicallyamend_order(**kwargs)— reduce an open order's quantity, keeping its prioritycreate_sor_order(**kwargs)/create_test_sor_order(**kwargs)— Smart Order Routing (live and test)create_oco(**kwargs)/create_oto(**kwargs)/create_otoco(**kwargs)create_opo(**kwargs)— One-Pending-the-Other order listcreate_opoco(**kwargs)— One-Pending-One-Cancels-the-Other order listcancel_oco(**kwargs)/get_oco(**kwargs)/get_all_oco(**kwargs)/get_open_oco(**kwargs)
Session management (the SDK normally manages the session automatically):
get_session_status()— reports which API key is authorizing the current connectionget_session_subscriptions()— lists active user-data subscriptions on the connectionsession_logout()— sendssession.logoutand clears the local auth flag so subsequent signed requests fall back to per-request signing
All take keyword arguments matching the Binance WebSocket API parameters and return the parsed result.
await client.sync_time() -> int
Syncs the local clock offset against Binance server time by issuing the WebSocket-API time request (get_server_time()) and storing server_time - local_time (ms). This offset is added to the timestamp of every signed request, preventing -1021 ("Timestamp for this request is outside of the recvWindow") rejections caused by clock drift.
You do not need to call this manually under normal conditions:
- The offset is applied automatically before the first signed request.
- Whenever a
-1021error is received, the client re-arms and re-syncs before the next signed request.
Call await client.sync_time() explicitly if you want to warm up the offset before trading begins or if you run a periodic resync loop. Returns the new offset in milliseconds.
client.key(api_key) -> self
Define or change api key. This method is unnecessary if we only request APIs of SecurityType.NONE
client.secret(api_secret) -> self
Define or change api secret, especially when we have not define api secret in Client constructor.
api_secret is not always required for using binance-sdk. See Endpoint security type
await client.get(uri, **kwargs)
await client.post(uri, **kwargs)
await client.put(uri, **kwargs)
await client.delete(uri, **kwargs)
- uri
strthe absolute request URL - security_type?
SecurityTypeendpoint security type. Defaults toSecurityType.NONE.
Generic REST escape hatch — sends a GET/POST/PUT/DELETE HTTPS request over the shared aiohttp session. Use this for arbitrary or unwrapped endpoints (e.g. /sapi/ paths) that are not yet covered by the named WS-API methods. Errors from this path surface as RateLimitException (HTTP 429), IPBannedException (HTTP 418), or StatusException (other non-2xx).
await client.subscribe(subtype, *subtype_params) -> None
await client.subscribe(*subscriptions) -> None
- subtype
strsubscription type, should be one ofSubType.*s. For details, see SubType - subtype_params
Listparams for a certainsubtype - subscriptions
List[Tuple]a pack of subscriptions each of which is a tuple ofsubtypeand*subtype_params.
Subscribe to a stream or multiple streams. If no websocket connection is made up, client.subscribe will also create a websocket connection.
from binance import SubType, TimeFrame
await client.subscribe(SubType.TICKER, 'BNBUSDT')
await client.subscribe(SubType.BOOK_TICKER, 'BNBUSDT')
await client.subscribe(SubType.AVG_PRICE, 'BNBUSDT')
await client.subscribe(SubType.WINDOW_TICKER, 'BNBUSDT', TimeFrame.H1)
await client.subscribe(SubType.PARTIAL_ORDER_BOOK, 'BNBUSDT', 20)
await client.subscribe(SubType.PARTIAL_ORDER_BOOK, 'BNBUSDT', 20, 100)
# SubType.ALL_MARKET_MINI_TICKERS
await client.subscribe(SubType.ALL_MARKET_MINI_TICKERS)
# SubType.ALL_MARKET_WINDOW_TICKERS with window 4h
await client.subscribe(SubType.ALL_MARKET_WINDOW_TICKERS, TimeFrame.H4)
# Subcribe to multiple types
await client.subscribe(
(SubType.KLINE, 'BTC_USDT', TimeFrame.D1),
(SubType.KLINE_UTC8, 'BTC_USDT', TimeFrame.D1),
(SubType.TICKER, 'BNBUSDT'),
(
[
SubType.ORDER_BOOK,
SubType.TRADE
],
['BNBUSDT', 'BTCUSDT']
),
(SubType.ALL_MARKET_MINI_TICKERS,) # <-- PAY ATTENTION to the `,` here
)
Possible exceptions:
InvalidSubParamsExceptionUnsupportedSubTypeExceptionInvalidSubTypeParamExceptionStreamAbandonedException
client.start() -> self
Start receiving streams
client.stop() -> self
Stop receiving streams
await client.close(code=4999) -> None
- code
int=4999the custom close code for websocket. It should be in the range 4000 - 4999
Close stream connection, clear all stream subscriptions and clear all handlers.
client.handler(*handlers) -> self
- handlers
List[Union[HandlerExceptionHandlerBase,TradeHandlerBase,...]]
Register message handlers for streams. If we've subscribed to a stream of a certain subtype with no corresponding handler provided, the messages of subtype will not be handled.
Except for HandlerExceptionHandlerBase, handlers each of whose name ends with Base should be inherited before use.
Typically, we need to override the def receive(self, payload) method.
class MyTradeHandler(TradeHandlerBase):
async def receive(self, payload):
# `payload` is a StockDataFrame.
df = super().receive(payload)
await saveTrade(df)
client.handler(MyTradeHandler())
We could also register multiple handlers at one time
client.handler(MyTradeHandler(), MyTickerHandler())
If we register an invalid handler, an InvalidHandlerException exception will be raised.
SubType
In this section, we will note the parameters for each subtypes
SubType with parameters symbol and interval
SubType.KLINESubType.KLINE_UTC8
And interval should be one of the TimeFrame enumerables
SubTypes with a param symbol
SubType.TRADESubType.AGG_TRADESubType.BLOCK_TRADESubType.REFERENCE_PRICESubType.BOOK_TICKERSubType.AVG_PRICESubType.MINI_TICKERSubType.TICKERSubType.ORDER_BOOK
SubTypes with params symbol and level
SubType.PARTIAL_ORDER_BOOK(levelshould be one of5,10,20)
SubTypes with an optional param updateInterval=1000 (ms)
SubType.ORDER_BOOK(1000or100)SubType.PARTIAL_ORDER_BOOK(symbol,level, optionalinterval:1000or100)
SubTypes with an optional param window=TimeFrame.H1
SubType.WINDOW_TICKER(withsymbol; one ofTimeFrame.H1/H4/D1)SubType.ALL_MARKET_WINDOW_TICKERS(one ofTimeFrame.H1/H4/D1)
Subtype with no param
SubType.ALL_MARKET_MINI_TICKERSSubType.USER
RetryPolicy
Retry policy is used by binance-sdk to determine what to do next after the client fails to do some certain thing.
abandon, delay = stream_retry_policy(info)
# `info.fails` is the counter number of
# how many times has the stream encountered the connection failure.
# If the stream is disconnected just now for the first time, `info.fails` will be `1`
# `info.exception` is the exception that raised which caused the failure
# If abandon is `True`, then the client will give up reconnecting.
# Otherwise:
# - The client will asyncio.sleep `delay` seconds before reconnecting.
Since 3.2.0 the default policy is a bounded, jittered exponential backoff (≈0.5s → 30s, never abandoning). See Rate Limits for why.
Rate Limits
binance-sdk is built to respect Binance's documented rate limits and to avoid the 429 → 418 IP-ban escalation (which can take a live trading system offline for up to 3 days). Since 3.3.0 every limit — REST and WebSocket — is tracked by a single unified rate-limit core, and you can read its live state through client.rate_limit_snapshot().
The pools
Binance enforces several independent pools; the core models each one:
| Pool | Scope | Default budget | On exceed (guard on) |
|---|---|---|---|
| Request weight | IP | 6000 / 1m (used at 90% → 5400) | sleep until headroom |
| Raw requests | IP | 300000 / 5m | sleep until headroom |
| Orders | account | 100 / 10s and 200000 / 1d | raise RateLimitReachedException |
| WS connections | IP | 290 / 5m | sleep until headroom |
| WS messages | per connection | 5 / 1s | sleep until headroom |
| WS streams | per connection | 1024 (cap) | raise TooManyStreamsException |
Orders never sleep — delaying an order can be worse than not sending it, so an over-budget order fails fast with RateLimitReachedException (carrying retry_after) and lets your strategy decide. Usage is always accounted (even with the guard off), so monitoring stays accurate.
WS-API: typed errors from trading/account/market-data calls
Trading, account, and market-data calls now go over the WS-API connection. Server errors on this path surface as:
StreamSubscribeException— any server-side error (code/msgfields match the Binance WS-API error object).StreamRateLimitException(subclass ofStreamSubscribeException) — rate-limit rejection (code-1003, status429/418); carriesretry_afterin milliseconds.
from binance import StreamSubscribeException, StreamRateLimitException
try:
await client.create_order(symbol='BTCUSDT', side='BUY', ...)
except StreamRateLimitException as e:
# WS-API rate-limited; e.retry_after is milliseconds
await asyncio.sleep(e.retry_after / 1000)
except StreamSubscribeException as e:
print(f'WS-API error {e.code}: {e.msg}')
REST escape hatch: typed errors
The generic client.get/post/put/delete REST path raises typed HTTP exceptions:
from binance import RateLimitException, IPBannedException, StatusException
try:
await client.get('https://api.binance.com/sapi/v1/...')
except IPBannedException as e:
# HTTP 418 — your IP is banned; wait it out
await asyncio.sleep(e.retry_after)
except RateLimitException as e:
# HTTP 429 — too many requests; back off
await asyncio.sleep(e.retry_after)
except StatusException as e:
print(f'HTTP {e.status_code}: {e.response}')
Both RateLimitException and IPBannedException subclass StatusException. The client never auto-retries — it surfaces retry_after and lets your strategy decide.
REST: used-weight visibility
The rate-limit headers on every REST response are captured. After any REST escape-hatch call you can read the latest values:
await client.get('https://api.binance.com/api/v3/exchangeInfo')
client.used_weight # e.g. {'1m': 20} (from X-MBX-USED-WEIGHT-*)
client.order_count # e.g. {'10s': 3} (from X-MBX-ORDER-COUNT-*)
REST: proactive throttle
By default (rate_limit_guard=True) the client throttles before sending a request that would breach the IP request-weight, IP raw-request, or account-order pools. Recommended for live trading:
client = Client(api_key, api_secret, rate_limit_guard=True)
The per-endpoint weight table is a conservative pre-throttle; the authoritative truth is always the X-MBX-USED-WEIGHT-* / X-MBX-ORDER-COUNT-* response headers, which the core reconciles after every call (used = max(client_estimate, header)). With rate_limit_guard=False, usage is still tracked (so monitoring works) but requests are never delayed.
Whenever a response carries Binance's rateLimits array (e.g. from get_exchange_info()), the core auto-configures its pool limits from it — so on a higher VIP tier the budgets track your account's real caps instead of the conservative defaults.
Monitoring: client.rate_limit_snapshot()
rate_limit_snapshot() returns a read-only, local (no network) RateLimitSnapshot you can poll from a monitoring loop or risk gate:
snap = client.rate_limit_snapshot()
snap.max_utilization # 0.0–1.0+, the busiest pool right now
snap.throttled # True if anything is queued/sleeping or a retry-after is active
snap.retry_after # seconds remaining on a 429/418 ban, or None
snap.pending # total calls currently waiting on a pool
for w in snap.windows:
print(w.scope, w.type, w.interval, f'{w.used}/{w.limit}', w.utilization, w.source)
# e.g. ip request_weight 1m 5400/5400 1.0 header
A RateLimitWindow describes one pool: scope (ip/account/connection), type (request_weight/raw_requests/orders/ws_connections/ws_messages/ws_streams), interval (1m, 10s, …), used, limit (the effective, safety-adjusted cap), remaining, utilization (used/limit), pending, and source — header when reconciled from an authoritative Binance header, otherwise client (a local estimate). RateLimitSnapshot exposes windows, pending, retry_after, throttled, at (epoch seconds), and the max_utilization property. Both types are importable from binance.
WebSocket: connection, message, and stream limits
- Connections are gated to stay under Binance's 300 attempts / 5 min / IP limit (a shared limiter, default cap 290/5min), independent of your
stream_retry_policy. - Outgoing messages are limited to 5/second (Binance's documented limit, including ping/pong and subscribe/unsubscribe).
- Streams per connection are capped at Binance's 1024 limit; exceeding it raises
TooManyStreamsException(carryingrequested/limit) instead of failing opaquely. serverShutdownevents (sent ~10 min before Binance's 24h forced disconnect) trigger a proactive reconnect.
WebSocket-API (user stream) rate-limit errors (code -1003, status 418/429) raise StreamRateLimitException (a subclass of StreamSubscribeException) carrying retry_after.
Behavioral changes in 3.4.0
- Asymmetric signing:
Client(private_key=..., private_key_pass=...)now signs requests with Ed25519 or RSA (Binance's recommended key types; HMAC viaapi_secretremains the default fallback). - Server-time sync: signed requests auto-sync a clock offset (and re-sync on
-1021) to avoid timestamp-out-of-recvWindow rejections; callawait client.sync_time()to warm it up. - Per-symbol order book depth:
OrderBookHandlerBase.orderbook(symbol, limit=...)overrides the snapshot depth for a single symbol. - Removed the dead
wapi/sapiAPI surface (get_deposit_history,withdraw, sub-account helpers, etc.): every endpoint returned 404 from Binance. Proper/sapi/support, if needed, will be a separate addition. - WebSocket keepalive simplified: the redundant
websocketsclient-side ping is disabled (the library still auto-replies pong to Binance server pings);stream_timeoutnow defaults to 30s.
Behavioral changes in 3.3.0
- All rate limiting — REST weight/raw/orders and WS connections/messages/streams — now flows through one unified core (
binance.rate_limit), the single source of truth. - New
client.rate_limit_snapshot()returns aRateLimitSnapshotfor live monitoring;RateLimiter,RateLimitSnapshot, andRateLimitWindoware now exported frombinance. - The account orders pool is now enforced (100/10s and 200000/1d), failing fast with
RateLimitReachedExceptionrather than sleeping. - Responses carrying a
rateLimitsarray auto-configure the pool limits. - The previously documented
stream_message_rateconstructor argument has been removed; the 5/s outgoing-message limit is now managed by the core per connection.
Behavioral changes in 3.2.0
- Reconnect backoff is now bounded and jittered (≈0.5s → 30s, never abandoning) instead of the previous near-zero-delay loop. Reconnection is intentionally slower but cannot trigger an IP ban; override with your own
stream_retry_policyif you need different behavior. 429/418now raiseRateLimitException/IPBannedException(subclasses ofStatusException).- The WebSocket outgoing-message rate now defaults to the documented 5/s.
OrderBookHandlerBase(**kwargs)
- kwargs
- limit?
int=1000the limit of the depth snapshot (default 1000, max 5000 — any value; Binance caps at 5000) - retry_policy?
RetryPolicy=
- limit?
By default, binance-sdk maintains the orderbook for you according to the rules of the official documentation.
Specifically, OrderBookHandlerBase does the job.
We can get the managed OrderBook object by method handler.orderbook(symbol). The handler-level limit (default 1000) applies to every symbol; to use a different snapshot depth for a single symbol, pass handler.orderbook(symbol, limit=...) before subscribing (default 1000, max 5000; any value is accepted and Binance caps it at 5000).
async def main():
client = Client(api_key)
# Unlike other handlers, we usually do not need to inherit `OrderBookHandlerBase`,
# unless we need to receive the raw payload of 'depthUpdate' message
handler = OrderBookHandlerBase()
client.handler(handler)
await client.subscribe(SubType.ORDER_BOOK, 'BTCUSDT')
# Get the reference of OrderBook object for 'BTCUSDT'
orderbook = handler.orderbook('BTCUSDT')
while True:
# If the `retry_policy` never abandon a retry,
# the 'try' block could be emitted
try:
await orderbook.updated()
except Exception as e:
print('exception occurred')
else:
await doSomethingWith(orderbook.asks, orderbook.bids)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.run_forever()
OrderBook(symbol, **kwargs)
- symbol
strthe symbol name - kwargs
- limit?
int=1000limit of the orderbook snapshot (default 1000, max 5000 — any value; Binance caps at 5000) - client
Client=Nonethe instance ofbinance.Client - retry_policy?
Callable[[int, Exception], (bool, int, bool)]retry policy for depth snapshot which has the same mechanism asClient::stream_retry_policy
- limit?
OrderBook is another public class that we could import from binance-sdk and you could also construct your own OrderBook instance.
async def main():
# PAY attention that `orderbook` should be run in an event loop
orderbook = OrderBook('BTCUSDT', client=client)
await orderbook.updated()
print(orderbook.asks)
orderbook.set_client(client) -> None
- client
Clientthe instance ofbinance.Client
Set the client. If client is not specified in the constructor, then executing this method will make the orderbook to fetch the snapshot for the first time.
orderbook.set_limit(limit) -> None
- limit
int
Set depth limit which is used by the Binance WebSocket API depth request.
orderbook.set_retry_policy(retry_policy) -> None
- retry_policy
RetryPolicy
Set retry policy of the certain orderbook
property orderbook.ready -> bool
There is a property getter in orderbook to detect whether the asks and bids are updated in the orderbook.
If there is a network malfunction of the stream which causing the gap between two depth update messages, orderbook will fetch a new snapshot from the server, and during that time and before we merge the snapshot, orderbook.ready is False.
property orderbook.asks -> list
property orderbook.bids -> list
Get asks and bids in ascending order.
orderbook.update(payload) -> bool
- payload
dictthe data payload of thedepthUpdatestream message
Returns True if the payload is valid and is updated to the orderbook, otherwise False
If the return value is False, the orderbook will automatically start fetching the snapshot
await orderbook.fetch() -> None
Manually fetch the snapshot.
For most scenarios, you need NOT to call this method because once there is an invalid payload, the orderbook will fetch the snapshot itself.
await orderbook.updated() -> None
Wait for the next update of the orderbook.
We could also await orderbook.updated() to make sure the orderbook is ready.
If the orderbook fails to fetch depth snapshot for so many times which means the fetching is abanboned by the retry_policy, an aiohttp exception will be raised.
Listen to the updates of orderbook
async def start_listening_updates(orderbook):
# This is an infinite loop
while True:
await orderbook.updated()
# do something
def start():
return asyncio.create_task(start_listening_updates(orderbook))
task = start()
# If we want to stop listening
task.cancel()
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file binance_sdk-4.0.0.tar.gz.
File metadata
- Download URL: binance_sdk-4.0.0.tar.gz
- Upload date:
- Size: 167.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
095696aad700193fa759ae2c2bbe26a3e2cd7d55f36fe0daab6ff5430e357acd
|
|
| MD5 |
90cade9465406df131563fbade3322d8
|
|
| BLAKE2b-256 |
09dacf82c2d1884517ebdacf80518d9d5635a25290176a6f1da285b3fc21c0e0
|
File details
Details for the file binance_sdk-4.0.0-py3-none-any.whl.
File metadata
- Download URL: binance_sdk-4.0.0-py3-none-any.whl
- Upload date:
- Size: 99.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fbc991b8f179ca6e3e3988fb6ea818e645db2fbc34079c028382ebf2e00c57f7
|
|
| MD5 |
c8626d755901eb32a76c458c2e721066
|
|
| BLAKE2b-256 |
53942703d91ba7c685d92a713a4f9f7aad9f1c1049ee0a9dc0299ac149311ee3
|