Skip to content

Commit e25b81e

Browse files
authored
Merge pull request binance-exchange#1 from sammchardy/master
update to latest
2 parents 2c2b3bf + 3f3cc65 commit e25b81e

11 files changed

Lines changed: 1714 additions & 131 deletions

File tree

Endpoints.md

Lines changed: 778 additions & 0 deletions
Large diffs are not rendered by default.

README.rst

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
================================
2-
Welcome to python-binance v0.7.5
2+
Welcome to python-binance v0.7.8
33
================================
44

55
Note
66
----
77

8-
I am working on a python3 version with async support to remove legacy dependencies and their related issues.
9-
10-
I would appreciate if you could try out the `feature/asyncio <https://github.com/sammchardy/python-binance/tree/feature/asyncio>`_ branch and give your feedback.
11-
8+
this library is not under active development by sammchardy. however, the community has been actively contributing lots of PRs. If you find missing features please submit a PR. please keep PRs small and non-breaking.
129

1310
.. image:: https://img.shields.io/pypi/v/python-binance.svg
1411
:target: https://pypi.python.org/pypi/python-binance
@@ -28,7 +25,7 @@ I would appreciate if you could try out the `feature/asyncio <https://github.com
2825
.. image:: https://img.shields.io/pypi/pyversions/python-binance.svg
2926
:target: https://pypi.python.org/pypi/python-binance
3027

31-
This is an unofficial Python wrapper for the `Binance exchange REST API v1/3 <https://github.com/binance-exchange/binance-official-api-docs>`_. I am in no way affiliated with Binance, use at your own risk.
28+
This is an unofficial Python wrapper for the `Binance exchange REST API v3 <https://github.com/binance/binance-spot-api-docs>`_. I am in no way affiliated with Binance, use at your own risk.
3229

3330
If you came here looking for the `Binance exchange <https://www.binance.com/?ref=10099792>`_ to purchase cryptocurrencies, then `go here <https://www.binance.com/?ref=10099792>`_. If you want to automate interactions with Binance stick around.
3431

binance/client.py

Lines changed: 639 additions & 92 deletions
Large diffs are not rendered by default.

binance/depthcache.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ class DepthCacheManager(object):
121121

122122
_default_refresh = 60 * 30 # 30 minutes
123123

124-
def __init__(self, client, symbol, callback=None, refresh_interval=_default_refresh, bm=None, limit=500):
124+
def __init__(self, client, symbol, callback=None, refresh_interval=_default_refresh, bm=None, limit=500, ws_interval=None):
125125
"""Initialise the DepthCacheManager
126126
127127
:param client: Binance API client
@@ -134,6 +134,8 @@ def __init__(self, client, symbol, callback=None, refresh_interval=_default_refr
134134
:type refresh_interval: int
135135
:param limit: Optional number of orders to get from orderbook
136136
:type limit: int
137+
:param ws_interval: Optional interval for updates on websocket, default None. If not set, updates happen every second. Must be 0, None (1s) or 100 (100ms).
138+
:type ws_interval: int
137139
138140
"""
139141
self._client = client
@@ -146,6 +148,7 @@ def __init__(self, client, symbol, callback=None, refresh_interval=_default_refr
146148
self._depth_cache = DepthCache(self._symbol)
147149
self._refresh_interval = refresh_interval
148150
self._conn_key = None
151+
self._ws_interval = ws_interval
149152

150153
self._start_socket()
151154
self._init_cache()
@@ -188,7 +191,7 @@ def _start_socket(self):
188191
if self._bm is None:
189192
self._bm = BinanceSocketManager(self._client)
190193

191-
self._conn_key = self._bm.start_depth_socket(self._symbol, self._depth_event)
194+
self._conn_key = self._bm.start_depth_socket(self._symbol, self._depth_event, interval=self._ws_interval)
192195
if not self._bm.is_alive():
193196
self._bm.start()
194197

@@ -271,3 +274,10 @@ def close(self, close_socket=False):
271274
self._bm.close()
272275
time.sleep(1)
273276
self._depth_cache = None
277+
278+
def get_symbol(self):
279+
"""Get the symbol
280+
281+
:return: symbol
282+
"""
283+
return self._symbol

binance/websockets.py

Lines changed: 163 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def clientConnectionLost(self, connector, reason):
6464
class BinanceSocketManager(threading.Thread):
6565

6666
STREAM_URL = 'wss://stream.binance.com:9443/'
67+
FSTREAM_URL = 'wss://fstream.binance.com/'
6768

6869
WEBSOCKET_DEPTH_5 = '5'
6970
WEBSOCKET_DEPTH_10 = '10'
@@ -84,9 +85,10 @@ def __init__(self, client, user_timeout=DEFAULT_USER_TIMEOUT):
8485
self._conns = {}
8586
self._client = client
8687
self._user_timeout = user_timeout
87-
self._timers = {'user': None, 'margin': None}
88+
self._timers = {'user': None, 'margin': None}
8889
self._listen_keys = {'user': None, 'margin': None}
8990
self._account_callbacks = {'user': None, 'margin': None}
91+
# Isolated margin sockets will be opened under the 'symbol' name
9092

9193
def _start_socket(self, path, callback, prefix='ws/'):
9294
if path in self._conns:
@@ -102,7 +104,21 @@ def _start_socket(self, path, callback, prefix='ws/'):
102104
self._conns[path] = connectWS(factory, context_factory)
103105
return path
104106

105-
def start_depth_socket(self, symbol, callback, depth=None):
107+
def _start_futures_socket(self, path, callback, prefix='stream?streams='):
108+
if path in self._conns:
109+
return False
110+
111+
factory_url = self.FSTREAM_URL + prefix + path
112+
factory = BinanceClientFactory(factory_url)
113+
factory.protocol = BinanceClientProtocol
114+
factory.callback = callback
115+
factory.reconnect = True
116+
context_factory = ssl.ClientContextFactory()
117+
118+
self._conns[path] = connectWS(factory, context_factory)
119+
return path
120+
121+
def start_depth_socket(self, symbol, callback, depth=None, interval=None):
106122
"""Start a websocket for symbol market depth returning either a diff or a partial book
107123
108124
https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#partial-book-depth-streams
@@ -113,6 +129,8 @@ def start_depth_socket(self, symbol, callback, depth=None):
113129
:type callback: function
114130
:param depth: optional Number of depth entries to return, default None. If passed returns a partial book instead of a diff
115131
:type depth: str
132+
:param interval: optional interval for updates, default None. If not set, updates happen every second. Must be 0, None (1s) or 100 (100ms)
133+
:type interval: int
116134
117135
:returns: connection key string if successful, False otherwise
118136
@@ -169,6 +187,11 @@ def start_depth_socket(self, symbol, callback, depth=None):
169187
socket_name = symbol.lower() + '@depth'
170188
if depth and depth != '1':
171189
socket_name = '{}{}'.format(socket_name, depth)
190+
if interval:
191+
if interval in [0, 100]:
192+
socket_name = '{}@{}ms'.format(socket_name, interval)
193+
else:
194+
raise ValueError("Websocket interval value not allowed. Allowed values are [0, 100]")
172195
return self._start_socket(socket_name, callback)
173196

174197
def start_kline_socket(self, symbol, callback, interval=Client.KLINE_INTERVAL_1MINUTE):
@@ -406,6 +429,99 @@ def start_ticker_socket(self, callback):
406429
"""
407430
return self._start_socket('!ticker@arr', callback)
408431

432+
def start_symbol_mark_price_socket(self, symbol, callback, fast=True):
433+
"""Start a websocket for a symbol's futures mark price
434+
https://binance-docs.github.io/apidocs/futures/en/#mark-price-stream
435+
:param symbol: required
436+
:type symbol: str
437+
:param callback: callback function to handle messages
438+
:type callback: function
439+
:returns: connection key string if successful, False otherwise
440+
Message Format
441+
.. code-block:: python
442+
{
443+
"e": "markPriceUpdate", // Event type
444+
"E": 1562305380000, // Event time
445+
"s": "BTCUSDT", // Symbol
446+
"p": "11185.87786614", // Mark price
447+
"r": "0.00030000", // Funding rate
448+
"T": 1562306400000 // Next funding time
449+
}
450+
"""
451+
stream_name = '@markPrice@1s' if fast else '@markPrice'
452+
return self._start_futures_socket(symbol.lower() + stream_name, callback)
453+
454+
def start_all_mark_price_socket(self, callback, fast=True):
455+
"""Start a websocket for all futures mark price data
456+
By default all symbols are included in an array.
457+
https://binance-docs.github.io/apidocs/futures/en/#mark-price-stream-for-all-market
458+
:param callback: callback function to handle messages
459+
:type callback: function
460+
:returns: connection key string if successful, False otherwise
461+
Message Format
462+
.. code-block:: python
463+
464+
[
465+
{
466+
"e": "markPriceUpdate", // Event type
467+
"E": 1562305380000, // Event time
468+
"s": "BTCUSDT", // Symbol
469+
"p": "11185.87786614", // Mark price
470+
"r": "0.00030000", // Funding rate
471+
"T": 1562306400000 // Next funding time
472+
}
473+
]
474+
"""
475+
stream_name = '!markPrice@arr@1s' if fast else '!markPrice@arr'
476+
return self._start_futures_socket(stream_name, callback)
477+
478+
def start_symbol_ticker_futures_socket(self, symbol, callback):
479+
"""Start a websocket for a symbol's ticker data
480+
By default all markets are included in an array.
481+
https://binance-docs.github.io/apidocs/futures/en/#individual-symbol-book-ticker-streams
482+
:param symbol: required
483+
:type symbol: str
484+
:param callback: callback function to handle messages
485+
:type callback: function
486+
:returns: connection key string if successful, False otherwise
487+
.. code-block:: python
488+
[
489+
{
490+
"u":400900217, // order book updateId
491+
"s":"BNBUSDT", // symbol
492+
"b":"25.35190000", // best bid price
493+
"B":"31.21000000", // best bid qty
494+
"a":"25.36520000", // best ask price
495+
"A":"40.66000000" // best ask qty
496+
}
497+
]
498+
"""
499+
return self._start_futures_socket(symbol.lower() + '@bookTicker', callback)
500+
501+
def start_all_ticker_futures_socket(self, callback):
502+
"""Start a websocket for all ticker data
503+
By default all markets are included in an array.
504+
https://binance-docs.github.io/apidocs/futures/en/#all-book-tickers-stream
505+
:param callback: callback function to handle messages
506+
:type callback: function
507+
:returns: connection key string if successful, False otherwise
508+
Message Format
509+
.. code-block:: python
510+
[
511+
{
512+
"u":400900217, // order book updateId
513+
"s":"BNBUSDT", // symbol
514+
"b":"25.35190000", // best bid price
515+
"B":"31.21000000", // best bid qty
516+
"a":"25.36520000", // best ask price
517+
"A":"40.66000000" // best ask qty
518+
}
519+
]
520+
"""
521+
522+
523+
return self._start_futures_socket('!bookTicker', callback)
524+
409525
def start_symbol_book_ticker_socket(self, symbol, callback):
410526
"""Start a websocket for the best bid or ask's price or quantity for a specified symbol.
411527
@@ -482,6 +598,7 @@ def start_user_socket(self, callback):
482598
"""Start a websocket for user data
483599
484600
https://github.com/binance-exchange/binance-official-api-docs/blob/master/user-data-stream.md
601+
https://binance-docs.github.io/apidocs/spot/en/#listen-key-spot
485602
486603
:param callback: callback function to handle messages
487604
:type callback: function
@@ -496,9 +613,9 @@ def start_user_socket(self, callback):
496613
return self._start_account_socket('user', user_listen_key, callback)
497614

498615
def start_margin_socket(self, callback):
499-
"""Start a websocket for margin data
616+
"""Start a websocket for cross-margin data
500617
501-
https://github.com/binance-exchange/binance-official-api-docs/blob/master/user-data-stream.md
618+
https://binance-docs.github.io/apidocs/spot/en/#listen-key-margin
502619
503620
:param callback: callback function to handle messages
504621
:type callback: function
@@ -512,6 +629,25 @@ def start_margin_socket(self, callback):
512629
# and start the socket with this specific key
513630
return self._start_account_socket('margin', margin_listen_key, callback)
514631

632+
def start_isolated_margin_socket(self, symbol, callback):
633+
"""Start a websocket for isolated margin data
634+
635+
https://binance-docs.github.io/apidocs/spot/en/#listen-key-isolated-margin
636+
637+
:param symbol: required - symbol for the isolated margin account
638+
:type symbol: str
639+
:param callback: callback function to handle messages
640+
:type callback: function
641+
642+
:returns: connection key string if successful, False otherwise
643+
644+
Message Format - see Binance API docs for all types
645+
"""
646+
# Get the isolated margin listen key
647+
isolated_margin_listen_key = self._client.isolated_margin_stream_get_listen_key(symbol)
648+
# and start the socket with this specific kek
649+
return self._start_account_socket(symbol, isolated_margin_listen_key, callback)
650+
515651
def _start_account_socket(self, socket_type, listen_key, callback):
516652
"""Starts one of user or margin socket"""
517653
self._check_account_socket_open(listen_key)
@@ -542,10 +678,15 @@ def _keepalive_account_socket(self, socket_type):
542678
if socket_type == 'user':
543679
listen_key_func = self._client.stream_get_listen_key
544680
callback = self._account_callbacks[socket_type]
545-
else:
681+
listen_key = listen_key_func()
682+
elif socket_type == 'margin': # cross-margin
546683
listen_key_func = self._client.margin_stream_get_listen_key
547684
callback = self._account_callbacks[socket_type]
548-
listen_key = listen_key_func()
685+
listen_key = listen_key_func()
686+
else: # isolated margin
687+
listen_key_func = self._client.isolated_margin_stream_get_listen_key
688+
callback = self._account_callbacks.get(socket_type, None)
689+
listen_key = listen_key_func(socket_type) # Passing symbol for islation margin
549690
if listen_key != self._listen_keys[socket_type]:
550691
self._start_account_socket(socket_type, listen_key, callback)
551692

@@ -565,18 +706,26 @@ def stop_socket(self, conn_key):
565706
self._conns[conn_key].disconnect()
566707
del(self._conns[conn_key])
567708

568-
# check if we have a user stream socket
569-
if len(conn_key) >= 60 and conn_key[:60] == self._listen_keys['user']:
570-
self._stop_account_socket('user')
709+
# OBSOLETE - removed when adding isolated margin. Loop over keys instead
710+
# # check if we have a user stream socket
711+
# if len(conn_key) >= 60 and conn_key[:60] == self._listen_keys['user']:
712+
# self._stop_account_socket('user')
713+
714+
# # or a margin stream socket
715+
# if len(conn_key) >= 60 and conn_key[:60] == self._listen_keys['margin']:
716+
# self._stop_account_socket('margin')
717+
718+
# NEW - Loop over keys in _listen_keys dictionary to find a match on
719+
# user, cross-margin and isolated margin:
720+
for key, value in self._listen_keys.items():
721+
if len(conn_key) >= 60 and conn_key[:60] == value:
722+
self._stop_account_socket(key)
571723

572-
# or a margin stream socket
573-
if len(conn_key) >= 60 and conn_key[:60] == self._listen_keys['margin']:
574-
self._stop_account_socket('margin')
575724

576725
def _stop_account_socket(self, socket_type):
577-
if not self._listen_keys[socket_type]:
726+
if not self._listen_keys.get(socket_type, None):
578727
return
579-
if self._timers[socket_type]:
728+
if self._timers.get(socket_type, None):
580729
self._timers[socket_type].cancel()
581730
self._timers[socket_type] = None
582731
self._listen_keys[socket_type] = None

docs/account.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Order Validation
99

1010
Binance has a number of rules around symbol pair orders with validation on minimum price, quantity and total order value.
1111

12-
Read more about their specifics in the `Filters <https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#filters>`_
12+
Read more about their specifics in the `Filters <https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#filters>`_
1313
section of the official API.
1414

1515
It can be helpful to format the output using the following snippet

docs/changelog.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
Changelog
22
=========
33

4+
v0.7.5.dev
5+
^^^^^^^^^^
6+
**Changed**
7+
- Stock json lib to ujson (https://github.com/sammchardy/python-binance/pull/383)
8+
49
v0.7.5 - 2020-02-06
510
^^^^^^^^^^^^^^^^^^^
611

0 commit comments

Comments
 (0)