ccxt 4.3.4__py2.py3-none-any.whl → 4.3.6__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/binance.py +1 -0
  3. ccxt/abstract/binancecoinm.py +1 -0
  4. ccxt/abstract/binanceus.py +1 -0
  5. ccxt/abstract/binanceusdm.py +1 -0
  6. ccxt/abstract/bingx.py +1 -0
  7. ccxt/abstract/whitebit.py +22 -1
  8. ccxt/abstract/woo.py +1 -0
  9. ccxt/async_support/__init__.py +1 -1
  10. ccxt/async_support/base/exchange.py +227 -36
  11. ccxt/async_support/binance.py +21 -14
  12. ccxt/async_support/bingx.py +40 -0
  13. ccxt/async_support/bitmex.py +22 -0
  14. ccxt/async_support/bybit.py +81 -1
  15. ccxt/async_support/coinbase.py +4 -4
  16. ccxt/async_support/coinex.py +29 -32
  17. ccxt/async_support/cryptocom.py +30 -1
  18. ccxt/async_support/htx.py +26 -0
  19. ccxt/async_support/hyperliquid.py +37 -0
  20. ccxt/async_support/kraken.py +27 -0
  21. ccxt/async_support/krakenfutures.py +26 -0
  22. ccxt/async_support/kucoin.py +52 -4
  23. ccxt/async_support/kucoinfutures.py +2 -2
  24. ccxt/async_support/okx.py +104 -1
  25. ccxt/async_support/whitebit.py +149 -2
  26. ccxt/async_support/woo.py +27 -0
  27. ccxt/base/exchange.py +233 -4
  28. ccxt/binance.py +21 -14
  29. ccxt/bingx.py +40 -0
  30. ccxt/bitmex.py +22 -0
  31. ccxt/bybit.py +81 -1
  32. ccxt/coinbase.py +4 -4
  33. ccxt/coinex.py +29 -32
  34. ccxt/cryptocom.py +30 -1
  35. ccxt/htx.py +26 -0
  36. ccxt/hyperliquid.py +37 -0
  37. ccxt/kraken.py +27 -0
  38. ccxt/krakenfutures.py +26 -0
  39. ccxt/kucoin.py +52 -4
  40. ccxt/kucoinfutures.py +2 -2
  41. ccxt/okx.py +104 -1
  42. ccxt/pro/__init__.py +1 -1
  43. ccxt/pro/binance.py +410 -73
  44. ccxt/pro/bitget.py +1 -1
  45. ccxt/pro/cex.py +1 -1
  46. ccxt/pro/lbank.py +1 -1
  47. ccxt/pro/woo.py +0 -1
  48. ccxt/test/test_async.py +17 -17
  49. ccxt/test/test_sync.py +17 -17
  50. ccxt/whitebit.py +149 -2
  51. ccxt/woo.py +27 -0
  52. {ccxt-4.3.4.dist-info → ccxt-4.3.6.dist-info}/METADATA +4 -4
  53. {ccxt-4.3.4.dist-info → ccxt-4.3.6.dist-info}/RECORD +55 -55
  54. {ccxt-4.3.4.dist-info → ccxt-4.3.6.dist-info}/WHEEL +0 -0
  55. {ccxt-4.3.4.dist-info → ccxt-4.3.6.dist-info}/top_level.txt +0 -0
@@ -47,6 +47,7 @@ class bingx(Exchange, ImplicitAPI):
47
47
  'option': False,
48
48
  'addMargin': True,
49
49
  'cancelAllOrders': True,
50
+ 'cancelAllOrdersAfter': True,
50
51
  'cancelOrder': True,
51
52
  'cancelOrders': True,
52
53
  'closeAllPositions': True,
@@ -243,6 +244,7 @@ class bingx(Exchange, ImplicitAPI):
243
244
  'trade/order': 3,
244
245
  'trade/batchOrders': 3,
245
246
  'trade/closeAllPositions': 3,
247
+ 'trade/cancelAllAfter': 3,
246
248
  'trade/marginType': 3,
247
249
  'trade/leverage': 3,
248
250
  'trade/positionMargin': 3,
@@ -2582,6 +2584,44 @@ class bingx(Exchange, ImplicitAPI):
2582
2584
  #
2583
2585
  return response
2584
2586
 
2587
+ async def cancel_all_orders_after(self, timeout: Int, params={}):
2588
+ """
2589
+ dead man's switch, cancel all orders after the given timeout
2590
+ :see: https://bingx-api.github.io/docs/#/en-us/spot/trade-api.html#Cancel%20all%20orders%20in%20countdown
2591
+ :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#Cancel%20all%20orders%20in%20countdown
2592
+ :param number timeout: time in milliseconds, 0 represents cancel the timer
2593
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2594
+ :param str [params.type]: spot or swap market
2595
+ :returns dict: the api result
2596
+ """
2597
+ await self.load_markets()
2598
+ isActive = (timeout > 0)
2599
+ request: dict = {
2600
+ 'type': 'ACTIVATE' if (isActive) else 'CLOSE',
2601
+ 'timeOut': (self.parse_to_int(timeout / 1000)) if (isActive) else 0,
2602
+ }
2603
+ response = None
2604
+ type = None
2605
+ type, params = self.handle_market_type_and_params('cancelAllOrdersAfter', None, params)
2606
+ if type == 'spot':
2607
+ response = await self.spotV1PrivatePostTradeCancelAllAfter(self.extend(request, params))
2608
+ elif type == 'swap':
2609
+ response = await self.swapV2PrivatePostTradeCancelAllAfter(self.extend(request, params))
2610
+ else:
2611
+ raise NotSupported(self.id + ' cancelAllOrdersAfter() is not supported for ' + type + ' markets')
2612
+ #
2613
+ # {
2614
+ # code: '0',
2615
+ # msg: '',
2616
+ # data: {
2617
+ # triggerTime: '1712645434',
2618
+ # status: 'ACTIVATED',
2619
+ # note: 'All your perpetual pending orders will be closed automatically at 2024-04-09 06:50:34 UTC(+0),before that you can cancel the timer, or self.extend triggerTime time by self request'
2620
+ # }
2621
+ # }
2622
+ #
2623
+ return response
2624
+
2585
2625
  async def fetch_order(self, id: str, symbol: Str = None, params={}):
2586
2626
  """
2587
2627
  fetches information on an order made by the user
@@ -48,6 +48,7 @@ class bitmex(Exchange, ImplicitAPI):
48
48
  'option': False,
49
49
  'addMargin': None,
50
50
  'cancelAllOrders': True,
51
+ 'cancelAllOrdersAfter': True,
51
52
  'cancelOrder': True,
52
53
  'cancelOrders': True,
53
54
  'closeAllPositions': False,
@@ -1979,6 +1980,27 @@ class bitmex(Exchange, ImplicitAPI):
1979
1980
  #
1980
1981
  return self.parse_orders(response, market)
1981
1982
 
1983
+ async def cancel_all_orders_after(self, timeout: Int, params={}):
1984
+ """
1985
+ dead man's switch, cancel all orders after the given timeout
1986
+ :see: https://www.bitmex.com/api/explorer/#not /Order/Order_cancelAllAfter
1987
+ :param number timeout: time in milliseconds, 0 represents cancel the timer
1988
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1989
+ :returns dict: the api result
1990
+ """
1991
+ await self.load_markets()
1992
+ request: dict = {
1993
+ 'timeout': self.parse_to_int(timeout / 1000) if (timeout > 0) else 0,
1994
+ }
1995
+ response = await self.privatePostOrderCancelAllAfter(self.extend(request, params))
1996
+ #
1997
+ # {
1998
+ # now: '2024-04-09T09:01:56.560Z',
1999
+ # cancelTime: '2024-04-09T09:01:56.660Z'
2000
+ # }
2001
+ #
2002
+ return response
2003
+
1982
2004
  async def fetch_leverages(self, symbols: List[str] = None, params={}) -> Leverages:
1983
2005
  """
1984
2006
  fetch the set leverage for all contract markets
@@ -7,7 +7,7 @@ from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.bybit import ImplicitAPI
8
8
  import asyncio
9
9
  import hashlib
10
- from ccxt.base.types import Balances, Currencies, Currency, Greeks, Int, Leverage, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, TradingFees, Transaction, TransferEntry
10
+ from ccxt.base.types import Balances, Currencies, Currency, Greeks, Int, Leverage, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, CancellationRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, TradingFees, Transaction, TransferEntry
11
11
  from typing import List
12
12
  from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import AuthenticationError
@@ -50,6 +50,8 @@ class bybit(Exchange, ImplicitAPI):
50
50
  'borrowCrossMargin': True,
51
51
  'cancelAllOrders': True,
52
52
  'cancelOrder': True,
53
+ 'cancelOrders': True,
54
+ 'cancelOrdersForSymbols': True,
53
55
  'closeAllPositions': False,
54
56
  'closePosition': False,
55
57
  'createMarketBuyOrderWithCost': True,
@@ -4089,6 +4091,84 @@ class bybit(Exchange, ImplicitAPI):
4089
4091
  row = self.safe_list(result, 'list', [])
4090
4092
  return self.parse_orders(row, market)
4091
4093
 
4094
+ async def cancel_orders_for_symbols(self, orders: List[CancellationRequest], params={}):
4095
+ """
4096
+ cancel multiple orders for multiple symbols
4097
+ :see: https://bybit-exchange.github.io/docs/v5/order/batch-cancel
4098
+ :param str[] ids: order ids
4099
+ :param str symbol: unified symbol of the market the order was made in
4100
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4101
+ :param str[] [params.clientOrderIds]: client order ids
4102
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
4103
+ """
4104
+ await self.load_markets()
4105
+ ordersRequests = []
4106
+ category = None
4107
+ for i in range(0, len(orders)):
4108
+ order = orders[i]
4109
+ symbol = self.safe_string(order, 'symbol')
4110
+ market = self.market(symbol)
4111
+ currentCategory = None
4112
+ currentCategory, params = self.get_bybit_type('cancelOrders', market, params)
4113
+ if currentCategory == 'inverse':
4114
+ raise NotSupported(self.id + ' cancelOrdersForSymbols does not allow inverse orders')
4115
+ if (category is not None) and (category != currentCategory):
4116
+ raise ExchangeError(self.id + ' cancelOrdersForSymbols requires all orders to be of the same category(linear, spot or option))')
4117
+ category = currentCategory
4118
+ id = self.safe_string(order, 'id')
4119
+ clientOrderId = self.safe_string(order, 'clientOrderId')
4120
+ idKey = 'orderId'
4121
+ if clientOrderId is not None:
4122
+ idKey = 'orderLinkId'
4123
+ orderItem = {
4124
+ 'symbol': market['id'],
4125
+ }
4126
+ orderItem[idKey] = id if (idKey == 'orderId') else clientOrderId
4127
+ ordersRequests.append(orderItem)
4128
+ request = {
4129
+ 'category': category,
4130
+ 'request': ordersRequests,
4131
+ }
4132
+ response = await self.privatePostV5OrderCancelBatch(self.extend(request, params))
4133
+ #
4134
+ # {
4135
+ # "retCode": "0",
4136
+ # "retMsg": "OK",
4137
+ # "result": {
4138
+ # "list": [
4139
+ # {
4140
+ # "category": "spot",
4141
+ # "symbol": "BTCUSDT",
4142
+ # "orderId": "1636282505818800896",
4143
+ # "orderLinkId": "1636282505818800897"
4144
+ # },
4145
+ # {
4146
+ # "category": "spot",
4147
+ # "symbol": "BTCUSDT",
4148
+ # "orderId": "1636282505818800898",
4149
+ # "orderLinkId": "1636282505818800899"
4150
+ # }
4151
+ # ]
4152
+ # },
4153
+ # "retExtInfo": {
4154
+ # "list": [
4155
+ # {
4156
+ # "code": "0",
4157
+ # "msg": "OK"
4158
+ # },
4159
+ # {
4160
+ # "code": "0",
4161
+ # "msg": "OK"
4162
+ # }
4163
+ # ]
4164
+ # },
4165
+ # "time": "1709796158501"
4166
+ # }
4167
+ #
4168
+ result = self.safe_dict(response, 'result', {})
4169
+ row = self.safe_list(result, 'list', [])
4170
+ return self.parse_orders(row, None)
4171
+
4092
4172
  async def cancel_all_usdc_orders(self, symbol: Str = None, params={}):
4093
4173
  if symbol is None:
4094
4174
  raise ArgumentsRequired(self.id + ' cancelAllUsdcOrders() requires a symbol argument')
@@ -3245,11 +3245,11 @@ class coinbase(Exchange, ImplicitAPI):
3245
3245
  now = str(self.seconds())
3246
3246
  sinceString = Precise.string_sub(now, str(requestedDuration))
3247
3247
  request['start'] = sinceString
3248
- endString = self.number_to_string(until)
3249
- if until is None:
3248
+ if until is not None:
3249
+ request['end'] = self.number_to_string(self.parse_to_int(until / 1000))
3250
+ else:
3250
3251
  # 300 candles max
3251
- endString = Precise.string_add(sinceString, str(requestedDuration))
3252
- request['end'] = endString
3252
+ request['end'] = Precise.string_add(sinceString, str(requestedDuration))
3253
3253
  response = await self.v3PrivateGetBrokerageProductsProductIdCandles(self.extend(request, params))
3254
3254
  #
3255
3255
  # {
@@ -1116,14 +1116,13 @@ class coinex(Exchange, ImplicitAPI):
1116
1116
  #
1117
1117
  # Spot and Swap fetchTrades(public)
1118
1118
  #
1119
- # {
1120
- # "id": 2611511379,
1121
- # "type": "buy",
1122
- # "price": "192.63",
1123
- # "amount": "0.02266931",
1124
- # "date": 1638990110,
1125
- # "date_ms": 1638990110518
1126
- # },
1119
+ # {
1120
+ # "amount": "0.00049432",
1121
+ # "created_at": 1713849825667,
1122
+ # "deal_id": 4137517302,
1123
+ # "price": "66251",
1124
+ # "side": "buy"
1125
+ # }
1127
1126
  #
1128
1127
  # Spot and Margin fetchMyTrades(private)
1129
1128
  #
@@ -1177,8 +1176,8 @@ class coinex(Exchange, ImplicitAPI):
1177
1176
  #
1178
1177
  timestamp = self.safe_timestamp_2(trade, 'create_time', 'time')
1179
1178
  if timestamp is None:
1180
- timestamp = self.safe_integer(trade, 'date_ms')
1181
- tradeId = self.safe_string(trade, 'id')
1179
+ timestamp = self.safe_integer(trade, 'created_at')
1180
+ tradeId = self.safe_string_2(trade, 'id', 'deal_id')
1182
1181
  orderId = self.safe_string(trade, 'order_id')
1183
1182
  priceString = self.safe_string(trade, 'price')
1184
1183
  amountString = self.safe_string(trade, 'amount')
@@ -1210,9 +1209,9 @@ class coinex(Exchange, ImplicitAPI):
1210
1209
  elif rawSide == 2:
1211
1210
  side = 'buy'
1212
1211
  if side is None:
1213
- side = self.safe_string(trade, 'type')
1212
+ side = self.safe_string_2(trade, 'type', 'side')
1214
1213
  else:
1215
- side = self.safe_string(trade, 'type')
1214
+ side = self.safe_string_2(trade, 'type', 'side')
1216
1215
  return self.safe_trade({
1217
1216
  'info': trade,
1218
1217
  'timestamp': timestamp,
@@ -1231,9 +1230,9 @@ class coinex(Exchange, ImplicitAPI):
1231
1230
 
1232
1231
  async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1233
1232
  """
1234
- get the list of most recent trades for a particular symbol
1235
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot001_market005_market_deals
1236
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http011_market_deals
1233
+ get the list of the most recent trades for a particular symbol
1234
+ :see: https://docs.coinex.com/api/v2/spot/market/http/list-market-deals
1235
+ :see: https://docs.coinex.com/api/v2/futures/market/http/list-market-deals
1237
1236
  :param str symbol: unified symbol of the market to fetch trades for
1238
1237
  :param int [since]: timestamp in ms of the earliest trade to fetch
1239
1238
  :param int [limit]: the maximum amount of trades to fetch
@@ -1250,26 +1249,25 @@ class coinex(Exchange, ImplicitAPI):
1250
1249
  request['limit'] = limit
1251
1250
  response = None
1252
1251
  if market['swap']:
1253
- response = await self.v1PerpetualPublicGetMarketDeals(self.extend(request, params))
1252
+ response = await self.v2PublicGetFuturesDeals(self.extend(request, params))
1254
1253
  else:
1255
- response = await self.v1PublicGetMarketDeals(self.extend(request, params))
1254
+ response = await self.v2PublicGetSpotDeals(self.extend(request, params))
1256
1255
  #
1257
1256
  # Spot and Swap
1258
1257
  #
1259
- # {
1260
- # "code": 0,
1261
- # "data": [
1262
- # {
1263
- # "id": 2611511379,
1264
- # "type": "buy",
1265
- # "price": "192.63",
1266
- # "amount": "0.02266931",
1267
- # "date": 1638990110,
1268
- # "date_ms": 1638990110518
1269
- # },
1270
- # ],
1271
- # "message": "OK"
1272
- # }
1258
+ # {
1259
+ # "code": 0,
1260
+ # "data": [
1261
+ # {
1262
+ # "amount": "0.00049432",
1263
+ # "created_at": 1713849825667,
1264
+ # "deal_id": 4137517302,
1265
+ # "price": "66251",
1266
+ # "side": "buy"
1267
+ # },
1268
+ # ],
1269
+ # "message": "OK"
1270
+ # }
1273
1271
  #
1274
1272
  return self.parse_trades(response['data'], market, since, limit)
1275
1273
 
@@ -4205,7 +4203,6 @@ class coinex(Exchange, ImplicitAPI):
4205
4203
 
4206
4204
  async def fetch_funding_rates(self, symbols: Strings = None, params={}):
4207
4205
  """
4208
- * @method
4209
4206
  fetch the current funding rates
4210
4207
  :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http009_market_ticker_all
4211
4208
  :param str[] symbols: unified market symbols
@@ -6,7 +6,7 @@
6
6
  from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.cryptocom import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Account, Balances, Currency, Int, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
9
+ from ccxt.base.types import Account, Balances, Currency, Int, Market, Num, Order, OrderBook, OrderRequest, CancellationRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import AuthenticationError
@@ -47,6 +47,7 @@ class cryptocom(Exchange, ImplicitAPI):
47
47
  'cancelAllOrders': True,
48
48
  'cancelOrder': True,
49
49
  'cancelOrders': True,
50
+ 'cancelOrdersForSymbols': True,
50
51
  'closeAllPositions': False,
51
52
  'closePosition': True,
52
53
  'createMarketBuyOrderWithCost': False,
@@ -1353,6 +1354,34 @@ class cryptocom(Exchange, ImplicitAPI):
1353
1354
  result = self.safe_list(response, 'result', [])
1354
1355
  return self.parse_orders(result, market, None, None, params)
1355
1356
 
1357
+ async def cancel_orders_for_symbols(self, orders: List[CancellationRequest], params={}):
1358
+ """
1359
+ cancel multiple orders for multiple symbols
1360
+ :see: https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#private-cancel-order-list-list
1361
+ :param CancellationRequest[] orders: each order should contain the parameters required by cancelOrder namely id and symbol
1362
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1363
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1364
+ """
1365
+ await self.load_markets()
1366
+ orderRequests = []
1367
+ for i in range(0, len(orders)):
1368
+ order = orders[i]
1369
+ id = self.safe_string(order, 'id')
1370
+ symbol = self.safe_string(order, 'symbol')
1371
+ market = self.market(symbol)
1372
+ orderItem = {
1373
+ 'instrument_name': market['id'],
1374
+ 'order_id': str(id),
1375
+ }
1376
+ orderRequests.append(orderItem)
1377
+ request = {
1378
+ 'contingency_type': 'LIST',
1379
+ 'order_list': orderRequests,
1380
+ }
1381
+ response = await self.v1PrivatePostPrivateCancelOrderList(self.extend(request, params))
1382
+ result = self.safe_list(response, 'result', [])
1383
+ return self.parse_orders(result, None, None, None, params)
1384
+
1356
1385
  async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1357
1386
  """
1358
1387
  fetch all unfilled currently open orders
ccxt/async_support/htx.py CHANGED
@@ -54,6 +54,7 @@ class htx(Exchange, ImplicitAPI):
54
54
  'borrowCrossMargin': True,
55
55
  'borrowIsolatedMargin': True,
56
56
  'cancelAllOrders': True,
57
+ 'cancelAllOrdersAfter': True,
57
58
  'cancelOrder': True,
58
59
  'cancelOrders': True,
59
60
  'createDepositAddress': None,
@@ -5629,6 +5630,31 @@ class htx(Exchange, ImplicitAPI):
5629
5630
  #
5630
5631
  return response
5631
5632
 
5633
+ async def cancel_all_orders_after(self, timeout: Int, params={}):
5634
+ """
5635
+ dead man's switch, cancel all orders after the given timeout
5636
+ :see: https://huobiapi.github.io/docs/spot/v1/en/#dead-man-s-switch
5637
+ :param number timeout: time in milliseconds, 0 represents cancel the timer
5638
+ :param dict [params]: extra parameters specific to the exchange API endpoint
5639
+ :returns dict: the api result
5640
+ """
5641
+ await self.load_markets()
5642
+ request: dict = {
5643
+ 'timeout': self.parse_to_int(timeout / 1000) if (timeout > 0) else 0,
5644
+ }
5645
+ response = await self.v2PrivatePostAlgoOrdersCancelAllAfter(self.extend(request, params))
5646
+ #
5647
+ # {
5648
+ # "code": 200,
5649
+ # "message": "success",
5650
+ # "data": {
5651
+ # "currentTime": 1630491627230,
5652
+ # "triggerTime": 1630491637230
5653
+ # }
5654
+ # }
5655
+ #
5656
+ return response
5657
+
5632
5658
  def parse_deposit_address(self, depositAddress, currency: Currency = None):
5633
5659
  #
5634
5660
  # {
@@ -43,6 +43,7 @@ class hyperliquid(Exchange, ImplicitAPI):
43
43
  'borrowCrossMargin': False,
44
44
  'borrowIsolatedMargin': False,
45
45
  'cancelAllOrders': False,
46
+ 'cancelAllOrdersAfter': True,
46
47
  'cancelOrder': True,
47
48
  'cancelOrders': True,
48
49
  'cancelOrdersForSymbols': True,
@@ -1303,6 +1304,42 @@ class hyperliquid(Exchange, ImplicitAPI):
1303
1304
  #
1304
1305
  return response
1305
1306
 
1307
+ async def cancel_all_orders_after(self, timeout: Int, params={}):
1308
+ """
1309
+ dead man's switch, cancel all orders after the given timeout
1310
+ :param number timeout: time in milliseconds, 0 represents cancel the timer
1311
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1312
+ :param str [params.vaultAddress]: the vault address
1313
+ :returns dict: the api result
1314
+ """
1315
+ self.check_required_credentials()
1316
+ await self.load_markets()
1317
+ params = self.omit(params, ['clientOrderId', 'client_id'])
1318
+ nonce = self.milliseconds()
1319
+ request = {
1320
+ 'nonce': nonce,
1321
+ # 'vaultAddress': vaultAddress,
1322
+ }
1323
+ cancelAction = {
1324
+ 'type': 'scheduleCancel',
1325
+ 'time': nonce + timeout,
1326
+ }
1327
+ vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
1328
+ signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
1329
+ request['action'] = cancelAction
1330
+ request['signature'] = signature
1331
+ if vaultAddress is not None:
1332
+ params = self.omit(params, 'vaultAddress')
1333
+ request['vaultAddress'] = vaultAddress
1334
+ response = await self.privatePostExchange(self.extend(request, params))
1335
+ #
1336
+ # {
1337
+ # "status":"err",
1338
+ # "response":"Cannot set scheduled cancel time until enough volume traded. Required: $1000000. Traded: $373.47205."
1339
+ # }
1340
+ #
1341
+ return response
1342
+
1306
1343
  async def edit_order(self, id: str, symbol: str, type: str, side: str, amount: Num = None, price: Num = None, params={}):
1307
1344
  """
1308
1345
  edit a trade order
@@ -54,6 +54,7 @@ class kraken(Exchange, ImplicitAPI):
54
54
  'option': False,
55
55
  'addMargin': False,
56
56
  'cancelAllOrders': True,
57
+ 'cancelAllOrdersAfter': True,
57
58
  'cancelOrder': True,
58
59
  'cancelOrders': True,
59
60
  'createDepositAddress': True,
@@ -2006,6 +2007,32 @@ class kraken(Exchange, ImplicitAPI):
2006
2007
  await self.load_markets()
2007
2008
  return await self.privatePostCancelAll(params)
2008
2009
 
2010
+ async def cancel_all_orders_after(self, timeout: Int, params={}):
2011
+ """
2012
+ dead man's switch, cancel all orders after the given timeout
2013
+ :see: https://docs.kraken.com/rest/#tag/Spot-Trading/operation/cancelAllOrdersAfter
2014
+ :param number timeout: time in milliseconds, 0 represents cancel the timer
2015
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2016
+ :returns dict: the api result
2017
+ """
2018
+ if timeout > 86400000:
2019
+ raise BadRequest(self.id + 'cancelAllOrdersAfter timeout should be less than 86400000 milliseconds')
2020
+ await self.load_markets()
2021
+ request: dict = {
2022
+ 'timeout': (self.parse_to_int(timeout / 1000)) if (timeout > 0) else 0,
2023
+ }
2024
+ response = await self.privatePostCancelAllOrdersAfter(self.extend(request, params))
2025
+ #
2026
+ # {
2027
+ # "error": [],
2028
+ # "result": {
2029
+ # "currentTime": "2023-03-24T17:41:56Z",
2030
+ # "triggerTime": "2023-03-24T17:42:56Z"
2031
+ # }
2032
+ # }
2033
+ #
2034
+ return response
2035
+
2009
2036
  async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2010
2037
  """
2011
2038
  fetch all unfilled currently open orders
@@ -46,6 +46,7 @@ class krakenfutures(Exchange, ImplicitAPI):
46
46
  'future': True,
47
47
  'option': False,
48
48
  'cancelAllOrders': True,
49
+ 'cancelAllOrdersAfter': True,
49
50
  'cancelOrder': True,
50
51
  'cancelOrders': True,
51
52
  'createMarketOrder': False,
@@ -1207,6 +1208,31 @@ class krakenfutures(Exchange, ImplicitAPI):
1207
1208
  response = await self.privatePostCancelallorders(self.extend(request, params))
1208
1209
  return response
1209
1210
 
1211
+ async def cancel_all_orders_after(self, timeout: Int, params={}):
1212
+ """
1213
+ dead man's switch, cancel all orders after the given timeout
1214
+ :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-order-management-dead-man-39-s-switch
1215
+ :param number timeout: time in milliseconds, 0 represents cancel the timer
1216
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1217
+ :returns dict: the api result
1218
+ """
1219
+ await self.load_markets()
1220
+ request: dict = {
1221
+ 'timeout': (self.parse_to_int(timeout / 1000)) if (timeout > 0) else 0,
1222
+ }
1223
+ response = await self.privatePostCancelallordersafter(self.extend(request, params))
1224
+ #
1225
+ # {
1226
+ # "result": "success",
1227
+ # "serverTime": "2018-06-19T16:51:23.839Z",
1228
+ # "status": {
1229
+ # "currentTime": "2018-06-19T16:51:23.839Z",
1230
+ # "triggerTime": "0"
1231
+ # }
1232
+ # }
1233
+ #
1234
+ return response
1235
+
1210
1236
  async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1211
1237
  """
1212
1238
  :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-order-management-get-open-orders
@@ -534,7 +534,7 @@ class kucoin(Exchange, ImplicitAPI):
534
534
  '400006': AuthenticationError,
535
535
  '400007': AuthenticationError,
536
536
  '400008': NotSupported,
537
- '400100': InsufficientFunds, # {"msg":"account.available.amount","code":"400100"}
537
+ '400100': InsufficientFunds, # {"msg":"account.available.amount","code":"400100"} or {"msg":"Withdrawal amount is below the minimum requirement.","code":"400100"}
538
538
  '400200': InvalidOrder, # {"code":"400200","msg":"Forbidden to place an order"}
539
539
  '400350': InvalidOrder, # {"code":"400350","msg":"Upper limit for holding: 10,000USDT, you can still buy 10,000USDT worth of coin."}
540
540
  '400370': InvalidOrder, # {"code":"400370","msg":"Max. price: 0.02500000000000000000"}
@@ -1159,8 +1159,10 @@ class kucoin(Exchange, ImplicitAPI):
1159
1159
  # "chains":[
1160
1160
  # {
1161
1161
  # "chainName":"ERC20",
1162
- # "chain":"eth",
1162
+ # "chainId": "eth"
1163
1163
  # "withdrawalMinSize":"2999",
1164
+ # "depositMinSize":null,
1165
+ # "withdrawFeeRate":"0",
1164
1166
  # "withdrawalMinFee":"2999",
1165
1167
  # "isWithdrawEnabled":false,
1166
1168
  # "isDepositEnabled":false,
@@ -1263,7 +1265,7 @@ class kucoin(Exchange, ImplicitAPI):
1263
1265
  'max': None,
1264
1266
  },
1265
1267
  'deposit': {
1266
- 'min': self.safe_number(chainExtraData, 'depositMinSize'),
1268
+ 'min': self.safe_number(chain, 'depositMinSize'),
1267
1269
  'max': None,
1268
1270
  },
1269
1271
  },
@@ -3020,7 +3022,6 @@ class kucoin(Exchange, ImplicitAPI):
3020
3022
  request = {
3021
3023
  'currency': currency['id'],
3022
3024
  'address': address,
3023
- 'amount': amount,
3024
3025
  # 'memo': tag,
3025
3026
  # 'isInner': False, # internal transfer or external withdrawal
3026
3027
  # 'remark': 'optional',
@@ -3032,6 +3033,8 @@ class kucoin(Exchange, ImplicitAPI):
3032
3033
  networkCode, params = self.handle_network_code_and_params(params)
3033
3034
  if networkCode is not None:
3034
3035
  request['chain'] = self.network_code_to_id(networkCode).lower()
3036
+ await self.load_currency_precision(currency, networkCode)
3037
+ request['amount'] = self.currency_to_precision(code, amount, networkCode)
3035
3038
  includeFee = None
3036
3039
  includeFee, params = self.handle_option_and_params(params, 'withdraw', 'includeFee', False)
3037
3040
  if includeFee:
@@ -3050,6 +3053,51 @@ class kucoin(Exchange, ImplicitAPI):
3050
3053
  data = self.safe_dict(response, 'data', {})
3051
3054
  return self.parse_transaction(data, currency)
3052
3055
 
3056
+ async def load_currency_precision(self, currency, networkCode: Str = None):
3057
+ # might not have network specific precisions defined in fetchCurrencies(because of webapi failure)
3058
+ # we should check and refetch precision once-per-instance for that specific currency & network
3059
+ # so avoids thorwing exceptions and burden to users
3060
+ # Note: self needs to be executed only if networkCode was provided
3061
+ if networkCode is not None:
3062
+ networks = currency['networks']
3063
+ network = self.safe_dict(networks, networkCode)
3064
+ if self.safe_number(network, 'precision') is not None:
3065
+ # if precision exists, no need to refetch
3066
+ return
3067
+ # otherwise try to fetch and store in instance
3068
+ request = {
3069
+ 'currency': currency['id'],
3070
+ 'chain': self.network_code_to_id(networkCode).lower(),
3071
+ }
3072
+ response = await self.privateGetWithdrawalsQuotas(request)
3073
+ #
3074
+ # {
3075
+ # "code": "200000",
3076
+ # "data": {
3077
+ # "currency": "USDT",
3078
+ # "limitBTCAmount": "14.24094850",
3079
+ # "usedBTCAmount": "0.00000000",
3080
+ # "quotaCurrency": "USDT",
3081
+ # "limitQuotaCurrencyAmount": "999999.00000000",
3082
+ # "usedQuotaCurrencyAmount": "0",
3083
+ # "remainAmount": "999999.0000",
3084
+ # "availableAmount": "10.77545071",
3085
+ # "withdrawMinFee": "1",
3086
+ # "innerWithdrawMinFee": "0",
3087
+ # "withdrawMinSize": "10",
3088
+ # "isWithdrawEnabled": True,
3089
+ # "precision": 4,
3090
+ # "chain": "EOS",
3091
+ # "reason": null,
3092
+ # "lockedAmount": "0"
3093
+ # }
3094
+ # }
3095
+ #
3096
+ data = self.safe_dict(response, 'data', {})
3097
+ precision = self.parse_number(self.parse_precision(self.safe_string(data, 'precision')))
3098
+ code = currency['code']
3099
+ self.currencies[code]['networks'][networkCode]['precision'] = precision
3100
+
3053
3101
  def parse_transaction_status(self, status):
3054
3102
  statuses = {
3055
3103
  'SUCCESS': 'ok',