From e2b391d26018bb8cf24f7e48aeaf9c5c037abc2e Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Wed, 7 Apr 2021 10:25:20 +0100 Subject: [PATCH 01/21] Updated .gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2676bd57d..2435fd76d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ build/ dist/ python_binance.egg-info/ *__pycache__ -*.egg-info/ \ No newline at end of file +*.egg-info/ +.idea/ +venv/ \ No newline at end of file From dc552a7fb2a6b1868af99226299dc90977638043 Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Wed, 7 Apr 2021 10:25:42 +0100 Subject: [PATCH 02/21] Added options URLs --- binance/client.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/binance/client.py b/binance/client.py index 37843a5cc..4e923aefe 100644 --- a/binance/client.py +++ b/binance/client.py @@ -19,12 +19,14 @@ class Client(object): FUTURES_DATA_URL = 'https://fapi.binance.{}/futures/data' FUTURES_COIN_URL = "https://dapi.binance.{}/dapi" FUTURES_COIN_DATA_URL = "https://dapi.binance.{}/futures/data" + OPTIONS_URL = 'https://vapi.binance.{}/vapi' PUBLIC_API_VERSION = 'v1' PRIVATE_API_VERSION = 'v3' WITHDRAW_API_VERSION = 'v3' MARGIN_API_VERSION = 'v1' FUTURES_API_VERSION = 'v1' FUTURES_API_VERSION2 = "v2" + OPTIONS_API_VERSION = 'v1' SYMBOL_TYPE_SPOT = 'SPOT' @@ -120,6 +122,7 @@ def __init__(self, api_key=None, api_secret=None, requests_params=None, tld='com self.FUTURES_DATA_URL = self.FUTURES_DATA_URL.format(tld) self.FUTURES_COIN_URL = self.FUTURES_COIN_URL.format(tld) self.FUTURES_COIN_DATA_URL = self.FUTURES_COIN_DATA_URL.format(tld) + self.OPTIONS_URL = self.OPTIONS_URL.format(tld) self.API_KEY = api_key self.API_SECRET = api_secret From 9511e0e2482f62cf56b388e0dedaacac4760d700 Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Wed, 7 Apr 2021 10:42:17 +0100 Subject: [PATCH 03/21] Added uri creation function --- binance/client.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/binance/client.py b/binance/client.py index 4e923aefe..76cd5b4d7 100644 --- a/binance/client.py +++ b/binance/client.py @@ -171,6 +171,9 @@ def _create_futures_coin_api_url(self, path, version=1): def _create_futures_coin_data_api_url(self, path, version=1): return self.FUTURES_COIN_DATA_URL + "/" + path + def _create_options_api_uri(self, path): + return self.OPTIONS_URL + '/' + self.OPTIONS_API_VERSION + '/' + path + def _generate_signature(self, data): ordered_data = self._order_params(data) From aa2306b1aab198d42e73b3156e0fca0c64074bc8 Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Wed, 7 Apr 2021 11:02:56 +0100 Subject: [PATCH 04/21] Added request options api function --- binance/client.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/binance/client.py b/binance/client.py index 76cd5b4d7..94b67a957 100644 --- a/binance/client.py +++ b/binance/client.py @@ -282,6 +282,11 @@ def _request_futures_coin_data_api(self, method, path, signed=False, version=1, return self._request(method, uri, signed, True, **kwargs) + def _request_options_api(self, method, path, signed=False, **kwargs): + uri = self._create_options_api_uri(path) + + return self._request(method, uri, signed, True, **kwargs) + def _handle_response(self): """Internal helper for handling API responses from the Binance server. Raises the appropriate exceptions when necessary; otherwise, returns the From a1f68007ff0cedb07d7ff5eef30169965cb96f02 Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Wed, 7 Apr 2021 11:03:52 +0100 Subject: [PATCH 05/21] Added options ping function --- binance/client.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/binance/client.py b/binance/client.py index 94b67a957..29c12f734 100644 --- a/binance/client.py +++ b/binance/client.py @@ -5855,3 +5855,13 @@ def enable_fast_withdraw_switch(self, **params): """ return self._request_margin_api('post', 'enableFastWithdrawSwitch', True, data=params) + + # Options API + + def options_ping(self): + """Test connectivity to the REST API + + https://binance-docs.github.io/apidocs/voptions/en/#test-connectivity + + """ + return self._request_options_api('get', 'ping') From 1f280086fabe648c288d224a567de58b049506d5 Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Wed, 7 Apr 2021 13:20:49 +0100 Subject: [PATCH 06/21] Added all endpoints under quoting interface --- binance/client.py | 124 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 123 insertions(+), 1 deletion(-) diff --git a/binance/client.py b/binance/client.py index 29c12f734..a61cac645 100644 --- a/binance/client.py +++ b/binance/client.py @@ -5856,7 +5856,12 @@ def enable_fast_withdraw_switch(self, **params): """ return self._request_margin_api('post', 'enableFastWithdrawSwitch', True, data=params) - # Options API + """ + ==================================================================================================================== + Options API + ==================================================================================================================== + """ + # Quoting interface endpoints def options_ping(self): """Test connectivity to the REST API @@ -5865,3 +5870,120 @@ def options_ping(self): """ return self._request_options_api('get', 'ping') + + def options_time(self): + """Get server time + + https://binance-docs.github.io/apidocs/voptions/en/#get-server-time + + """ + return self._request_options_api('get', 'time') + + def options_info(self): + """Get current trading pair info + + https://binance-docs.github.io/apidocs/voptions/en/#get-current-trading-pair-info + + """ + return self._request_options_api('get', 'optionInfo') + + def options_exchange_info(self): + """Get current limit info and trading pair info + + https://binance-docs.github.io/apidocs/voptions/en/#get-current-limit-info-and-trading-pair-info + + """ + return self._request_options_api('get', 'exchangeInfo') + + def options_index_price(self, **params): + """Get the spot index price + + https://binance-docs.github.io/apidocs/voptions/en/#get-the-spot-index-price + + :param underlying: mandatory - Spot pair(Option contract underlying asset)- BTCUSDT + :type underlying: str + + """ + return self._request_options_api('get', 'index', data=params) + + def options_price(self, **params): + """Get the latest price + + https://binance-docs.github.io/apidocs/voptions/en/#get-the-latest-price + + :param symbol: optional - Option trading pair - BTC-200730-9000-C + :type symbol: str + + """ + return self._request_options_api('get', 'ticker', data=params) + + def options_mark_price(self, **params): + """Get the latest mark price + + https://binance-docs.github.io/apidocs/voptions/en/#get-the-latest-mark-price + + :param symbol: optional - Option trading pair - BTC-200730-9000-C + :type symbol: str + + """ + return self._request_options_api('get', 'mark', data=params) + + def options_depth(self, **params): + """Depth information + + https://binance-docs.github.io/apidocs/voptions/en/#depth-information + + :param symbol: mandatory - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param limit: optional - Default:100 Max:1000.Optional value:[10, 20, 50, 100, 500, 1000] - 100 + :type limit: int + + """ + return self._request_options_api('get', 'depth', data=params) + + def options_klines(self, **params): + """Candle data + + https://binance-docs.github.io/apidocs/voptions/en/#candle-data + + :param symbol: mandatory - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param interval: mandatory - Time interval - 5m + :type interval: str + :param startTime: optional - Start Time - 1592317127349 + :type startTime: int + :param endTime: optional - End Time - 1592317127349 + :type endTime: int + :param limit: optional - Number of records Default:500 Max:1500 - 500 + :type limit: int + + """ + return self._request_options_api('get', 'klines', data=params) + + def options_recent_trades(self, **params): + """Recently completed Option trades + + https://binance-docs.github.io/apidocs/voptions/en/#recently-completed-option-trades + + :param symbol: mandatory - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param limit: optional - Number of records Default:100 Max:500 - 100 + :type limit: int + + """ + return self._request_options_api('get', 'trades', data=params) + + def options_historical_trades(self, **params): + """Query trade history + + https://binance-docs.github.io/apidocs/voptions/en/#query-trade-history + + :param symbol: mandatory - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param fromId: optional - The deal ID from which to return. The latest deal record is returned by default - 1592317127349 + :type fromId: int + :param limit: optional - Number of records Default:100 Max:500 - 100 + :type limit: int + + """ + return self._request_options_api('get', 'historicalTrades', data=params) From 4f8c5f02b8ae9d2c27b3726a2e4facff045e2561 Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Wed, 7 Apr 2021 18:44:35 +0100 Subject: [PATCH 07/21] Changed mandatory to required --- binance/client.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/binance/client.py b/binance/client.py index a61cac645..73924b810 100644 --- a/binance/client.py +++ b/binance/client.py @@ -5900,7 +5900,7 @@ def options_index_price(self, **params): https://binance-docs.github.io/apidocs/voptions/en/#get-the-spot-index-price - :param underlying: mandatory - Spot pair(Option contract underlying asset)- BTCUSDT + :param underlying: required - Spot pair(Option contract underlying asset)- BTCUSDT :type underlying: str """ @@ -5933,7 +5933,7 @@ def options_depth(self, **params): https://binance-docs.github.io/apidocs/voptions/en/#depth-information - :param symbol: mandatory - Option trading pair - BTC-200730-9000-C + :param symbol: required - Option trading pair - BTC-200730-9000-C :type symbol: str :param limit: optional - Default:100 Max:1000.Optional value:[10, 20, 50, 100, 500, 1000] - 100 :type limit: int @@ -5946,9 +5946,9 @@ def options_klines(self, **params): https://binance-docs.github.io/apidocs/voptions/en/#candle-data - :param symbol: mandatory - Option trading pair - BTC-200730-9000-C + :param symbol: required - Option trading pair - BTC-200730-9000-C :type symbol: str - :param interval: mandatory - Time interval - 5m + :param interval: required - Time interval - 5m :type interval: str :param startTime: optional - Start Time - 1592317127349 :type startTime: int @@ -5965,7 +5965,7 @@ def options_recent_trades(self, **params): https://binance-docs.github.io/apidocs/voptions/en/#recently-completed-option-trades - :param symbol: mandatory - Option trading pair - BTC-200730-9000-C + :param symbol: required - Option trading pair - BTC-200730-9000-C :type symbol: str :param limit: optional - Number of records Default:100 Max:500 - 100 :type limit: int @@ -5978,7 +5978,7 @@ def options_historical_trades(self, **params): https://binance-docs.github.io/apidocs/voptions/en/#query-trade-history - :param symbol: mandatory - Option trading pair - BTC-200730-9000-C + :param symbol: required - Option trading pair - BTC-200730-9000-C :type symbol: str :param fromId: optional - The deal ID from which to return. The latest deal record is returned by default - 1592317127349 :type fromId: int From 0c19ba8c7234fd35876be7d378b27c26399bf8ee Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Thu, 8 Apr 2021 08:11:32 +0100 Subject: [PATCH 08/21] Added options websockets --- binance/websockets.py | 85 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 6 deletions(-) diff --git a/binance/websockets.py b/binance/websockets.py index af479787c..0083194fd 100644 --- a/binance/websockets.py +++ b/binance/websockets.py @@ -1,4 +1,5 @@ # coding=utf-8 +import gzip import threading from autobahn.twisted.websocket import WebSocketClientFactory, \ @@ -22,13 +23,18 @@ def onConnect(self, response): self.factory.resetDelay() def onMessage(self, payload, isBinary): - if not isBinary: + if isBinary: try: - payload_obj = json.loads(payload.decode('utf8')) - except ValueError: - pass - else: - self.factory.callback(payload_obj) + payload = gzip.decompress(payload) + except: + print('Could not interpret binary response payload') + + try: + payload_obj = json.loads(payload.decode('utf8')) + except ValueError: + pass + else: + self.factory.callback(payload_obj) class BinanceReconnectingClientFactory(ReconnectingClientFactory): @@ -64,6 +70,7 @@ class BinanceSocketManager(threading.Thread): STREAM_URL = 'wss://stream.binance.com:9443/' FSTREAM_URL = 'wss://fstream.binance.com/' + VSTREAM_URL = 'wss://vstream.binance.com/' WEBSOCKET_DEPTH_5 = '5' WEBSOCKET_DEPTH_10 = '10' @@ -120,6 +127,20 @@ def _start_futures_socket(self, path, callback, prefix='stream?streams='): self._conns[path] = connectWS(factory, context_factory) return path + def _start_options_socket(self, path, callback, prefix='ws/'): + if path in self._conns: + return False + + factory_url = self.VSTREAM_URL + prefix + path + factory = BinanceClientFactory(factory_url) + factory.protocol = BinanceClientProtocol + factory.callback = callback + factory.reconnect = True + context_factory = ssl.ClientContextFactory() + + self._conns[path] = connectWS(factory, context_factory) + return path + def start_depth_socket(self, symbol, callback, depth=None, interval=None): """Start a websocket for symbol market depth returning either a diff or a partial book @@ -698,6 +719,58 @@ def start_isolated_margin_socket(self, symbol, callback): # and start the socket with this specific kek return self._start_account_socket(symbol, isolated_margin_listen_key, callback) + def start_options_ticker_socket(self, symbol, callback): + """Subscribe to a 24 hour ticker info stream + + https://binance-docs.github.io/apidocs/voptions/en/#market-streams-payload-24-hour-ticker + + :param symbol: required + :type symbol: str + :param callback: callback function to handle messages + :type callback: function + """ + return self._start_options_socket(symbol.lower() + '@ticker', callback) + + def start_options_recent_trades_socket(self, symbol, callback): + """Subscribe to a latest completed trades stream + + https://binance-docs.github.io/apidocs/voptions/en/#market-streams-payload-latest-completed-trades + + :param symbol: required + :type symbol: str + :param callback: callback function to handle messages + :type callback: function + """ + return self._start_options_socket(symbol.lower() + '@trade', callback) + + def start_options_kline_socket(self, symbol, callback, interval=Client.KLINE_INTERVAL_1MINUTE): + """Subscribe to a candlestick data stream + + https://binance-docs.github.io/apidocs/voptions/en/#market-streams-payload-candle + + :param symbol: required + :type symbol: str + :param callback: callback function to handle messages + :type callback: function + :param interval: Kline interval, default KLINE_INTERVAL_1MINUTE + :type interval: str + """ + return self._start_options_socket(symbol.lower() + '@kline_' + interval, callback) + + def start_options_depth_socket(self, symbol, callback, depth='10'): + """Subscribe to a depth data stream + + https://binance-docs.github.io/apidocs/voptions/en/#market-streams-payload-depth + + :param symbol: required + :type symbol: str + :param callback: callback function to handle messages + :type callback: function + :param depth: optional Number of depth entries to return, default 10. + :type depth: str + """ + return self._start_options_socket(symbol.lower() + '@depth' + str(depth), callback) + def _start_account_socket(self, socket_type, listen_key, callback): """Starts one of user or margin socket""" self._check_account_socket_open(listen_key) From f1116df160f978b8be36e42b732c02561968848a Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Thu, 8 Apr 2021 08:15:02 +0100 Subject: [PATCH 09/21] Added options multiplex socket --- binance/websockets.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/binance/websockets.py b/binance/websockets.py index 0083194fd..3de897e7f 100644 --- a/binance/websockets.py +++ b/binance/websockets.py @@ -665,6 +665,29 @@ def start_multiplex_socket(self, streams, callback): stream_path = 'streams={}'.format('/'.join(streams)) return self._start_socket(stream_path, callback, 'stream?') + def start_options_multiplex_socket(self, streams, callback): + """Start a multiplexed socket using a list of socket names. + User stream sockets can not be included. + + Symbols in socket name must be lowercase i.e bnbbtc@aggTrade, neobtc@ticker + + Combined stream events are wrapped as follows: {"stream":"","data":} + + https://binance-docs.github.io/apidocs/voptions/en/#account-and-trading-interface + + :param streams: list of stream names in lower case + :type streams: list + :param callback: callback function to handle messages + :type callback: function + + :returns: connection key string if successful, False otherwise + + Message Format - see Binance API docs for all types + + """ + stream_path = 'streams={}'.format('/'.join([s.lower() for s in streams])) + return self._start_options_socket(stream_path, callback, 'stream?') + def start_user_socket(self, callback): """Start a websocket for user data From a050ca12d80ef9b7fa2b7ef5c20a591e08ee2b73 Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Thu, 8 Apr 2021 10:44:16 +0100 Subject: [PATCH 10/21] Added return if binary response cannot be decompressed --- binance/websockets.py | 1 + 1 file changed, 1 insertion(+) diff --git a/binance/websockets.py b/binance/websockets.py index 3de897e7f..1f03e5f35 100644 --- a/binance/websockets.py +++ b/binance/websockets.py @@ -28,6 +28,7 @@ def onMessage(self, payload, isBinary): payload = gzip.decompress(payload) except: print('Could not interpret binary response payload') + return try: payload_obj = json.loads(payload.decode('utf8')) From d4cd3219bb2e70e3e4c22bd6308fa5f006b07256 Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Thu, 8 Apr 2021 11:21:08 +0100 Subject: [PATCH 11/21] Added account and trading interface endpoints --- binance/client.py | 214 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) diff --git a/binance/client.py b/binance/client.py index 73924b810..4bcbca322 100644 --- a/binance/client.py +++ b/binance/client.py @@ -5987,3 +5987,217 @@ def options_historical_trades(self, **params): """ return self._request_options_api('get', 'historicalTrades', data=params) + + # Account and trading interface endpoints + + def options_account_info(self, **params): + """Account asset info (USER_DATA) + + https://binance-docs.github.io/apidocs/voptions/en/#account-asset-info-user_data + + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('get', 'account', data=params) + + def options_funds_transfer(self, **params): + """Funds transfer (USER_DATA) + + https://binance-docs.github.io/apidocs/voptions/en/#funds-transfer-user_data + + :param currency: required - Asset type - USDT + :type currency: str + :param type: required - IN: Transfer from spot account to option account OUT: Transfer from option account to spot account - IN + :type type: str (ENUM) + :param amount: required - Amount - 10000 + :type amount: float + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('post', 'transfer', data=params) + + def options_positions(self, **params): + """Option holdings info (USER_DATA) + + https://binance-docs.github.io/apidocs/voptions/en/#option-holdings-info-user_data + + :param symbol: optional - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('get', 'position', data=params) + + def options_bill(self, **params): + """Account funding flow (USER_DATA) + + https://binance-docs.github.io/apidocs/voptions/en/#account-funding-flow-user_data + + :param currency: required - Asset type - USDT + :type currency: str + :param recordId: optional - Return the recordId and subsequent data, the latest data is returned by default - 100000 + :type recordId: int + :param startTime: optional - Start Time - 1593511200000 + :type startTime: int + :param endTime: optional - End Time - 1593511200000 + :type endTime: int + :param limit: optional - Number of result sets returned Default:100 Max:1000 - 100 + :type limit: int + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('post', 'bill', data=params) + + def options_place_order(self, **params): + """Option order (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#option-order-trade + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param side: required - Buy/sell direction: SELL, BUY - BUY + :type side: str (ENUM) + :param type: required - Order Type: LIMIT, MARKET - LIMIT + :type type: str (ENUM) + :param quantity: required - Order Quantity - 3 + :type quantity: float + :param price: optional - Order Price - 1000 + :type price: float + :param timeInForce: optional - Time in force method(Default GTC) - GTC + :type timeInForce: str (ENUM) + :param reduceOnly: optional - Reduce Only (Default false) - false + :type reduceOnly: bool + :param postOnly: optional - Post Only (Default false) - false + :type postOnly: bool + :param newOrderRespType: optional - "ACK", "RESULT", Default "ACK" - ACK + :type newOrderRespType: str (ENUM) + :param clientOrderId: optional - User-defined order ID cannot be repeated in pending orders - 10000 + :type clientOrderId: str + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('post', 'order', data=params) + + def options_place_batch_order(self, **params): + """Place Multiple Option orders (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#place-multiple-option-orders-trade + + :param orders: required - order list. Max 5 orders - [{"symbol":"BTC-210115-35000-C","price":"100","quantity":"0.0001","side":"BUY","type":"LIMIT"}] + :type orders: list + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('post', 'batchOrders', data=params) + + def options_cancel_order(self, **params): + """Cancel Option order (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#cancel-option-order-trade + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param orderId: optional - Order ID - 4611875134427365377 + :type orderId: str + :param clientOrderId: optional - User-defined order ID - 10000 + :type clientOrderId: str + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('delete', 'order', data=params) + + def options_cancel_batch_order(self, **params): + """Cancel Multiple Option orders (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#cancel-multiple-option-orders-trade + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param orderIds: optional - Order ID - [4611875134427365377,4611875134427365378] + :type orderId: list + :param clientOrderIds: optional - User-defined order ID - ["my_id_1","my_id_2"] + :type clientOrderIds: list + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('delete', 'batchOrders', data=params) + + def options_cancel_all_orders(self, **params): + """Cancel all Option orders (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#cancel-all-option-orders-trade + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('delete', 'allOpenOrders', data=params) + + def options_query_order(self, **params): + """Query Option order (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#query-option-order-trade + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param orderId: optional - Order ID - 4611875134427365377 + :type orderId: str + :param clientOrderId: optional - User-defined order ID - 10000 + :type clientOrderId: str + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('get', 'order', data=params) + + def options_query_pending_orders(self, **params): + """Query current pending Option orders (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#query-current-pending-option-orders-trade + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param orderId: optional - Returns the orderId and subsequent orders, the most recent order is returned by default - 100000 + :type orderId: str + :param startTime: optional - Start Time - 1593511200000 + :type startTime: int + :param endTime: optional - End Time - 1593511200000 + :type endTime: int + :param limit: optional - Number of result sets returned Default:100 Max:1000 - 100 + :type limit: int + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('get', 'openOrders', data=params) + + def options_query_order_history(self, **params): + """Query Option order history (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#query-option-order-history-trade + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param orderId: optional - Returns the orderId and subsequent orders, the most recent order is returned by default - 100000 + :type orderId: str + :param startTime: optional - Start Time - 1593511200000 + :type startTime: int + :param endTime: optional - End Time - 1593511200000 + :type endTime: int + :param limit: optional - Number of result sets returned Default:100 Max:1000 - 100 + :type limit: int + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('get', 'historyOrders', data=params) From c01820bc50ae5717ca1048030739defe63e4d38e Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Thu, 8 Apr 2021 11:38:28 +0100 Subject: [PATCH 12/21] Renamed options_depth to options_order_book --- binance/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binance/client.py b/binance/client.py index 4bcbca322..d41e0c8d5 100644 --- a/binance/client.py +++ b/binance/client.py @@ -5928,7 +5928,7 @@ def options_mark_price(self, **params): """ return self._request_options_api('get', 'mark', data=params) - def options_depth(self, **params): + def options_order_book(self, **params): """Depth information https://binance-docs.github.io/apidocs/voptions/en/#depth-information From 83d33beaabd01a43598158ed1bc6130dba9473d6 Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Thu, 8 Apr 2021 12:46:52 +0100 Subject: [PATCH 13/21] Added OptionsDepthCacheManager --- binance/depthcache.py | 100 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/binance/depthcache.py b/binance/depthcache.py index a2e92ff71..f89c2eb35 100644 --- a/binance/depthcache.py +++ b/binance/depthcache.py @@ -283,3 +283,103 @@ def get_symbol(self): :return: symbol """ return self._symbol + + +class OptionsDepthCacheManager(DepthCacheManager): + _default_refresh = 60*30 # 30 minutes + + def __init__(self, client, symbol, callback=None, refresh_interval=_default_refresh, bm=None, limit=10): + """Initialise the OptionsDepthCacheManager + + :param client: Binance API client + :type client: binance.Client + :param symbol: Symbol to create depth cache for + :type symbol: string + :param callback: Optional function to receive depth cache updates + :type callback: function + :param refresh_interval: Optional number of seconds between cache refresh, use 0 or None to disable + :type refresh_interval: int + :param limit: Optional number of orders to get from orderbook + :type limit: int + + """ + self._client = client + self._symbol = symbol + self._limit = limit + self._callback = callback + self._bm = bm + self._refresh_interval = refresh_interval + self._conn_key = None + + self._init_cache() + self._start_socket() + + def _init_cache(self): + """Initialise the depth cache and set a refresh time + + :return: + """ + + # initialise or clear depth cache + self._depth_cache = DepthCache(self._symbol) + + # set a time to refresh the depth cache + if self._refresh_interval: + self._refresh_time = int(time.time()) + self._refresh_interval + + def _start_socket(self): + """Start the depth cache socket + + :return: + """ + if self._bm is None: + self._bm = BinanceSocketManager(self._client) + + self._conn_key = self._bm.start_options_depth_socket(self._symbol, self._depth_event) + if not self._bm.is_alive(): + self._bm.start() + + def _depth_event(self, msg): + """Handle a depth event + + :param msg: + :return: + + """ + + if 'e' in msg and msg['e'] == 'error': + # close the socket + self.close() + + # notify the user by returning a None value + if self._callback: + self._callback(None) + + self._process_depth_message(msg) + + def _process_depth_message(self, msg, buffer=False): + """Process a depth event message. + + :param msg: Depth event message. + :return: + + """ + + # add any bid or ask values + for bid in msg['b']: + self._depth_cache.add_bid(bid) + for ask in msg['a']: + self._depth_cache.add_ask(ask) + + # keeping update time + self._depth_cache.update_time = msg['E'] + + # call the callback with the updated depth cache + if self._callback: + self._callback(self._depth_cache) + + # after processing event see if we need to refresh the depth cache + if self._refresh_interval and int(time.time()) > self._refresh_time: + self.close() + self._init_cache() + self._start_socket() From 66aaf1421a23065f2c7f47144e04736391664b3c Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Thu, 8 Apr 2021 13:03:50 +0100 Subject: [PATCH 14/21] Pointless change so that all docstrings are currently derived exactly from Binance documentation --- binance/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binance/client.py b/binance/client.py index d41e0c8d5..15755c1fb 100644 --- a/binance/client.py +++ b/binance/client.py @@ -5864,7 +5864,7 @@ def enable_fast_withdraw_switch(self, **params): # Quoting interface endpoints def options_ping(self): - """Test connectivity to the REST API + """Test connectivity https://binance-docs.github.io/apidocs/voptions/en/#test-connectivity From 005507d189a44900f8b77ce09a6b33990ef81964 Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Thu, 8 Apr 2021 13:14:36 +0100 Subject: [PATCH 15/21] Added options quoting interface endpoints docs to Endpoints.md --- Endpoints.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/Endpoints.md b/Endpoints.md index 5e1ca94cc..ba351cdb6 100644 --- a/Endpoints.md +++ b/Endpoints.md @@ -783,6 +783,52 @@ > :warning: Not yet implemented - *User Data Streams* > :warning: Not yet implemented +### [Vanilla Options](https://binance-docs.github.io/apidocs/voptions/en/) +- *Quoting interface* + - **GET /vapi/v1/ping** (Test connectivity) + ```python + client.options_ping() + ``` + - **GET /vapi/v1/time** (Get server time) + ```python + client.options_time() + ``` + - **GET /vapi/v1/optionInfo** (Get current trading pair info) + ```python + client.options_info() + ``` + - **GET /vapi/v1/exchangeInfo** (Get current limit info and trading pair info) + ```python + client.options_exchange_info() + ``` + - **GET /vapi/v1/index** (Get the spot index price) + ```python + client.options_index_price(underlying) + ``` + - **GET /vapi/v1/ticker** (Get the latest price) + ```python + client.options_price(symbol) + ``` + - **GET /vapi/v1/mark** (Get the latest mark price) + ```python + client.options_mark_price(symbol) + ``` + - **GET /vapi/v1/depth** (Depth information) + ```python + client.options_order_book(symbol, limit) + ``` + - **GET /vapi/v1/klines** (Candle data) + ```python + client.options_klines(symbol, interval, startTime, endTime, limit) + ``` + - **GET /vapi/v1/trades** (Recently completed Option trades) + ```python + client.options_recent_trades(symbol, limit) + ``` + - **GET /vapi/v1/historicalTrades** (Query trade history) + ```python + client.options_historical_trades(symbol, fromId, limit) + ``` ### [COIN-M Futures](https://binance-docs.github.io/apidocs/delivery/en/) > :warning: Not yet implemented ### [USDT-M Futures testnet](https://binance-docs.github.io/apidocs/testnet/en/) From be53ec506823c8d2fb3343daddecbaa670d53aef Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Thu, 8 Apr 2021 13:34:52 +0100 Subject: [PATCH 16/21] Added options account and trading interface endpoints docs to Endpoints.md --- Endpoints.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/Endpoints.md b/Endpoints.md index ba351cdb6..5e855cf58 100644 --- a/Endpoints.md +++ b/Endpoints.md @@ -829,6 +829,56 @@ ```python client.options_historical_trades(symbol, fromId, limit) ``` +- *Account and trading interface* + - **GET /vapi/v1/account (HMAC SHA256)** (Account asset info (USER_DATA)) + ```python + client.options_account_info(recvWindow) + ``` + - **POST /vapi/v1/transfer (HMAC SHA256)** (Funds transfer (USER_DATA)) + ```python + client.options_funds_transfer(currency, type, amount, recvWindow) + ``` + - **GET /vapi/v1/position (HMAC SHA256)** (Option holdings info (USER_DATA)) + ```python + client.options_positions(symbol, recvWindow) + ``` + - **POST /vapi/v1/bill (HMAC SHA256)** (Account funding flow (USER_DATA)) + ```python + client.options_bill(currency, recordId, startTime, endTime, limit, recvWindow) + ``` + - **POST /vapi/v1/order (HMAC SHA256)** (Option order (TRADE)) + ```python + client.options_place_order(symbol, side, type, quantity, price, timeInForce, reduceOnly, postOnly, \ + newOrderRespType, clientOrderId, recvWindow, recvWindow) + ``` + - **POST /vapi/v1/batchOrders (HMAC SHA256)** (Place Multiple Option orders (TRADE)) + ```python + client.options_place_batch_order(orders, recvWindow) + ``` + - **DELETE /vapi/v1/order (HMAC SHA256)** (Cancel Option order (TRADE)) + ```python + client.options_cancel_order(symbol, orderId, clientOrderId, recvWindow) + ``` + - **DELETE /vapi/v1/batchOrders (HMAC SHA256)** (Cancel Multiple Option orders (TRADE)) + ```python + client.options_cancel_batch_order(symbol, orderIds, clientOrderIds, recvWindow) + ``` + - **DELETE /vapi/v1/allOpenOrders (HMAC SHA256)** (Cancel all Option orders (TRADE)) + ```python + client.options_cancel_all_orders(symbol, recvWindow) + ``` + - **GET /vapi/v1/order (HMAC SHA256)** (Query Option order (TRADE)) + ```python + client.options_query_order(symbol, orderId, clientOrderId, recvWindow) + ``` + - **GET /vapi/v1/openOrders (HMAC SHA256)** (Query current pending Option orders (TRADE)) + ```python + client.options_query_pending_orders(symbol, orderId, startTime, endTime, limit, recvWindow) + ``` + - **GET /vapi/v1/historyOrders (HMAC SHA256)** (Query Option order history (TRADE)) + ```python + client.options_query_order_history(symbol, orderId, startTime, endTime, limit, recvWindow) + ``` ### [COIN-M Futures](https://binance-docs.github.io/apidocs/delivery/en/) > :warning: Not yet implemented ### [USDT-M Futures testnet](https://binance-docs.github.io/apidocs/testnet/en/) From cea537f038cd07f146561baf26c78d71bde0a7e6 Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Thu, 8 Apr 2021 14:03:13 +0100 Subject: [PATCH 17/21] Added options depth cache note in documentation --- docs/depth_cache.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/depth_cache.rst b/docs/depth_cache.rst index b6e791c28..45b21ecae 100644 --- a/docs/depth_cache.rst +++ b/docs/depth_cache.rst @@ -1,7 +1,8 @@ Depth Cache =========== -To follow the depth cache updates for a symbol use the `DepthCacheManager` +To follow the depth cache updates for a symbol use the `DepthCacheManager`. For vanilla options use the +`OptionsDepthCacheManager`. Create the manager like so, passing the api client, symbol and an optional callback function. From 73c59e4e6539e535acbf9d3fefd71d9f3f0433bd Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Thu, 8 Apr 2021 14:19:45 +0100 Subject: [PATCH 18/21] Added testnet flag in client and options testnet support --- binance/client.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/binance/client.py b/binance/client.py index 15755c1fb..098da9fe0 100644 --- a/binance/client.py +++ b/binance/client.py @@ -20,6 +20,7 @@ class Client(object): FUTURES_COIN_URL = "https://dapi.binance.{}/dapi" FUTURES_COIN_DATA_URL = "https://dapi.binance.{}/futures/data" OPTIONS_URL = 'https://vapi.binance.{}/vapi' + OPTIONS_TESTNET_URL = 'https://testnet.binanceops.{}/vapi' PUBLIC_API_VERSION = 'v1' PRIVATE_API_VERSION = 'v3' WITHDRAW_API_VERSION = 'v3' @@ -102,7 +103,7 @@ class Client(object): MINING_TO_USDT_FUTURE = "MINING_UMFUTURE" MINING_TO_FIAT = "MINING_C2C" - def __init__(self, api_key=None, api_secret=None, requests_params=None, tld='com'): + def __init__(self, api_key=None, api_secret=None, requests_params=None, tld='com', testnet=False): """Binance API Client constructor :param api_key: Api Key @@ -111,6 +112,8 @@ def __init__(self, api_key=None, api_secret=None, requests_params=None, tld='com :type api_secret: str. :param requests_params: optional - Dictionary of requests params to use for all calls :type requests_params: dict. + :param testnet: Use testnet environment - only available for vanilla options at the moment + :type testnet: bool """ @@ -123,12 +126,14 @@ def __init__(self, api_key=None, api_secret=None, requests_params=None, tld='com self.FUTURES_COIN_URL = self.FUTURES_COIN_URL.format(tld) self.FUTURES_COIN_DATA_URL = self.FUTURES_COIN_DATA_URL.format(tld) self.OPTIONS_URL = self.OPTIONS_URL.format(tld) + self.OPTIONS_TESTNET_URL = self.OPTIONS_TESTNET_URL.format(tld) self.API_KEY = api_key self.API_SECRET = api_secret self.session = self._init_session() self._requests_params = requests_params self.response = None + self.testnet = testnet self.timestamp_offset = 0 # init DNS and SSL cert @@ -172,7 +177,11 @@ def _create_futures_coin_data_api_url(self, path, version=1): return self.FUTURES_COIN_DATA_URL + "/" + path def _create_options_api_uri(self, path): - return self.OPTIONS_URL + '/' + self.OPTIONS_API_VERSION + '/' + path + if self.testnet: + url = self.OPTIONS_TESTNET_URL + else: + url = self.OPTIONS_URL + return url + '/' + self.OPTIONS_API_VERSION + '/' + path def _generate_signature(self, data): From 936a0f6dc824555a408276c532f56df62fa332f6 Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Fri, 9 Apr 2021 20:54:53 +0100 Subject: [PATCH 19/21] Corrected signed flag to True in signed options requests --- binance/client.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/binance/client.py b/binance/client.py index 098da9fe0..d06beb7a0 100644 --- a/binance/client.py +++ b/binance/client.py @@ -6008,7 +6008,7 @@ def options_account_info(self, **params): :type recvWindow: int """ - return self._request_options_api('get', 'account', data=params) + return self._request_options_api('get', 'account', signed=True, data=params) def options_funds_transfer(self, **params): """Funds transfer (USER_DATA) @@ -6025,7 +6025,7 @@ def options_funds_transfer(self, **params): :type recvWindow: int """ - return self._request_options_api('post', 'transfer', data=params) + return self._request_options_api('post', 'transfer', signed=True, data=params) def options_positions(self, **params): """Option holdings info (USER_DATA) @@ -6038,7 +6038,7 @@ def options_positions(self, **params): :type recvWindow: int """ - return self._request_options_api('get', 'position', data=params) + return self._request_options_api('get', 'position', signed=True, data=params) def options_bill(self, **params): """Account funding flow (USER_DATA) @@ -6059,7 +6059,7 @@ def options_bill(self, **params): :type recvWindow: int """ - return self._request_options_api('post', 'bill', data=params) + return self._request_options_api('post', 'bill', signed=True, data=params) def options_place_order(self, **params): """Option order (TRADE) @@ -6090,7 +6090,7 @@ def options_place_order(self, **params): :type recvWindow: int """ - return self._request_options_api('post', 'order', data=params) + return self._request_options_api('post', 'order', signed=True, data=params) def options_place_batch_order(self, **params): """Place Multiple Option orders (TRADE) @@ -6103,7 +6103,7 @@ def options_place_batch_order(self, **params): :type recvWindow: int """ - return self._request_options_api('post', 'batchOrders', data=params) + return self._request_options_api('post', 'batchOrders', signed=True, data=params) def options_cancel_order(self, **params): """Cancel Option order (TRADE) @@ -6120,7 +6120,7 @@ def options_cancel_order(self, **params): :type recvWindow: int """ - return self._request_options_api('delete', 'order', data=params) + return self._request_options_api('delete', 'order', signed=True, data=params) def options_cancel_batch_order(self, **params): """Cancel Multiple Option orders (TRADE) @@ -6137,7 +6137,7 @@ def options_cancel_batch_order(self, **params): :type recvWindow: int """ - return self._request_options_api('delete', 'batchOrders', data=params) + return self._request_options_api('delete', 'batchOrders', signed=True, data=params) def options_cancel_all_orders(self, **params): """Cancel all Option orders (TRADE) @@ -6150,7 +6150,7 @@ def options_cancel_all_orders(self, **params): :type recvWindow: int """ - return self._request_options_api('delete', 'allOpenOrders', data=params) + return self._request_options_api('delete', 'allOpenOrders', signed=True, data=params) def options_query_order(self, **params): """Query Option order (TRADE) @@ -6167,7 +6167,7 @@ def options_query_order(self, **params): :type recvWindow: int """ - return self._request_options_api('get', 'order', data=params) + return self._request_options_api('get', 'order', signed=True, data=params) def options_query_pending_orders(self, **params): """Query current pending Option orders (TRADE) @@ -6188,7 +6188,7 @@ def options_query_pending_orders(self, **params): :type recvWindow: int """ - return self._request_options_api('get', 'openOrders', data=params) + return self._request_options_api('get', 'openOrders', signed=True, data=params) def options_query_order_history(self, **params): """Query Option order history (TRADE) @@ -6209,4 +6209,4 @@ def options_query_order_history(self, **params): :type recvWindow: int """ - return self._request_options_api('get', 'historyOrders', data=params) + return self._request_options_api('get', 'historyOrders', signed=True, data=params) From 57d341622d96d5f8ed5dc03b1d53d561292a4fb8 Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Fri, 9 Apr 2021 21:01:34 +0100 Subject: [PATCH 20/21] Added option trade list endpoint --- Endpoints.md | 4 ++++ binance/client.py | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/Endpoints.md b/Endpoints.md index 5e855cf58..641b310ff 100644 --- a/Endpoints.md +++ b/Endpoints.md @@ -879,6 +879,10 @@ ```python client.options_query_order_history(symbol, orderId, startTime, endTime, limit, recvWindow) ``` + - **GET /vapi/v1/userTrades (HMAC SHA256)** (Option Trade List (USER_DATA)) + ```python + client.options_user_trades(symbol, fromId, startTime, endTime, limit, recvWindow) + ``` ### [COIN-M Futures](https://binance-docs.github.io/apidocs/delivery/en/) > :warning: Not yet implemented ### [USDT-M Futures testnet](https://binance-docs.github.io/apidocs/testnet/en/) diff --git a/binance/client.py b/binance/client.py index d06beb7a0..edc4e84e6 100644 --- a/binance/client.py +++ b/binance/client.py @@ -6210,3 +6210,24 @@ def options_query_order_history(self, **params): """ return self._request_options_api('get', 'historyOrders', signed=True, data=params) + + def options_user_trades(self, **params): + """Option Trade List (USER_DATA) + + https://binance-docs.github.io/apidocs/voptions/en/#option-trade-list-user_data + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param fromId: optional - Trade id to fetch from. Default gets most recent trades. - 4611875134427365376 + :type orderId: int + :param startTime: optional - Start Time - 1593511200000 + :type startTime: int + :param endTime: optional - End Time - 1593511200000 + :type endTime: int + :param limit: optional - Number of result sets returned Default:100 Max:1000 - 100 + :type limit: int + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('get', 'userTrades', signed=True, data=params) From 7e769f2da8178d56a3e95062e51f9872f7b5932d Mon Sep 17 00:00:00 2001 From: Ollie Hooper <35010178+Ollie-Hooper@users.noreply.github.com> Date: Fri, 9 Apr 2021 21:34:42 +0100 Subject: [PATCH 21/21] Added options testnet websocket support - have not been able to test as no activity on the testnet... --- binance/websockets.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/binance/websockets.py b/binance/websockets.py index 1f03e5f35..6323722de 100644 --- a/binance/websockets.py +++ b/binance/websockets.py @@ -72,6 +72,7 @@ class BinanceSocketManager(threading.Thread): STREAM_URL = 'wss://stream.binance.com:9443/' FSTREAM_URL = 'wss://fstream.binance.com/' VSTREAM_URL = 'wss://vstream.binance.com/' + VSTREAM_TESTNET_URL = 'wss://testnetws.binanceops.com/' WEBSOCKET_DEPTH_5 = '5' WEBSOCKET_DEPTH_10 = '10' @@ -97,6 +98,8 @@ def __init__(self, client, user_timeout=DEFAULT_USER_TIMEOUT): self._account_callbacks = {'user': None, 'margin': None} # Isolated margin sockets will be opened under the 'symbol' name + self.testnet = self._client.testnet + def _start_socket(self, path, callback, prefix='ws/'): if path in self._conns: return False @@ -132,7 +135,12 @@ def _start_options_socket(self, path, callback, prefix='ws/'): if path in self._conns: return False - factory_url = self.VSTREAM_URL + prefix + path + if self.testnet: + url = self.VSTREAM_TESTNET_URL + else: + url = self.VSTREAM_URL + + factory_url = url + prefix + path factory = BinanceClientFactory(factory_url) factory.protocol = BinanceClientProtocol factory.callback = callback