11import asyncio
22from pathlib import Path
33from typing import Any , Dict , List , Optional , Union
4- from urllib .parse import urlencode
4+ from urllib .parse import urlencode , quote
55import time
66import aiohttp
77import yarl
1212 BinanceRequestException ,
1313 NotImplementedException ,
1414)
15- from binance .helpers import convert_ts_str , get_loop , interval_to_milliseconds
15+ from binance .helpers import (
16+ convert_list_to_json_array ,
17+ convert_ts_str ,
18+ get_loop ,
19+ interval_to_milliseconds ,
20+ )
1621from .base_client import BaseClient
1722from .client import Client
1823
@@ -102,16 +107,32 @@ async def close_connection(self):
102107 async def _request (
103108 self , method , uri : str , signed : bool , force_params : bool = False , ** kwargs
104109 ):
110+ # this check needs to be done before __get_request_kwargs to avoid
111+ # polluting the signature
112+ headers = {}
113+ if method .upper () in ["POST" , "PUT" , "DELETE" ]:
114+ headers .update ({"Content-Type" : "application/x-www-form-urlencoded" })
115+
116+ if "data" in kwargs :
117+ for key in kwargs ["data" ]:
118+ if key == "headers" :
119+ headers .update (kwargs ["data" ][key ])
120+ del kwargs ["data" ][key ]
121+ break
122+
105123 kwargs = self ._get_request_kwargs (method , signed , force_params , ** kwargs )
106124
107- if method == ' get' :
125+ if method == " get" :
108126 # url encode the query string
109- if ' params' in kwargs :
127+ if " params" in kwargs :
110128 uri = f"{ uri } ?{ kwargs ['params' ]} "
111- kwargs .pop (' params' )
129+ kwargs .pop (" params" )
112130
113131 async with getattr (self .session , method )(
114- yarl .URL (uri , encoded = True ), proxy = self .https_proxy , ** kwargs
132+ yarl .URL (uri , encoded = True ),
133+ proxy = self .https_proxy ,
134+ headers = headers ,
135+ ** kwargs ,
115136 ) as response :
116137 self .response = response
117138 return await self ._handle_response (response )
@@ -138,59 +159,64 @@ async def _request_api(
138159 ** kwargs ,
139160 ):
140161 uri = self ._create_api_uri (path , signed , version )
141- return await self ._request (method , uri , signed , ** kwargs )
162+ force_params = kwargs .pop ("force_params" , False )
163+ return await self ._request (method , uri , signed , force_params , ** kwargs )
142164
143165 async def _request_futures_api (
144166 self , method , path , signed = False , version = 1 , ** kwargs
145167 ) -> Dict :
146168 version = self ._get_version (version , ** kwargs )
147169 uri = self ._create_futures_api_uri (path , version = version )
148-
149- return await self ._request (method , uri , signed , False , ** kwargs )
170+ force_params = kwargs . pop ( "force_params" , False )
171+ return await self ._request (method , uri , signed , force_params , ** kwargs )
150172
151173 async def _request_futures_data_api (
152174 self , method , path , signed = False , ** kwargs
153175 ) -> Dict :
154176 uri = self ._create_futures_data_api_uri (path )
155-
156- return await self ._request (method , uri , signed , True , ** kwargs )
177+ force_params = kwargs . pop ( "force_params" , True )
178+ return await self ._request (method , uri , signed , force_params , ** kwargs )
157179
158180 async def _request_futures_coin_api (
159181 self , method , path , signed = False , version = 1 , ** kwargs
160182 ) -> Dict :
161183 version = self ._get_version (version , ** kwargs )
162184 uri = self ._create_futures_coin_api_url (path , version = version )
163-
164- return await self ._request (method , uri , signed , False , ** kwargs )
185+ force_params = kwargs . pop ( "force_params" , False )
186+ return await self ._request (method , uri , signed , force_params , ** kwargs )
165187
166188 async def _request_futures_coin_data_api (
167189 self , method , path , signed = False , version = 1 , ** kwargs
168190 ) -> Dict :
169191 version = self ._get_version (version , ** kwargs )
170192 uri = self ._create_futures_coin_data_api_url (path , version = version )
171193
172- return await self ._request (method , uri , signed , True , ** kwargs )
194+ force_params = kwargs .pop ("force_params" , True )
195+ return await self ._request (method , uri , signed , force_params , ** kwargs )
173196
174197 async def _request_options_api (self , method , path , signed = False , ** kwargs ) -> Dict :
175198 uri = self ._create_options_api_uri (path )
199+ force_params = kwargs .pop ("force_params" , True )
176200
177- return await self ._request (method , uri , signed , True , ** kwargs )
201+ return await self ._request (method , uri , signed , force_params , ** kwargs )
178202
179203 async def _request_margin_api (
180204 self , method , path , signed = False , version = 1 , ** kwargs
181205 ) -> Dict :
182206 version = self ._get_version (version , ** kwargs )
183207 uri = self ._create_margin_api_uri (path , version )
184208
185- return await self ._request (method , uri , signed , ** kwargs )
209+ force_params = kwargs .pop ("force_params" , False )
210+ return await self ._request (method , uri , signed , force_params , ** kwargs )
186211
187212 async def _request_papi_api (
188213 self , method , path , signed = False , version = 1 , ** kwargs
189214 ) -> Dict :
190215 version = self ._get_version (version , ** kwargs )
191216 uri = self ._create_papi_api_uri (path , version )
192217
193- return await self ._request (method , uri , signed , ** kwargs )
218+ force_params = kwargs .pop ("force_params" , False )
219+ return await self ._request (method , uri , signed , force_params , ** kwargs )
194220
195221 async def _request_website (self , method , path , signed = False , ** kwargs ) -> Dict :
196222 uri = self ._create_website_uri (path )
@@ -712,13 +738,16 @@ async def get_account(self, **params):
712738
713739 get_account .__doc__ = Client .get_account .__doc__
714740
715- async def get_asset_balance (self , asset , ** params ):
741+ async def get_asset_balance (self , asset = None , ** params ):
716742 res = await self .get_account (** params )
717743 # find asset balance in list of balances
718744 if "balances" in res :
719- for bal in res ["balances" ]:
720- if bal ["asset" ].lower () == asset .lower ():
721- return bal
745+ if asset :
746+ for bal in res ["balances" ]:
747+ if bal ["asset" ].lower () == asset .lower ():
748+ return bal
749+ else :
750+ return res ["balances" ]
722751 return None
723752
724753 get_asset_balance .__doc__ = Client .get_asset_balance .__doc__
@@ -1775,17 +1804,28 @@ async def futures_create_order(self, **params):
17751804 params ["newClientOrderId" ] = self .CONTRACT_ORDER_PREFIX + self .uuid22 ()
17761805 return await self ._request_futures_api ("post" , "order" , True , data = params )
17771806
1807+ async def futures_modify_order (self , ** params ):
1808+ """Modify an existing order. Currently only LIMIT order modification is supported.
1809+
1810+ https://binance-docs.github.io/apidocs/futures/en/#modify-order-trade
1811+
1812+ """
1813+ return await self ._request_futures_api ("put" , "order" , True , data = params )
1814+
17781815 async def futures_create_test_order (self , ** params ):
17791816 return await self ._request_futures_api ("post" , "order/test" , True , data = params )
17801817
17811818 async def futures_place_batch_order (self , ** params ):
17821819 for order in params ["batchOrders" ]:
17831820 if "newClientOrderId" not in order :
17841821 order ["newClientOrderId" ] = self .CONTRACT_ORDER_PREFIX + self .uuid22 ()
1785- query_string = urlencode ( params )
1786- query_string = query_string .replace ("%27" , "%22" )
1822+ order = self . _order_params ( order )
1823+ query_string = urlencode ( params ). replace ( "%40" , "@" ) .replace ("%27" , "%22" )
17871824 params ["batchOrders" ] = query_string [12 :]
1788- return await self ._request_futures_api ("post" , "batchOrders" , True , data = params )
1825+
1826+ return await self ._request_futures_api (
1827+ "post" , "batchOrders" , True , data = params , force_params = True
1828+ )
17891829
17901830 async def futures_get_order (self , ** params ):
17911831 return await self ._request_futures_api ("get" , "order" , True , data = params )
@@ -1805,8 +1845,16 @@ async def futures_cancel_all_open_orders(self, **params):
18051845 )
18061846
18071847 async def futures_cancel_orders (self , ** params ):
1848+ if params .get ("orderidlist" ):
1849+ params ["orderidlist" ] = quote (
1850+ convert_list_to_json_array (params ["orderidlist" ])
1851+ )
1852+ if params .get ("origclientorderidlist" ):
1853+ params ["origclientorderidlist" ] = quote (
1854+ convert_list_to_json_array (params ["origclientorderidlist" ])
1855+ )
18081856 return await self ._request_futures_api (
1809- "delete" , "batchOrders" , True , data = params
1857+ "delete" , "batchOrders" , True , data = params , force_params = True
18101858 )
18111859
18121860 async def futures_countdown_cancel_all (self , ** params ):
@@ -2036,10 +2084,18 @@ async def futures_coin_cancel_order(self, **params):
20362084
20372085 async def futures_coin_cancel_all_open_orders (self , ** params ):
20382086 return await self ._request_futures_coin_api (
2039- "delete" , "allOpenOrders" , signed = True , data = params
2087+ "delete" , "allOpenOrders" , signed = True , data = params , force_params = True
20402088 )
20412089
20422090 async def futures_coin_cancel_orders (self , ** params ):
2091+ if params .get ("orderidlist" ):
2092+ params ["orderidlist" ] = quote (
2093+ convert_list_to_json_array (params ["orderidlist" ])
2094+ )
2095+ if params .get ("origclientorderidlist" ):
2096+ params ["origclientorderidlist" ] = quote (
2097+ convert_list_to_json_array (params ["origclientorderidlist" ])
2098+ )
20432099 return await self ._request_futures_coin_api (
20442100 "delete" , "batchOrders" , True , data = params
20452101 )
@@ -3601,3 +3657,51 @@ async def ws_futures_account_status(self, **params):
36013657 https://developers.binance.com/docs/derivatives/usds-margined-futures/account/websocket-api/Account-Information
36023658 """
36033659 return await self ._ws_futures_api_request ("account.status" , True , params )
3660+
3661+ ####################################################
3662+ # Gift Card API Endpoints
3663+ ####################################################
3664+
3665+ async def gift_card_fetch_token_limit (self , ** params ):
3666+ return await self ._request_margin_api (
3667+ "get" , "giftcard/buyCode/token-limit" , signed = True , data = params
3668+ )
3669+
3670+ gift_card_fetch_token_limit .__doc__ = Client .gift_card_fetch_token_limit .__doc__
3671+
3672+ async def gift_card_fetch_rsa_public_key (self , ** params ):
3673+ return await self ._request_margin_api (
3674+ "get" , "giftcard/cryptography/rsa-public-key" , signed = True , data = params
3675+ )
3676+
3677+ gift_card_fetch_rsa_public_key .__doc__ = (
3678+ Client .gift_card_fetch_rsa_public_key .__doc__
3679+ )
3680+
3681+ async def gift_card_verify (self , ** params ):
3682+ return await self ._request_margin_api (
3683+ "get" , "giftcard/verify" , signed = True , data = params
3684+ )
3685+
3686+ gift_card_verify .__doc__ = Client .gift_card_verify .__doc__
3687+
3688+ async def gift_card_redeem (self , ** params ):
3689+ return await self ._request_margin_api (
3690+ "post" , "giftcard/redeemCode" , signed = True , data = params
3691+ )
3692+
3693+ gift_card_redeem .__doc__ = Client .gift_card_redeem .__doc__
3694+
3695+ async def gift_card_create (self , ** params ):
3696+ return await self ._request_margin_api (
3697+ "post" , "giftcard/createCode" , signed = True , data = params
3698+ )
3699+
3700+ gift_card_create .__doc__ = Client .gift_card_create .__doc__
3701+
3702+ async def gift_card_create_dual_token (self , ** params ):
3703+ return await self ._request_margin_api (
3704+ "post" , "giftcard/buyCode" , signed = True , data = params
3705+ )
3706+
3707+ gift_card_create_dual_token .__doc__ = Client .gift_card_create_dual_token .__doc__
0 commit comments