Skip to content

Commit 6866ca5

Browse files
m-HDcarlosmiei
andauthored
added cancel_replace_order, cancel_all_open_orders and cancel_all_open_margin_orders to client.py (sammchardy#1475)
* added cancel_replace_order, cancel_all_open_orders and cancel_all_open_margin_orders to client.py * added TIME_IN_FORCE_GTD * added parameters for get_current_order_count() * added parameters for get_current_order_count() * fix params * changed quotation marks * add missing version * add id * space * add tests --------- Co-authored-by: m-HD <none> Co-authored-by: carlosmiei <43336371+carlosmiei@users.noreply.github.com>
1 parent 1867c30 commit 6866ca5

3 files changed

Lines changed: 164 additions & 5 deletions

File tree

binance/client.py

Lines changed: 132 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2160,6 +2160,117 @@ def cancel_order(self, **params):
21602160
"""
21612161
return self._delete("order", True, data=params)
21622162

2163+
def cancel_all_open_orders(self, **params):
2164+
return self._delete("openOrders", True, data=params)
2165+
2166+
def cancel_replace_order(self, **params):
2167+
"""Cancels an existing order and places a new order on the same symbol.
2168+
2169+
Filters and Order Count are evaluated before the processing of the cancellation and order placement occurs.
2170+
2171+
A new order that was not attempted (i.e. when newOrderResult: NOT_ATTEMPTED), will still increase the order count by 1.
2172+
2173+
https://binance-docs.github.io/apidocs/spot/en/#cancel-an-existing-order-and-send-a-new-order-trade
2174+
2175+
:param symbol: required
2176+
:type symbol: str
2177+
:param side: required
2178+
:type side: enum
2179+
:param type: required
2180+
:type type: enum
2181+
:param cancelReplaceMode: required - STOP_ON_FAILURE or ALLOW_FAILURE
2182+
:type cancelReplaceMode: enum
2183+
:param timeInForce: optional
2184+
:type timeInForce: enum
2185+
:param quantity: optional
2186+
:type quantity: decimal
2187+
:param quoteOrderQty: optional
2188+
:type quoteOrderQty: decimal
2189+
:param price: optional
2190+
:type price: decimal
2191+
:param cancelNewClientOrderId: optional - Used to uniquely identify this cancel. Automatically generated by default.
2192+
:type cancelNewClientOrderId: str
2193+
:param cancelOrigClientOrderId: optional - Either the cancelOrigClientOrderId or cancelOrderId must be provided. If both are provided, cancelOrderId takes precedence.
2194+
:type cancelOrigClientOrderId: str
2195+
:param cancelOrderId: optional - Either the cancelOrigClientOrderId or cancelOrderId must be provided. If both are provided, cancelOrderId takes precedence.
2196+
:type cancelOrderId: long
2197+
:param newClientOrderId: optional - Used to identify the new order.
2198+
:type newClientOrderId: str
2199+
:param strategyId: optional
2200+
:type strategyId: int
2201+
:param strategyType: optional - The value cannot be less than 1000000.
2202+
:type strategyType: int
2203+
:param stopPrice: optional
2204+
:type stopPrice: decimal
2205+
:param trailingDelta: optional
2206+
:type trailingDelta: long
2207+
:param icebergQty: optional
2208+
:type icebergQty: decimal
2209+
:param newOrderRespType: optional - ACK, RESULT or FULL. MARKET and LIMIT orders types default to FULL; all other orders default to ACK
2210+
:type newOrderRespType: enum
2211+
:param selfTradePreventionMode: optional - EXPIRE_TAKER, EXPIRE_MAKER, EXPIRE_BOTH or NONE.
2212+
:type selfTradePreventionMode: enum
2213+
:param cancelRestrictions: optional - ONLY_NEW or ONLY_PARTIALLY_FILLED
2214+
:type cancelRestrictions: enum
2215+
:param recvWindow: optional - The value cannot be greater than 60000
2216+
:type recvWindow: int
2217+
2218+
:returns: API response
2219+
2220+
.. code-block:: python
2221+
2222+
//Both the cancel order placement and new order placement succeeded.
2223+
{
2224+
"cancelResult": "SUCCESS",
2225+
"newOrderResult": "SUCCESS",
2226+
"cancelResponse": {
2227+
"symbol": "BTCUSDT",
2228+
"origClientOrderId": "DnLo3vTAQcjha43lAZhZ0y",
2229+
"orderId": 9,
2230+
"orderListId": -1,
2231+
"clientOrderId": "osxN3JXAtJvKvCqGeMWMVR",
2232+
"transactTime": 1684804350068,
2233+
"price": "0.01000000",
2234+
"origQty": "0.000100",
2235+
"executedQty": "0.00000000",
2236+
"cummulativeQuoteQty": "0.00000000",
2237+
"status": "CANCELED",
2238+
"timeInForce": "GTC",
2239+
"type": "LIMIT",
2240+
"side": "SELL",
2241+
"selfTradePreventionMode": "NONE"
2242+
},
2243+
"newOrderResponse": {
2244+
"symbol": "BTCUSDT",
2245+
"orderId": 10,
2246+
"orderListId": -1,
2247+
"clientOrderId": "wOceeeOzNORyLiQfw7jd8S",
2248+
"transactTime": 1652928801803,
2249+
"price": "0.02000000",
2250+
"origQty": "0.040000",
2251+
"executedQty": "0.00000000",
2252+
"cummulativeQuoteQty": "0.00000000",
2253+
"status": "NEW",
2254+
"timeInForce": "GTC",
2255+
"type": "LIMIT",
2256+
"side": "BUY",
2257+
"workingTime": 1669277163808,
2258+
"fills": [],
2259+
"selfTradePreventionMode": "NONE"
2260+
2261+
}
2262+
}
2263+
Similar to POST /api/v3/order, additional mandatory parameters are determined by type.
2264+
2265+
Response format varies depending on whether the processing of the message succeeded, partially succeeded, or failed.
2266+
2267+
:raises: BinanceRequestException, BinanceAPIException
2268+
2269+
"""
2270+
if "newClientOrderId" not in params:
2271+
params["newClientOrderId"] = self.SPOT_ORDER_PREFIX + self.uuid22()
2272+
return self._post("order/cancelReplace", True, data=params)
2273+
21632274
def get_open_orders(self, **params):
21642275
"""Get all open orders on a symbol.
21652276
@@ -2341,10 +2452,10 @@ def get_my_trades(self, **params):
23412452
"""
23422453
return self._get("myTrades", True, data=params)
23432454

2344-
def get_current_order_count(self):
2455+
def get_current_order_count(self, **params):
23452456
"""Displays the user's current order count usage for all intervals.
23462457
2347-
https://binance-docs.github.io/apidocs/spot/en/#query-current-order-count-usage-trade
2458+
https://binance-docs.github.io/apidocs/spot/en/#query-unfilled-order-count-user_data
23482459
23492460
:returns: API response
23502461
@@ -2368,7 +2479,7 @@ def get_current_order_count(self):
23682479
]
23692480
23702481
"""
2371-
return self._get("rateLimit/order", True)
2482+
return self._get("rateLimit/order", True, data=params)
23722483

23732484
def get_prevented_matches(self, **params):
23742485
"""Displays the list of orders that were expired because of STP.
@@ -4717,6 +4828,9 @@ def cancel_margin_order(self, **params):
47174828
"delete", "margin/order", signed=True, data=params
47184829
)
47194830

4831+
def cancel_all_open_margin_orders(self, **params):
4832+
return self._request_margin_api("delete", "margin/openOrders", signed=True, data=params)
4833+
47204834
def set_margin_max_leverage(self, **params):
47214835
"""Adjust cross margin max leverage
47224836
@@ -11065,6 +11179,14 @@ async def cancel_order(self, **params):
1106511179

1106611180
cancel_order.__doc__ = Client.cancel_order.__doc__
1106711181

11182+
async def cancel_all_open_orders(self, **params):
11183+
return await self._delete("openOrders", True, data=params)
11184+
11185+
async def cancel_replace_order(self, **params):
11186+
if "newClientOrderId" not in params:
11187+
params["newClientOrderId"] = self.SPOT_ORDER_PREFIX + self.uuid22()
11188+
return await self._post("order/cancelReplace", signed=True, data=params)
11189+
1106811190
async def get_open_orders(self, **params):
1106911191
return await self._get("openOrders", True, data=params)
1107011192

@@ -11097,8 +11219,8 @@ async def get_my_trades(self, **params):
1109711219

1109811220
get_my_trades.__doc__ = Client.get_my_trades.__doc__
1109911221

11100-
async def get_current_order_count(self):
11101-
return await self._get("rateLimit/order", True)
11222+
async def get_current_order_count(self, **params):
11223+
return await self._get("rateLimit/order", True, data=params)
1110211224

1110311225
get_current_order_count.__doc__ = Client.get_current_order_count.__doc__
1110411226

@@ -11543,6 +11665,11 @@ async def cancel_margin_order(self, **params):
1154311665

1154411666
cancel_margin_order.__doc__ = Client.cancel_margin_order.__doc__
1154511667

11668+
async def cancel_all_open_margin_orders(self, **params):
11669+
return await self._request_margin_api("delete", "margin/openOrders", signed=True, data=params)
11670+
11671+
cancel_all_open_margin_orders.__doc__ = Client.cancel_all_open_margin_orders.__doc__
11672+
1154611673
async def set_margin_max_leverage(self, **params):
1154711674
return await self._request_margin_api(
1154811675
"post", "margin/max-leverage", signed=True, data=params

binance/enums.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
TIME_IN_FORCE_IOC = "IOC" # Immediate or cancel
5252
TIME_IN_FORCE_FOK = "FOK" # Fill or kill
5353
TIME_IN_FORCE_GTX = "GTX" # Post only order
54+
TIME_IN_FORCE_GTD = "GTD" # Good till date
5455

5556
ORDER_RESP_TYPE_ACK = "ACK"
5657
ORDER_RESP_TYPE_RESULT = "RESULT"

tests/test_ids.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ def test_spot_market_id():
3939
assert url_dict["newClientOrderId"].startswith("x-HNA2TXFJ")
4040

4141

42+
def test_spot_cancel_replace_id():
43+
with requests_mock.mock() as m:
44+
m.post("https://api.binance.com/api/v3/order/cancelReplace", json={}, status_code=200)
45+
client.cancel_replace_order(
46+
cancelOrderId="orderId", symbol="LTCUSDT", side="BUY", type="MARKET", quantity=0.1
47+
)
48+
url_dict = dict(pair.split("=") for pair in m.last_request.text.split("&"))
49+
assert url_dict["newClientOrderId"].startswith("x-HNA2TXFJ")
50+
4251
def test_swap_id():
4352
with requests_mock.mock() as m:
4453
m.post("https://fapi.binance.com/fapi/v1/order", json={}, status_code=200)
@@ -147,6 +156,28 @@ def handler(url, **kwargs):
147156
await clientAsync.close_connection()
148157

149158

159+
@pytest.mark.asyncio()
160+
async def test_spot_cancel_replace_id_async():
161+
clientAsync = AsyncClient(
162+
api_key="api_key", api_secret="api_secret"
163+
) # reuse client later
164+
with aioresponses() as m:
165+
166+
def handler(url, **kwargs):
167+
client_order_id = kwargs["data"][0][1]
168+
assert client_order_id.startswith("x-HNA2TXFJ")
169+
170+
m.post(
171+
"https://api.binance.com/api/v3/order/cancelReplace",
172+
payload={"id": 1},
173+
status=200,
174+
callback=handler,
175+
)
176+
await clientAsync.cancel_replace_order(
177+
orderId="id", symbol="LTCUSDT", side="BUY", type="MARKET", quantity=0.1
178+
)
179+
await clientAsync.close_connection()
180+
150181
@pytest.mark.asyncio()
151182
async def test_swap_id_async():
152183
clientAsync = AsyncClient(api_key="api_key", api_secret="api_secret")

0 commit comments

Comments
 (0)