FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

feat(client): pyright fixes and batch orders (#1445) · SoniCoder/python-binance@6b3dbd0 · GitHub

Commit 6b3dbd0

Browse files
authored
feat(client): pyright fixes and batch orders (sammchardy#1445)
* chore: add readthedocs * pyrigh fixes and workflow * fix batch orders and tests * rm * fix test * rename * add tests
1 parent 81c43cf commit 6b3dbd0

7 files changed

Lines changed: 153 additions & 97 deletions

File tree

‎.github/workflows/lint.yml‎

Lines changed: 0 additions & 30 deletions
This file was deleted.

‎.github/workflows/python-app.yml‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
- name: Install dependencies
3030
run: |
3131
python -m pip install --upgrade pip
32-
pip install flake8 pytest
32+
pip install flake8 pytest pyright
3333
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
3434
if [ -f test-requirements.txt ]; then pip install -r test-requirements.txt; fi
3535
- name: Lint with flake8
@@ -38,6 +38,8 @@ jobs:
3838
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
3939
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
4040
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
41+
- name: Type check with pyright
42+
run: pyright
4143
- name: Test with pytest
4244
run: |
4345
pytest

‎binance/client.py‎

Lines changed: 27 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -274,12 +274,12 @@ def _create_options_api_uri(self, path: str) -> str:
274274
def _rsa_signature(self, query_string: str):
275275
assert self.PRIVATE_KEY
276276
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
278278
return b64encode(signature).decode()
279279

280280
def _ed25519_signature(self, query_string: str):
281281
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
283283

284284
def _hmac_signature(self, query_string: str) -> str:
285285
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
440440
version = self._get_version(version, **kwargs)
441441
uri = self._create_futures_coin_api_url(path, version=version)
442442

443-
return self._request(method, uri, signed, True, **kwargs)
443+
return self._request(method, uri, signed, False, **kwargs)
444444

445445
def _request_futures_coin_data_api(self, method, path, signed=False, version=1, **kwargs) -> Dict:
446446
version = self._get_version(version, **kwargs)
@@ -1561,6 +1561,7 @@ def create_order(self, **params):
15611561
params['newClientOrderId'] = self.SPOT_ORDER_PREFIX + self.uuid22()
15621562
return self._post('order', True, data=params)
15631563

1564+
15641565
def order_limit(self, timeInForce=BaseClient.TIME_IN_FORCE_GTC, **params):
15651566
"""Send in a new limit order
15661567
@@ -3711,38 +3712,6 @@ def get_margin_capital_flow(self, **params):
37113712
"""
37123713
return self._request_margin_api('get', 'margin/capital-flow', True, data=params)
37133714

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-
37463715
def get_margin_asset(self, **params):
37473716
"""Query cross-margin asset
37483717
@@ -7424,6 +7393,9 @@ def futures_place_batch_order(self, **params):
74247393
the url encoding is done on the special query param, batchOrders, in the early stage.
74257394
74267395
"""
7396+
for order in params['batchOrders']:
7397+
if 'newClientOrderId' not in order:
7398+
order['newClientOrderId'] = self.CONTRACT_ORDER_PREFIX + self.uuid22()
74277399
query_string = urlencode(params)
74287400
query_string = query_string.replace('%27', '%22')
74297401
params['batchOrders'] = query_string[12:]
@@ -7823,6 +7795,8 @@ def futures_coin_create_order(self, **params):
78237795
https://binance-docs.github.io/apidocs/delivery/en/#new-order-trade
78247796
78257797
"""
7798+
if 'newClientOrderId' not in params:
7799+
params['newClientOrderId'] = self.CONTRACT_ORDER_PREFIX + self.uuid22()
78267800
return self._request_futures_coin_api("post", "order", True, data=params)
78277801

78287802
def futures_coin_place_batch_order(self, **params):
@@ -7834,6 +7808,9 @@ def futures_coin_place_batch_order(self, **params):
78347808
the url encoding is done on the special query param, batchOrders, in the early stage.
78357809
78367810
"""
7811+
for order in params['batchOrders']:
7812+
if 'newClientOrderId' not in order:
7813+
order['newClientOrderId'] = self.CONTRACT_ORDER_PREFIX + self.uuid22()
78377814
query_string = urlencode(params)
78387815
query_string = query_string.replace('%27', '%22')
78397816
params['batchOrders'] = query_string[12:]
@@ -8471,6 +8448,9 @@ def options_place_batch_order(self, **params):
84718448
:type recvWindow: int
84728449
84738450
"""
8451+
for order in params['batchOrders']:
8452+
if 'newClientOrderId' not in order:
8453+
order['newClientOrderId'] = self.CONTRACT_ORDER_PREFIX + self.uuid22()
84748454
return self._request_options_api('post', 'batchOrders', signed=True, data=params)
84758455

84768456
def options_cancel_order(self, **params):
@@ -10115,7 +10095,7 @@ async def _request_futures_coin_api(self, method, path, signed=False, version=1,
1011510095
version = self._get_version(version, **kwargs)
1011610096
uri = self._create_futures_coin_api_url(path, version=version)
1011710097

10118-
return await self._request(method, uri, signed, True, **kwargs)
10098+
return await self._request(method, uri, signed, False, **kwargs)
1011910099

1012010100
async def _request_futures_coin_data_api(self, method, path, signed=False, version=1, **kwargs) -> Dict:
1012110101
version = self._get_version(version, **kwargs)
@@ -10889,9 +10869,6 @@ async def get_max_margin_loan(self, **params):
1088910869
async def get_max_margin_transfer(self, **params):
1089010870
return await self._request_margin_api('get', 'margin/maxTransferable', signed=True, data=params)
1089110871

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-
1089510872
# Margin OCO
1089610873

1089710874
async def create_margin_oco_order(self, **params):
@@ -11235,6 +11212,9 @@ async def futures_create_test_order(self, **params):
1123511212
return await self._request_futures_api('post', 'order/test', True, data=params)
1123611213

1123711214
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()
1123811218
query_string = urlencode(params)
1123911219
query_string = query_string.replace('%27', '%22')
1124011220
params['batchOrders'] = query_string[12:]
@@ -11405,9 +11385,14 @@ async def universal_transfer(self, **params):
1140511385
)
1140611386

1140711387
async def futures_coin_create_order(self, **params):
11388+
if 'newClientOrderId' not in params:
11389+
params['newClientOrderId'] = self.CONTRACT_ORDER_PREFIX + self.uuid22()
1140811390
return await self._request_futures_coin_api("post", "order", True, data=params)
1140911391

1141011392
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()
1141111396
query_string = urlencode(params)
1141211397
query_string = query_string.replace('%27', '%22')
1141311398
params['batchOrders'] = query_string[12:]
@@ -11574,6 +11559,9 @@ async def options_place_order(self, **params):
1157411559
return await self._request_options_api('post', 'order', signed=True, data=params)
1157511560

1157611561
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()
1157711565
return await self._request_options_api('post', 'batchOrders', signed=True, data=params)
1157811566

1157911567
async def options_cancel_order(self, **params):

‎binance/depthcache.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def sort_depth(vals, reverse=False, conv_type: Callable = float):
133133
class BaseDepthCacheManager:
134134
TIMEOUT = 60
135135

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):
137137
"""Create a DepthCacheManager instance
138138
139139
:param client: Binance API client
@@ -286,7 +286,7 @@ def get_symbol(self):
286286
class DepthCacheManager(BaseDepthCacheManager):
287287

288288
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
290290
):
291291
"""Initialise the DepthCacheManager
292292

‎tests/test_ids.py‎

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,37 @@ def test_swap_id():
4343
assert url_dict['quantity'] == '0.1'
4444
assert url_dict['newClientOrderId'.lower()].startswith('x-Cb7ytekJ'.lower())
4545

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+
4677

4778
def test_papi_um_id():
4879
with requests_mock.mock() as m:
@@ -115,3 +146,39 @@ def handler(url, **kwargs):
115146
m.post("https://papi.binance.com/papi/v1/cm/order", payload={'id': 1}, status=200, callback=handler)
116147
await clientAsync.papi_create_cm_order(symbol="LTCUSDT", side="BUY", type="MARKET", quantity=0.1)
117148
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()

‎tests/test_papi.py‎

Lines changed: 0 additions & 25 deletions
This file was deleted.

‎tests/test_ping.py‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff 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

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL