| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 81c43cf commit 6b3dbd0
7 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -29,7 +29,7 @@ jobs: | |||
| 29 | 29 | - name: Install dependencies | |
| 30 | 30 | run: | | |
| 31 | 31 | python -m pip install --upgrade pip | |
| 32 | - pip install flake8 pytest | ||
| 32 | + pip install flake8 pytest pyright | ||
| 33 | 33 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi | |
| 34 | 34 | if [ -f test-requirements.txt ]; then pip install -r test-requirements.txt; fi | |
| 35 | 35 | - name: Lint with flake8 | |
@@ -38,6 +38,8 @@ jobs: | |||
| 38 | 38 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics | |
| 39 | 39 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide | |
| 40 | 40 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics | |
| 41 | + - name: Type check with pyright | ||
| 42 | + run: pyright | ||
| 41 | 43 | - name: Test with pytest | |
| 42 | 44 | run: | | |
| 43 | 45 | pytest | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -274,12 +274,12 @@ def _create_options_api_uri(self, path: str) -> str: | |||
| 274 | 274 | def _rsa_signature(self, query_string: str): | |
| 275 | 275 | assert self.PRIVATE_KEY | |
| 276 | 276 | h = SHA256.new(query_string.encode("utf-8")) | |
| 277 | - signature = pkcs1_15.new(self.PRIVATE_KEY).sign(h) | ||
| 277 | + signature = pkcs1_15.new(self.PRIVATE_KEY).sign(h) # type: ignore | ||
| 278 | 278 | return b64encode(signature).decode() | |
| 279 | 279 | ||
| 280 | 280 | def _ed25519_signature(self, query_string: str): | |
| 281 | 281 | assert self.PRIVATE_KEY | |
| 282 | - return b64encode(eddsa.new(self.PRIVATE_KEY, "rfc8032").sign(query_string.encode())).decode() | ||
| 282 | + return b64encode(eddsa.new(self.PRIVATE_KEY, "rfc8032").sign(query_string.encode())).decode() # type: ignore | ||
| 283 | 283 | ||
| 284 | 284 | def _hmac_signature(self, query_string: str) -> str: | |
| 285 | 285 | assert self.API_SECRET, "API Secret required for private endpoints" | |
@@ -440,7 +440,7 @@ def _request_futures_coin_api(self, method, path, signed=False, version=1, **kwa | |||
| 440 | 440 | version = self._get_version(version, **kwargs) | |
| 441 | 441 | uri = self._create_futures_coin_api_url(path, version=version) | |
| 442 | 442 | ||
| 443 | - return self._request(method, uri, signed, True, **kwargs) | ||
| 443 | + return self._request(method, uri, signed, False, **kwargs) | ||
| 444 | 444 | ||
| 445 | 445 | def _request_futures_coin_data_api(self, method, path, signed=False, version=1, **kwargs) -> Dict: | |
| 446 | 446 | version = self._get_version(version, **kwargs) | |
@@ -1561,6 +1561,7 @@ def create_order(self, **params): | |||
| 1561 | 1561 | params['newClientOrderId'] = self.SPOT_ORDER_PREFIX + self.uuid22() | |
| 1562 | 1562 | return self._post('order', True, data=params) | |
| 1563 | 1563 | ||
| 1564 | + | ||
| 1564 | 1565 | def order_limit(self, timeInForce=BaseClient.TIME_IN_FORCE_GTC, **params): | |
| 1565 | 1566 | """Send in a new limit order | |
| 1566 | 1567 | ||
@@ -3711,38 +3712,6 @@ def get_margin_capital_flow(self, **params): | |||
| 3711 | 3712 | """ | |
| 3712 | 3713 | return self._request_margin_api('get', 'margin/capital-flow', True, data=params) | |
| 3713 | 3714 | ||
| 3714 | - def get_margin_delist_schedule(self, **params): | ||
| 3715 | - """Get tokens or symbols delist schedule for cross margin and isolated margin | ||
| 3716 | - | ||
| 3717 | - https://binance-docs.github.io/apidocs/spot/en/#get-tokens-or-symbols-delist-schedule-for-cross-margin-and-isolated-margin-market_data | ||
| 3718 | - | ||
| 3719 | - :returns: API response | ||
| 3720 | - | ||
| 3721 | - .. code-block:: python | ||
| 3722 | - [ | ||
| 3723 | - { | ||
| 3724 | - "delistTime": 1686161202000, | ||
| 3725 | - "crossMarginAssets": [ | ||
| 3726 | - "BTC", | ||
| 3727 | - "USDT" | ||
| 3728 | - ], | ||
| 3729 | - "isolatedMarginSymbols": [ | ||
| 3730 | - "ADAUSDT", | ||
| 3731 | - "BNBUSDT" | ||
| 3732 | - ] | ||
| 3733 | - }, | ||
| 3734 | - { | ||
| 3735 | - "delistTime": 1686222232000, | ||
| 3736 | - "crossMarginAssets": [ | ||
| 3737 | - "ADA" | ||
| 3738 | - ], | ||
| 3739 | - "isolatedMarginSymbols": [] | ||
| 3740 | - } | ||
| 3741 | - ] | ||
| 3742 | - | ||
| 3743 | - """ | ||
| 3744 | - return self._request_margin_api('get', 'margin/delist-schedule', True, data=params) | ||
| 3745 | - | ||
| 3746 | 3715 | def get_margin_asset(self, **params): | |
| 3747 | 3716 | """Query cross-margin asset | |
| 3748 | 3717 | ||
@@ -7424,6 +7393,9 @@ def futures_place_batch_order(self, **params): | |||
| 7424 | 7393 | the url encoding is done on the special query param, batchOrders, in the early stage. | |
| 7425 | 7394 | ||
| 7426 | 7395 | """ | |
| 7396 | + for order in params['batchOrders']: | ||
| 7397 | + if 'newClientOrderId' not in order: | ||
| 7398 | + order['newClientOrderId'] = self.CONTRACT_ORDER_PREFIX + self.uuid22() | ||
| 7427 | 7399 | query_string = urlencode(params) | |
| 7428 | 7400 | query_string = query_string.replace('%27', '%22') | |
| 7429 | 7401 | params['batchOrders'] = query_string[12:] | |
@@ -7823,6 +7795,8 @@ def futures_coin_create_order(self, **params): | |||
| 7823 | 7795 | https://binance-docs.github.io/apidocs/delivery/en/#new-order-trade | |
| 7824 | 7796 | ||
| 7825 | 7797 | """ | |
| 7798 | + if 'newClientOrderId' not in params: | ||
| 7799 | + params['newClientOrderId'] = self.CONTRACT_ORDER_PREFIX + self.uuid22() | ||
| 7826 | 7800 | return self._request_futures_coin_api("post", "order", True, data=params) | |
| 7827 | 7801 | ||
| 7828 | 7802 | def futures_coin_place_batch_order(self, **params): | |
@@ -7834,6 +7808,9 @@ def futures_coin_place_batch_order(self, **params): | |||
| 7834 | 7808 | the url encoding is done on the special query param, batchOrders, in the early stage. | |
| 7835 | 7809 | ||
| 7836 | 7810 | """ | |
| 7811 | + for order in params['batchOrders']: | ||
| 7812 | + if 'newClientOrderId' not in order: | ||
| 7813 | + order['newClientOrderId'] = self.CONTRACT_ORDER_PREFIX + self.uuid22() | ||
| 7837 | 7814 | query_string = urlencode(params) | |
| 7838 | 7815 | query_string = query_string.replace('%27', '%22') | |
| 7839 | 7816 | params['batchOrders'] = query_string[12:] | |
@@ -8471,6 +8448,9 @@ def options_place_batch_order(self, **params): | |||
| 8471 | 8448 | :type recvWindow: int | |
| 8472 | 8449 | ||
| 8473 | 8450 | """ | |
| 8451 | + for order in params['batchOrders']: | ||
| 8452 | + if 'newClientOrderId' not in order: | ||
| 8453 | + order['newClientOrderId'] = self.CONTRACT_ORDER_PREFIX + self.uuid22() | ||
| 8474 | 8454 | return self._request_options_api('post', 'batchOrders', signed=True, data=params) | |
| 8475 | 8455 | ||
| 8476 | 8456 | def options_cancel_order(self, **params): | |
@@ -10115,7 +10095,7 @@ async def _request_futures_coin_api(self, method, path, signed=False, version=1, | |||
| 10115 | 10095 | version = self._get_version(version, **kwargs) | |
| 10116 | 10096 | uri = self._create_futures_coin_api_url(path, version=version) | |
| 10117 | 10097 | ||
| 10118 | - return await self._request(method, uri, signed, True, **kwargs) | ||
| 10098 | + return await self._request(method, uri, signed, False, **kwargs) | ||
| 10119 | 10099 | ||
| 10120 | 10100 | async def _request_futures_coin_data_api(self, method, path, signed=False, version=1, **kwargs) -> Dict: | |
| 10121 | 10101 | version = self._get_version(version, **kwargs) | |
@@ -10889,9 +10869,6 @@ async def get_max_margin_loan(self, **params): | |||
| 10889 | 10869 | async def get_max_margin_transfer(self, **params): | |
| 10890 | 10870 | return await self._request_margin_api('get', 'margin/maxTransferable', signed=True, data=params) | |
| 10891 | 10871 | ||
| 10892 | - async def get_margin_delist_schedule(self, **params): | ||
| 10893 | - return await self._request_margin_api('get', '/margin/delist-schedule', signed=True, data=params) | ||
| 10894 | - | ||
| 10895 | 10872 | # Margin OCO | |
| 10896 | 10873 | ||
| 10897 | 10874 | async def create_margin_oco_order(self, **params): | |
@@ -11235,6 +11212,9 @@ async def futures_create_test_order(self, **params): | |||
| 11235 | 11212 | return await self._request_futures_api('post', 'order/test', True, data=params) | |
| 11236 | 11213 | ||
| 11237 | 11214 | async def futures_place_batch_order(self, **params): | |
| 11215 | + for order in params['batchOrders']: | ||
| 11216 | + if 'newClientOrderId' not in order: | ||
| 11217 | + order['newClientOrderId'] = self.CONTRACT_ORDER_PREFIX + self.uuid22() | ||
| 11238 | 11218 | query_string = urlencode(params) | |
| 11239 | 11219 | query_string = query_string.replace('%27', '%22') | |
| 11240 | 11220 | params['batchOrders'] = query_string[12:] | |
@@ -11405,9 +11385,14 @@ async def universal_transfer(self, **params): | |||
| 11405 | 11385 | ) | |
| 11406 | 11386 | ||
| 11407 | 11387 | async def futures_coin_create_order(self, **params): | |
| 11388 | + if 'newClientOrderId' not in params: | ||
| 11389 | + params['newClientOrderId'] = self.CONTRACT_ORDER_PREFIX + self.uuid22() | ||
| 11408 | 11390 | return await self._request_futures_coin_api("post", "order", True, data=params) | |
| 11409 | 11391 | ||
| 11410 | 11392 | async def futures_coin_place_batch_order(self, **params): | |
| 11393 | + for order in params['batchOrders']: | ||
| 11394 | + if 'newClientOrderId' not in order: | ||
| 11395 | + order['newClientOrderId'] = self.CONTRACT_ORDER_PREFIX + self.uuid22() | ||
| 11411 | 11396 | query_string = urlencode(params) | |
| 11412 | 11397 | query_string = query_string.replace('%27', '%22') | |
| 11413 | 11398 | params['batchOrders'] = query_string[12:] | |
@@ -11574,6 +11559,9 @@ async def options_place_order(self, **params): | |||
| 11574 | 11559 | return await self._request_options_api('post', 'order', signed=True, data=params) | |
| 11575 | 11560 | ||
| 11576 | 11561 | async def options_place_batch_order(self, **params): | |
| 11562 | + for order in params['batchOrders']: | ||
| 11563 | + if 'newClientOrderId' not in order: | ||
| 11564 | + order['newClientOrderId'] = self.CONTRACT_ORDER_PREFIX + self.uuid22() | ||
| 11577 | 11565 | return await self._request_options_api('post', 'batchOrders', signed=True, data=params) | |
| 11578 | 11566 | ||
| 11579 | 11567 | async def options_cancel_order(self, **params): | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -133,7 +133,7 @@ def sort_depth(vals, reverse=False, conv_type: Callable = float): | |||
| 133 | 133 | class BaseDepthCacheManager: | |
| 134 | 134 | TIMEOUT = 60 | |
| 135 | 135 | ||
| 136 | - def __init__(self, client, symbol, loop=None, refresh_interval=DEFAULT_REFRESH, bm=None, limit=10, conv_type=float): | ||
| 136 | + def __init__(self, client, symbol, loop=None, refresh_interval: Optional[int]=DEFAULT_REFRESH, bm=None, limit=10, conv_type=float): | ||
| 137 | 137 | """Create a DepthCacheManager instance | |
| 138 | 138 | ||
| 139 | 139 | :param client: Binance API client | |
@@ -286,7 +286,7 @@ def get_symbol(self): | |||
| 286 | 286 | class DepthCacheManager(BaseDepthCacheManager): | |
| 287 | 287 | ||
| 288 | 288 | def __init__( | |
| 289 | - self, client, symbol, loop=None, refresh_interval=None, bm=None, limit=500, conv_type=float, ws_interval=None | ||
| 289 | + self, client, symbol, loop=None, refresh_interval: Optional[int]=None, bm=None, limit=500, conv_type=float, ws_interval=None | ||
| 290 | 290 | ): | |
| 291 | 291 | """Initialise the DepthCacheManager | |
| 292 | 292 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -43,6 +43,37 @@ def test_swap_id(): | |||
| 43 | 43 | assert url_dict['quantity'] == '0.1' | |
| 44 | 44 | assert url_dict['newClientOrderId'.lower()].startswith('x-Cb7ytekJ'.lower()) | |
| 45 | 45 | ||
| 46 | + def test_swap_batch_id(): | ||
| 47 | + with requests_mock.mock() as m: | ||
| 48 | + m.post("https://fapi.binance.com/fapi/v1/batchOrders", json={}, status_code=200) | ||
| 49 | + order = {"symbol" : "LTCUSDT", "side":"BUY", "type":"MARKET", "quantity":0.1} | ||
| 50 | + orders = [order, order] | ||
| 51 | + client.futures_place_batch_order(batchOrders=orders) | ||
| 52 | + text = m.last_request.text | ||
| 53 | + assert 'x-Cb7ytekJ' in text | ||
| 54 | + | ||
| 55 | + def test_coin_id(): | ||
| 56 | + with requests_mock.mock() as m: | ||
| 57 | + m.post("https://dapi.binance.com/dapi/v1/order", json={}, status_code=200) | ||
| 58 | + client.futures_coin_create_order(symbol="LTCUSD_PERP", side="BUY", type="MARKET", quantity=0.1) | ||
| 59 | + url_dict = dict(pair.split('=') for pair in m.last_request.text.split('&')) | ||
| 60 | + # why lowercase? check this later | ||
| 61 | + assert url_dict['symbol'] == 'LTCUSD_PERP' | ||
| 62 | + assert url_dict['side'] == 'BUY' | ||
| 63 | + assert url_dict['type'] == 'MARKET' | ||
| 64 | + assert url_dict['quantity'] == '0.1' | ||
| 65 | + assert url_dict['newClientOrderId'].startswith('x-Cb7ytekJ') | ||
| 66 | + | ||
| 67 | + | ||
| 68 | + def test_coin_batch_id(): | ||
| 69 | + with requests_mock.mock() as m: | ||
| 70 | + m.post("https://dapi.binance.com/dapi/v1/batchOrders", json={}, status_code=200) | ||
| 71 | + order = {"symbol" : "BTCUSD_PERP", "side":"BUY", "type":"MARKET", "quantity":0.1} | ||
| 72 | + orders = [order, order] | ||
| 73 | + client.futures_coin_place_batch_order(batchOrders=orders) | ||
| 74 | + text = m.last_request.text | ||
| 75 | + assert 'x-Cb7ytekJ' in text | ||
| 76 | + | ||
| 46 | 77 | ||
| 47 | 78 | def test_papi_um_id(): | |
| 48 | 79 | with requests_mock.mock() as m: | |
@@ -115,3 +146,39 @@ def handler(url, **kwargs): | |||
| 115 | 146 | m.post("https://papi.binance.com/papi/v1/cm/order", payload={'id': 1}, status=200, callback=handler) | |
| 116 | 147 | await clientAsync.papi_create_cm_order(symbol="LTCUSDT", side="BUY", type="MARKET", quantity=0.1) | |
| 117 | 148 | await clientAsync.close_connection() | |
| 149 | + | ||
| 150 | + @pytest.mark.asyncio() | ||
| 151 | + async def test_coin_id_async(): | ||
| 152 | + clientAsync = AsyncClient(api_key="api_key", api_secret="api_secret") | ||
| 153 | + with aioresponses() as m: | ||
| 154 | + def handler(url, **kwargs): | ||
| 155 | + client_order_id = kwargs['data'][0][1] | ||
| 156 | + assert client_order_id.startswith('x-Cb7ytekJ') | ||
| 157 | + m.post("https://dapi.binance.com/dapi/v1/order", payload={'id': 1}, status=200, callback=handler) | ||
| 158 | + await clientAsync.futures_coin_create_order(symbol="LTCUSD_PERP", side="BUY", type="MARKET", quantity=0.1) | ||
| 159 | + await clientAsync.close_connection() | ||
| 160 | + | ||
| 161 | + @pytest.mark.asyncio() | ||
| 162 | + async def test_swap_batch_id_async(): | ||
| 163 | + with aioresponses() as m: | ||
| 164 | + clientAsync = AsyncClient(api_key="api_key", api_secret="api_secret") | ||
| 165 | + def handler(url, **kwargs): | ||
| 166 | + assert 'x-Cb7ytekJ' in kwargs['data'][0][1] | ||
| 167 | + m.post("https://fapi.binance.com/fapi/v1/batchOrders", payload={'id': 1}, status=200, callback=handler) | ||
| 168 | + order = {"symbol" : "LTCUSDT", "side":"BUY", "type":"MARKET", "quantity":0.1} | ||
| 169 | + orders = [order, order] | ||
| 170 | + await clientAsync.futures_place_batch_order(batchOrders=orders) | ||
| 171 | + await clientAsync.close_connection() | ||
| 172 | + | ||
| 173 | + | ||
| 174 | + @pytest.mark.asyncio() | ||
| 175 | + async def test_coin_batch_id_async(): | ||
| 176 | + with aioresponses() as m: | ||
| 177 | + clientAsync = AsyncClient(api_key="api_key", api_secret="api_secret") | ||
| 178 | + def handler(url, **kwargs): | ||
| 179 | + assert 'x-Cb7ytekJ' in kwargs['data'][0][1] | ||
| 180 | + m.post("https://dapi.binance.com/dapi/v1/batchOrders", payload={'id': 1}, status=200, callback=handler) | ||
| 181 | + order = {"symbol" : "LTCUSD_PERP", "side":"BUY", "type":"MARKET", "quantity":0.1} | ||
| 182 | + orders = [order, order] | ||
| 183 | + await clientAsync.futures_coin_place_batch_order(batchOrders=orders) | ||
| 184 | + await clientAsync.close_connection() | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,54 @@ | |||
| 1 | + | ||
| 2 | + from binance.client import Client, AsyncClient | ||
| 3 | + import os | ||
| 4 | + import pytest | ||
| 5 | + | ||
| 6 | + proxies = {} | ||
| 7 | + proxy = os.getenv("PROXY") | ||
| 8 | + | ||
| 9 | + if proxy: | ||
| 10 | + proxies = {"http": proxy, 'https': proxy } # tmp: improve this in the future | ||
| 11 | + else: | ||
| 12 | + print("No proxy set") | ||
| 13 | + | ||
| 14 | + client = Client("api_key", "api_secret", {'proxies': proxies}) | ||
| 15 | + | ||
| 16 | + def test_papi_ping_sync(): | ||
| 17 | + ping_response = client.papi_ping() | ||
| 18 | + assert ping_response != None | ||
| 19 | + | ||
| 20 | + def test_ping_sync(): | ||
| 21 | + ping_response = client.ping() | ||
| 22 | + assert ping_response != None | ||
| 23 | + | ||
| 24 | + def test_futures_ping(): | ||
| 25 | + ping_response = client.futures_ping() | ||
| 26 | + assert ping_response != None | ||
| 27 | + | ||
| 28 | + def test_coin_ping(): | ||
| 29 | + ping_response = client.futures_coin_ping() | ||
| 30 | + assert ping_response != None | ||
| 31 | + | ||
| 32 | + @pytest.mark.asyncio() | ||
| 33 | + async def test_papi_ping_async(): | ||
| 34 | + clientAsync = AsyncClient(api_key="api_key", api_secret="api_secret", https_proxy=proxy) | ||
| 35 | + ping_response = await clientAsync.papi_ping() | ||
| 36 | + assert ping_response != None | ||
| 37 | + | ||
| 38 | + @pytest.mark.asyncio() | ||
| 39 | + async def test_ping_async(): | ||
| 40 | + clientAsync = AsyncClient(api_key="api_key", api_secret="api_secret", https_proxy=proxy) | ||
| 41 | + ping_response = await clientAsync.ping() | ||
| 42 | + assert ping_response != None | ||
| 43 | + | ||
| 44 | + @pytest.mark.asyncio() | ||
| 45 | + async def test_futures_ping_async(): | ||
| 46 | + clientAsync = AsyncClient(api_key="api_key", api_secret="api_secret", https_proxy=proxy) | ||
| 47 | + ping_response = await clientAsync.futures_ping() | ||
| 48 | + assert ping_response != None | ||
| 49 | + | ||
| 50 | + @pytest.mark.asyncio() | ||
| 51 | + async def test_coin_ping_async(): | ||
| 52 | + clientAsync = AsyncClient(api_key="api_key", api_secret="api_secret", https_proxy=proxy) | ||
| 53 | + ping_response = await clientAsync.futures_coin_ping() | ||
| 54 | + assert ping_response != None | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments