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
ccxt/coinbase.py CHANGED
@@ -3244,11 +3244,11 @@ class coinbase(Exchange, ImplicitAPI):
3244
3244
  now = str(self.seconds())
3245
3245
  sinceString = Precise.string_sub(now, str(requestedDuration))
3246
3246
  request['start'] = sinceString
3247
- endString = self.number_to_string(until)
3248
- if until is None:
3247
+ if until is not None:
3248
+ request['end'] = self.number_to_string(self.parse_to_int(until / 1000))
3249
+ else:
3249
3250
  # 300 candles max
3250
- endString = Precise.string_add(sinceString, str(requestedDuration))
3251
- request['end'] = endString
3251
+ request['end'] = Precise.string_add(sinceString, str(requestedDuration))
3252
3252
  response = self.v3PrivateGetBrokerageProductsProductIdCandles(self.extend(request, params))
3253
3253
  #
3254
3254
  # {
ccxt/coinex.py CHANGED
@@ -1115,14 +1115,13 @@ class coinex(Exchange, ImplicitAPI):
1115
1115
  #
1116
1116
  # Spot and Swap fetchTrades(public)
1117
1117
  #
1118
- # {
1119
- # "id": 2611511379,
1120
- # "type": "buy",
1121
- # "price": "192.63",
1122
- # "amount": "0.02266931",
1123
- # "date": 1638990110,
1124
- # "date_ms": 1638990110518
1125
- # },
1118
+ # {
1119
+ # "amount": "0.00049432",
1120
+ # "created_at": 1713849825667,
1121
+ # "deal_id": 4137517302,
1122
+ # "price": "66251",
1123
+ # "side": "buy"
1124
+ # }
1126
1125
  #
1127
1126
  # Spot and Margin fetchMyTrades(private)
1128
1127
  #
@@ -1176,8 +1175,8 @@ class coinex(Exchange, ImplicitAPI):
1176
1175
  #
1177
1176
  timestamp = self.safe_timestamp_2(trade, 'create_time', 'time')
1178
1177
  if timestamp is None:
1179
- timestamp = self.safe_integer(trade, 'date_ms')
1180
- tradeId = self.safe_string(trade, 'id')
1178
+ timestamp = self.safe_integer(trade, 'created_at')
1179
+ tradeId = self.safe_string_2(trade, 'id', 'deal_id')
1181
1180
  orderId = self.safe_string(trade, 'order_id')
1182
1181
  priceString = self.safe_string(trade, 'price')
1183
1182
  amountString = self.safe_string(trade, 'amount')
@@ -1209,9 +1208,9 @@ class coinex(Exchange, ImplicitAPI):
1209
1208
  elif rawSide == 2:
1210
1209
  side = 'buy'
1211
1210
  if side is None:
1212
- side = self.safe_string(trade, 'type')
1211
+ side = self.safe_string_2(trade, 'type', 'side')
1213
1212
  else:
1214
- side = self.safe_string(trade, 'type')
1213
+ side = self.safe_string_2(trade, 'type', 'side')
1215
1214
  return self.safe_trade({
1216
1215
  'info': trade,
1217
1216
  'timestamp': timestamp,
@@ -1230,9 +1229,9 @@ class coinex(Exchange, ImplicitAPI):
1230
1229
 
1231
1230
  def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1232
1231
  """
1233
- get the list of most recent trades for a particular symbol
1234
- :see: https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot001_market005_market_deals
1235
- :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http011_market_deals
1232
+ get the list of the most recent trades for a particular symbol
1233
+ :see: https://docs.coinex.com/api/v2/spot/market/http/list-market-deals
1234
+ :see: https://docs.coinex.com/api/v2/futures/market/http/list-market-deals
1236
1235
  :param str symbol: unified symbol of the market to fetch trades for
1237
1236
  :param int [since]: timestamp in ms of the earliest trade to fetch
1238
1237
  :param int [limit]: the maximum amount of trades to fetch
@@ -1249,26 +1248,25 @@ class coinex(Exchange, ImplicitAPI):
1249
1248
  request['limit'] = limit
1250
1249
  response = None
1251
1250
  if market['swap']:
1252
- response = self.v1PerpetualPublicGetMarketDeals(self.extend(request, params))
1251
+ response = self.v2PublicGetFuturesDeals(self.extend(request, params))
1253
1252
  else:
1254
- response = self.v1PublicGetMarketDeals(self.extend(request, params))
1253
+ response = self.v2PublicGetSpotDeals(self.extend(request, params))
1255
1254
  #
1256
1255
  # Spot and Swap
1257
1256
  #
1258
- # {
1259
- # "code": 0,
1260
- # "data": [
1261
- # {
1262
- # "id": 2611511379,
1263
- # "type": "buy",
1264
- # "price": "192.63",
1265
- # "amount": "0.02266931",
1266
- # "date": 1638990110,
1267
- # "date_ms": 1638990110518
1268
- # },
1269
- # ],
1270
- # "message": "OK"
1271
- # }
1257
+ # {
1258
+ # "code": 0,
1259
+ # "data": [
1260
+ # {
1261
+ # "amount": "0.00049432",
1262
+ # "created_at": 1713849825667,
1263
+ # "deal_id": 4137517302,
1264
+ # "price": "66251",
1265
+ # "side": "buy"
1266
+ # },
1267
+ # ],
1268
+ # "message": "OK"
1269
+ # }
1272
1270
  #
1273
1271
  return self.parse_trades(response['data'], market, since, limit)
1274
1272
 
@@ -4204,7 +4202,6 @@ class coinex(Exchange, ImplicitAPI):
4204
4202
 
4205
4203
  def fetch_funding_rates(self, symbols: Strings = None, params={}):
4206
4204
  """
4207
- * @method
4208
4205
  fetch the current funding rates
4209
4206
  :see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http009_market_ticker_all
4210
4207
  :param str[] symbols: unified market symbols
ccxt/cryptocom.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.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
+ 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
+ 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 = 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
  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/htx.py CHANGED
@@ -53,6 +53,7 @@ class htx(Exchange, ImplicitAPI):
53
53
  'borrowCrossMargin': True,
54
54
  'borrowIsolatedMargin': True,
55
55
  'cancelAllOrders': True,
56
+ 'cancelAllOrdersAfter': True,
56
57
  'cancelOrder': True,
57
58
  'cancelOrders': True,
58
59
  'createDepositAddress': None,
@@ -5628,6 +5629,31 @@ class htx(Exchange, ImplicitAPI):
5628
5629
  #
5629
5630
  return response
5630
5631
 
5632
+ def cancel_all_orders_after(self, timeout: Int, params={}):
5633
+ """
5634
+ dead man's switch, cancel all orders after the given timeout
5635
+ :see: https://huobiapi.github.io/docs/spot/v1/en/#dead-man-s-switch
5636
+ :param number timeout: time in milliseconds, 0 represents cancel the timer
5637
+ :param dict [params]: extra parameters specific to the exchange API endpoint
5638
+ :returns dict: the api result
5639
+ """
5640
+ self.load_markets()
5641
+ request: dict = {
5642
+ 'timeout': self.parse_to_int(timeout / 1000) if (timeout > 0) else 0,
5643
+ }
5644
+ response = self.v2PrivatePostAlgoOrdersCancelAllAfter(self.extend(request, params))
5645
+ #
5646
+ # {
5647
+ # "code": 200,
5648
+ # "message": "success",
5649
+ # "data": {
5650
+ # "currentTime": 1630491627230,
5651
+ # "triggerTime": 1630491637230
5652
+ # }
5653
+ # }
5654
+ #
5655
+ return response
5656
+
5631
5657
  def parse_deposit_address(self, depositAddress, currency: Currency = None):
5632
5658
  #
5633
5659
  # {
ccxt/hyperliquid.py CHANGED
@@ -42,6 +42,7 @@ class hyperliquid(Exchange, ImplicitAPI):
42
42
  'borrowCrossMargin': False,
43
43
  'borrowIsolatedMargin': False,
44
44
  'cancelAllOrders': False,
45
+ 'cancelAllOrdersAfter': True,
45
46
  'cancelOrder': True,
46
47
  'cancelOrders': True,
47
48
  'cancelOrdersForSymbols': True,
@@ -1302,6 +1303,42 @@ class hyperliquid(Exchange, ImplicitAPI):
1302
1303
  #
1303
1304
  return response
1304
1305
 
1306
+ def cancel_all_orders_after(self, timeout: Int, params={}):
1307
+ """
1308
+ dead man's switch, cancel all orders after the given timeout
1309
+ :param number timeout: time in milliseconds, 0 represents cancel the timer
1310
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1311
+ :param str [params.vaultAddress]: the vault address
1312
+ :returns dict: the api result
1313
+ """
1314
+ self.check_required_credentials()
1315
+ self.load_markets()
1316
+ params = self.omit(params, ['clientOrderId', 'client_id'])
1317
+ nonce = self.milliseconds()
1318
+ request = {
1319
+ 'nonce': nonce,
1320
+ # 'vaultAddress': vaultAddress,
1321
+ }
1322
+ cancelAction = {
1323
+ 'type': 'scheduleCancel',
1324
+ 'time': nonce + timeout,
1325
+ }
1326
+ vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
1327
+ signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
1328
+ request['action'] = cancelAction
1329
+ request['signature'] = signature
1330
+ if vaultAddress is not None:
1331
+ params = self.omit(params, 'vaultAddress')
1332
+ request['vaultAddress'] = vaultAddress
1333
+ response = self.privatePostExchange(self.extend(request, params))
1334
+ #
1335
+ # {
1336
+ # "status":"err",
1337
+ # "response":"Cannot set scheduled cancel time until enough volume traded. Required: $1000000. Traded: $373.47205."
1338
+ # }
1339
+ #
1340
+ return response
1341
+
1305
1342
  def edit_order(self, id: str, symbol: str, type: str, side: str, amount: Num = None, price: Num = None, params={}):
1306
1343
  """
1307
1344
  edit a trade order
ccxt/kraken.py CHANGED
@@ -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
  self.load_markets()
2007
2008
  return self.privatePostCancelAll(params)
2008
2009
 
2010
+ 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
+ self.load_markets()
2021
+ request: dict = {
2022
+ 'timeout': (self.parse_to_int(timeout / 1000)) if (timeout > 0) else 0,
2023
+ }
2024
+ response = 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
  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
ccxt/krakenfutures.py CHANGED
@@ -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 = self.privatePostCancelallorders(self.extend(request, params))
1208
1209
  return response
1209
1210
 
1211
+ 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
+ self.load_markets()
1220
+ request: dict = {
1221
+ 'timeout': (self.parse_to_int(timeout / 1000)) if (timeout > 0) else 0,
1222
+ }
1223
+ response = 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
  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
ccxt/kucoin.py CHANGED
@@ -533,7 +533,7 @@ class kucoin(Exchange, ImplicitAPI):
533
533
  '400006': AuthenticationError,
534
534
  '400007': AuthenticationError,
535
535
  '400008': NotSupported,
536
- '400100': InsufficientFunds, # {"msg":"account.available.amount","code":"400100"}
536
+ '400100': InsufficientFunds, # {"msg":"account.available.amount","code":"400100"} or {"msg":"Withdrawal amount is below the minimum requirement.","code":"400100"}
537
537
  '400200': InvalidOrder, # {"code":"400200","msg":"Forbidden to place an order"}
538
538
  '400350': InvalidOrder, # {"code":"400350","msg":"Upper limit for holding: 10,000USDT, you can still buy 10,000USDT worth of coin."}
539
539
  '400370': InvalidOrder, # {"code":"400370","msg":"Max. price: 0.02500000000000000000"}
@@ -1158,8 +1158,10 @@ class kucoin(Exchange, ImplicitAPI):
1158
1158
  # "chains":[
1159
1159
  # {
1160
1160
  # "chainName":"ERC20",
1161
- # "chain":"eth",
1161
+ # "chainId": "eth"
1162
1162
  # "withdrawalMinSize":"2999",
1163
+ # "depositMinSize":null,
1164
+ # "withdrawFeeRate":"0",
1163
1165
  # "withdrawalMinFee":"2999",
1164
1166
  # "isWithdrawEnabled":false,
1165
1167
  # "isDepositEnabled":false,
@@ -1262,7 +1264,7 @@ class kucoin(Exchange, ImplicitAPI):
1262
1264
  'max': None,
1263
1265
  },
1264
1266
  'deposit': {
1265
- 'min': self.safe_number(chainExtraData, 'depositMinSize'),
1267
+ 'min': self.safe_number(chain, 'depositMinSize'),
1266
1268
  'max': None,
1267
1269
  },
1268
1270
  },
@@ -3019,7 +3021,6 @@ class kucoin(Exchange, ImplicitAPI):
3019
3021
  request = {
3020
3022
  'currency': currency['id'],
3021
3023
  'address': address,
3022
- 'amount': amount,
3023
3024
  # 'memo': tag,
3024
3025
  # 'isInner': False, # internal transfer or external withdrawal
3025
3026
  # 'remark': 'optional',
@@ -3031,6 +3032,8 @@ class kucoin(Exchange, ImplicitAPI):
3031
3032
  networkCode, params = self.handle_network_code_and_params(params)
3032
3033
  if networkCode is not None:
3033
3034
  request['chain'] = self.network_code_to_id(networkCode).lower()
3035
+ self.load_currency_precision(currency, networkCode)
3036
+ request['amount'] = self.currency_to_precision(code, amount, networkCode)
3034
3037
  includeFee = None
3035
3038
  includeFee, params = self.handle_option_and_params(params, 'withdraw', 'includeFee', False)
3036
3039
  if includeFee:
@@ -3049,6 +3052,51 @@ class kucoin(Exchange, ImplicitAPI):
3049
3052
  data = self.safe_dict(response, 'data', {})
3050
3053
  return self.parse_transaction(data, currency)
3051
3054
 
3055
+ def load_currency_precision(self, currency, networkCode: Str = None):
3056
+ # might not have network specific precisions defined in fetchCurrencies(because of webapi failure)
3057
+ # we should check and refetch precision once-per-instance for that specific currency & network
3058
+ # so avoids thorwing exceptions and burden to users
3059
+ # Note: self needs to be executed only if networkCode was provided
3060
+ if networkCode is not None:
3061
+ networks = currency['networks']
3062
+ network = self.safe_dict(networks, networkCode)
3063
+ if self.safe_number(network, 'precision') is not None:
3064
+ # if precision exists, no need to refetch
3065
+ return
3066
+ # otherwise try to fetch and store in instance
3067
+ request = {
3068
+ 'currency': currency['id'],
3069
+ 'chain': self.network_code_to_id(networkCode).lower(),
3070
+ }
3071
+ response = self.privateGetWithdrawalsQuotas(request)
3072
+ #
3073
+ # {
3074
+ # "code": "200000",
3075
+ # "data": {
3076
+ # "currency": "USDT",
3077
+ # "limitBTCAmount": "14.24094850",
3078
+ # "usedBTCAmount": "0.00000000",
3079
+ # "quotaCurrency": "USDT",
3080
+ # "limitQuotaCurrencyAmount": "999999.00000000",
3081
+ # "usedQuotaCurrencyAmount": "0",
3082
+ # "remainAmount": "999999.0000",
3083
+ # "availableAmount": "10.77545071",
3084
+ # "withdrawMinFee": "1",
3085
+ # "innerWithdrawMinFee": "0",
3086
+ # "withdrawMinSize": "10",
3087
+ # "isWithdrawEnabled": True,
3088
+ # "precision": 4,
3089
+ # "chain": "EOS",
3090
+ # "reason": null,
3091
+ # "lockedAmount": "0"
3092
+ # }
3093
+ # }
3094
+ #
3095
+ data = self.safe_dict(response, 'data', {})
3096
+ precision = self.parse_number(self.parse_precision(self.safe_string(data, 'precision')))
3097
+ code = currency['code']
3098
+ self.currencies[code]['networks'][networkCode]['precision'] = precision
3099
+
3052
3100
  def parse_transaction_status(self, status):
3053
3101
  statuses = {
3054
3102
  'SUCCESS': 'ok',
ccxt/kucoinfutures.py CHANGED
@@ -2093,8 +2093,8 @@ class kucoinfutures(kucoin, ImplicitAPI):
2093
2093
  # symbol(str) [optional] Symbol of the contract
2094
2094
  # side(str) [optional] buy or sell
2095
2095
  # type(str) [optional] limit, market, limit_stop or market_stop
2096
- # startAt(long) [optional] Start time(milisecond)
2097
- # endAt(long) [optional] End time(milisecond)
2096
+ # startAt(long) [optional] Start time(millisecond)
2097
+ # endAt(long) [optional] End time(millisecond)
2098
2098
  }
2099
2099
  market = None
2100
2100
  if symbol is not None:
ccxt/okx.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.okx import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Account, Balances, Conversion, Currencies, Currency, Greeks, Int, Leverage, MarginModification, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry
9
+ from ccxt.base.types import Account, Balances, Conversion, Currencies, Currency, Greeks, Int, Leverage, MarginModification, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, CancellationRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry
10
10
  from typing import List
11
11
  from typing import Any
12
12
  from ccxt.base.errors import ExchangeError
@@ -54,8 +54,10 @@ class okx(Exchange, ImplicitAPI):
54
54
  'option': True,
55
55
  'addMargin': True,
56
56
  'cancelAllOrders': False,
57
+ 'cancelAllOrdersAfter': True,
57
58
  'cancelOrder': True,
58
59
  'cancelOrders': True,
60
+ 'cancelOrdersForSymbols': True,
59
61
  'closeAllPositions': False,
60
62
  'closePosition': True,
61
63
  'createConvertTrade': True,
@@ -3083,6 +3085,107 @@ class okx(Exchange, ImplicitAPI):
3083
3085
  ordersData = self.safe_list(response, 'data', [])
3084
3086
  return self.parse_orders(ordersData, market, None, None, params)
3085
3087
 
3088
+ def cancel_orders_for_symbols(self, orders: List[CancellationRequest], params={}):
3089
+ """
3090
+ cancel multiple orders for multiple symbols
3091
+ :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-cancel-multiple-orders
3092
+ :see: https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-post-cancel-algo-order
3093
+ :param CancellationRequest[] orders: each order should contain the parameters required by cancelOrder namely id and symbol
3094
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3095
+ :param boolean [params.trigger]: whether the order is a stop/trigger order
3096
+ :param boolean [params.trailing]: set to True if you want to cancel trailing orders
3097
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
3098
+ """
3099
+ self.load_markets()
3100
+ request = []
3101
+ options = self.safe_dict(self.options, 'cancelOrders', {})
3102
+ defaultMethod = self.safe_string(options, 'method', 'privatePostTradeCancelBatchOrders')
3103
+ method = self.safe_string(params, 'method', defaultMethod)
3104
+ stop = self.safe_bool_2(params, 'stop', 'trigger')
3105
+ trailing = self.safe_bool(params, 'trailing', False)
3106
+ isStopOrTrailing = stop or trailing
3107
+ if isStopOrTrailing:
3108
+ method = 'privatePostTradeCancelAlgos'
3109
+ for i in range(0, len(orders)):
3110
+ order = orders[i]
3111
+ id = self.safe_string(order, 'id')
3112
+ clientOrderId = self.safe_string_2(order, 'clOrdId', 'clientOrderId')
3113
+ symbol = self.safe_string(order, 'symbol')
3114
+ market = self.market(symbol)
3115
+ idKey = 'ordId'
3116
+ if isStopOrTrailing:
3117
+ idKey = 'algoId'
3118
+ elif clientOrderId is not None:
3119
+ idKey = 'clOrdId'
3120
+ requestItem = {
3121
+ 'instId': market['id'],
3122
+ }
3123
+ requestItem[idKey] = clientOrderId if (clientOrderId is not None) else id
3124
+ request.append(requestItem)
3125
+ response = None
3126
+ if method == 'privatePostTradeCancelAlgos':
3127
+ response = self.privatePostTradeCancelAlgos(request) # * dont self.extend with params, otherwise ARRAY will be turned into OBJECT
3128
+ else:
3129
+ response = self.privatePostTradeCancelBatchOrders(request) # * dont self.extend with params, otherwise ARRAY will be turned into OBJECT
3130
+ #
3131
+ # {
3132
+ # "code": "0",
3133
+ # "data": [
3134
+ # {
3135
+ # "clOrdId": "e123456789ec4dBC1123456ba123b45e",
3136
+ # "ordId": "405071912345641543",
3137
+ # "sCode": "0",
3138
+ # "sMsg": ""
3139
+ # },
3140
+ # ...
3141
+ # ],
3142
+ # "msg": ""
3143
+ # }
3144
+ #
3145
+ # Algo order
3146
+ #
3147
+ # {
3148
+ # "code": "0",
3149
+ # "data": [
3150
+ # {
3151
+ # "algoId": "431375349042380800",
3152
+ # "sCode": "0",
3153
+ # "sMsg": ""
3154
+ # }
3155
+ # ],
3156
+ # "msg": ""
3157
+ # }
3158
+ #
3159
+ ordersData = self.safe_list(response, 'data', [])
3160
+ return self.parse_orders(ordersData, None, None, None, params)
3161
+
3162
+ def cancel_all_orders_after(self, timeout: Int, params={}):
3163
+ """
3164
+ dead man's switch, cancel all orders after the given timeout
3165
+ :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-cancel-all-after
3166
+ :param number timeout: time in milliseconds, 0 represents cancel the timer
3167
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3168
+ :returns dict: the api result
3169
+ """
3170
+ self.load_markets()
3171
+ request: dict = {
3172
+ 'timeOut': self.parse_to_int(timeout / 1000) if (timeout > 0) else 0,
3173
+ }
3174
+ response = self.privatePostTradeCancelAllAfter(self.extend(request, params))
3175
+ #
3176
+ # {
3177
+ # "code":"0",
3178
+ # "msg":"",
3179
+ # "data":[
3180
+ # {
3181
+ # "triggerTime":"1587971460",
3182
+ # "ts":"1587971400"
3183
+ # }
3184
+ # ]
3185
+ # }
3186
+ #
3187
+ return response
3188
+
3086
3189
  def parse_order_status(self, status):
3087
3190
  statuses = {
3088
3191
  'canceled': 'canceled',
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.4'
7
+ __version__ = '4.3.6'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10