Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
binance-sdk
is an another unofficial Binance SDK for python 3.7+, which:
pandas.DataFrame
support. If pandas
is installed, columns of all stream data frames are renamed for readability.async
/await
OrderBookHandlerBase
), so that you need not to worry about websocket reconnection and message losses. For details, see the section OrderBookHandlerBase
# Without pandas support
pip install binance-sdk
or
# With pandas support
pip install binance-sdk[pandas]
#!/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())
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
"""
# If binance-sdk is installed with pandas support, then
# `ticker` will be a `DataFrame` with columns renamed
# Otherwise, it is unnecessary to call `super().receive`.
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 pandas.DataFrame for each message
# type event_time symbol open high low ...
# 0 24hrTicker 1581597461196 BTCUSDT 10328.26000000 10491.00000000 10080.00000000 ...
# ...(to be continued)
# 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
TradeHandlerBase
AggTradeHandlerBase
OrderBookHandlerBase
KlineHandlerBase
MiniTickerHandlerBase
TickerHandlerBase
AllMarketMiniTickersHandlerBase
AllMarketTickersHandlerBase
AccountInfoHandlerBase
AccountPositionHandlerBase
BalanceUpdateHandlerBase
OrderUpdateHandlerBase
OrderListStatusHandlerBase
HandlerExceptionHandlerBase
a special handler to handle stream exceptionsclient.handler(MyTradeHandler(), MyOrderBookHandler(), MyKlineHandler())
# Before subscribe to user stream, you need to provide `api_secret` (and also `api_key`)
client.secret(api_secret)
# Or, you should provide `api_secret` when initialize the client
# ```
# client = Client(api_key, api_secret)
# ```
# binance-sdk will handle user listen key internally without your concern
await client.subscribe(SubType.USER)
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())
All arguments of the constructor Client are keyworded arguments and all optional.
str=None
binance api keystr=None
binance api secretdict=None
global request params for aiohttpCallable[[int, Exception], Tuple[bool, int, bool]]
retry policy for websocket stream. For details, see RetryPolicyint=5
seconds util the stream reach an timeout errorstr='https://api.binance.com'
to specify another API host for rest API requests. 这个参数的存在意义,使用方法,不累述,你懂的。str='wss://stream.binance.com'
to specify another stream host for websocket connections.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 keyworded arguments.
await client.create_order(
symbol='BTCUSDT',
# You could use string `BUY` (NOT recommended) instead of
# the built-in enum types of Binance-sdk.
# But it is a good practise to use enums which could help
# us to avoid spelling mistakes, and save our money.
side=OrderSide.BUY,
type=OrderType.LIMIT,
timeInForce=TimeInForce.GTC,
# Binance-sdk will not handle Decimals for you,
# so you'd better to know how to deal with python float precisions.
# Or you could use string-type quantity.
quantity=10.,
# It is better to use string type instead of float.
# The same as `quantity`
price='7000.1'
)
Define or change api key. This method is unnecessary if we only request APIs of SecurityType.NONE
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
str
the request urlSecurityType
endpoint security type. Defaults to SecurityType.NONE
.Send a GET/POST/PUT/DELETE HTTPs request.
str
subscription type, should be one of SubType.*
s. For details, see SubTypeList
params for a certain subtype
List[Tuple]
a pack of subscriptions each of which is a tuple of subtype
and *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, KlineInterval
await client.subscribe(SubType.TICKER, 'BNBUSDT')
# SubType.ALL_MARKET_MINI_TICKERS with default param
await client.subscribe(SubType.ALL_MARKET_MINI_TICKERS)
# SubType.ALL_MARKET_MINI_TICKERS with update interval 3000ms
await client.subscribe(SubType.ALL_MARKET_MINI_TICKERS, 3000)
# Subcribe to multiple types
await client.subscribe(
(SubType.KLINE, 'BTC_USDT', KlineInterval.DAY),
(SubType.TICKER, 'BNBUSDT'),
(
[
SubType.ORDER_BOOK,
SubType.TRADE
],
['BNBUSDT', 'BTCUSDT']
),
(SubType.ALL_MARKET_MINI_TICKERS,) # <-- PAY ATTENTION to the `,` here
)
Possible exceptions:
InvalidSubParamsException
UnsupportedSubTypeException
InvalidSubTypeParamException
StreamAbandonedException
Start receiving streams
Stop receiving streams
int=4999
the custom close code for websocket. It should be in the range 4000 - 4999Close stream connection, clear all stream subscriptions and clear all 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):
# If pandas is installed, then `payload` is a `pandas.DataFrame`,
# otherwise is a dict.
df = super().receive(payload)
# If you don't want the `pandas.DataFrame`, use `payload` directly
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.
In this section, we will note the parameters for each subtypes
SubType
with parameters symbol
and interval
SubType.KLINE
And interval
should be one of the KlineInterval
enumerables
SubType
s with a param symbol
SubType.TRADE
SubType.AGG_TRADE
SubType.MINI_TICKER
SubType.TICKER
SubType.ORDER_BOOK
SubType
s with an optional param updateInterval=1000
(ms)SubType.ALL_MARKET_MINI_TICKERS
SubType.ALL_MARKET_TICKERS
Subtype
with no paramSubType.USER
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.
int=100
the limit of the depth snapshotRetryPolicy=
By default, binance-sdk maintains the orderbook for you according to the rules of the official documentation.
Specifically, OrderBookHandlerBase
does the job.
We could get the managed OrderBook
object by method handler.orderbook(symbol)
.
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()
str
the symbol nameint=100
limit of the orderbookClient=None
the instance of binance.Client
Callable[[int, Exception], (bool, int, bool)]
retry policy for depth snapshot which has the same mechanism as Client::stream_retry_policy
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)
Client
the instance of binance.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.
int
Set depth limit which is used by binance reset api.
RetryPolicy
Set retry policy of the certain orderbook
orderbook.ready
-> boolThere 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
.
orderbook.asks
-> listorderbook.bids
-> listGet asks and bids in ascending order.
dict
the data payload of the depthUpdate
stream messageReturns 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
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.
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.
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()
FAQs
Binance Python SDK
We found that binance-sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.