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.
- ccxt/__init__.py +1 -1
- ccxt/abstract/binance.py +1 -0
- ccxt/abstract/binancecoinm.py +1 -0
- ccxt/abstract/binanceus.py +1 -0
- ccxt/abstract/binanceusdm.py +1 -0
- ccxt/abstract/bingx.py +1 -0
- ccxt/abstract/whitebit.py +22 -1
- ccxt/abstract/woo.py +1 -0
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/base/exchange.py +227 -36
- ccxt/async_support/binance.py +21 -14
- ccxt/async_support/bingx.py +40 -0
- ccxt/async_support/bitmex.py +22 -0
- ccxt/async_support/bybit.py +81 -1
- ccxt/async_support/coinbase.py +4 -4
- ccxt/async_support/coinex.py +29 -32
- ccxt/async_support/cryptocom.py +30 -1
- ccxt/async_support/htx.py +26 -0
- ccxt/async_support/hyperliquid.py +37 -0
- ccxt/async_support/kraken.py +27 -0
- ccxt/async_support/krakenfutures.py +26 -0
- ccxt/async_support/kucoin.py +52 -4
- ccxt/async_support/kucoinfutures.py +2 -2
- ccxt/async_support/okx.py +104 -1
- ccxt/async_support/whitebit.py +149 -2
- ccxt/async_support/woo.py +27 -0
- ccxt/base/exchange.py +233 -4
- ccxt/binance.py +21 -14
- ccxt/bingx.py +40 -0
- ccxt/bitmex.py +22 -0
- ccxt/bybit.py +81 -1
- ccxt/coinbase.py +4 -4
- ccxt/coinex.py +29 -32
- ccxt/cryptocom.py +30 -1
- ccxt/htx.py +26 -0
- ccxt/hyperliquid.py +37 -0
- ccxt/kraken.py +27 -0
- ccxt/krakenfutures.py +26 -0
- ccxt/kucoin.py +52 -4
- ccxt/kucoinfutures.py +2 -2
- ccxt/okx.py +104 -1
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/binance.py +410 -73
- ccxt/pro/bitget.py +1 -1
- ccxt/pro/cex.py +1 -1
- ccxt/pro/lbank.py +1 -1
- ccxt/pro/woo.py +0 -1
- ccxt/test/test_async.py +17 -17
- ccxt/test/test_sync.py +17 -17
- ccxt/whitebit.py +149 -2
- ccxt/woo.py +27 -0
- {ccxt-4.3.4.dist-info → ccxt-4.3.6.dist-info}/METADATA +4 -4
- {ccxt-4.3.4.dist-info → ccxt-4.3.6.dist-info}/RECORD +55 -55
- {ccxt-4.3.4.dist-info → ccxt-4.3.6.dist-info}/WHEEL +0 -0
- {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
|
-
|
3248
|
-
|
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
|
-
|
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
|
-
#
|
1120
|
-
#
|
1121
|
-
#
|
1122
|
-
#
|
1123
|
-
#
|
1124
|
-
#
|
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, '
|
1180
|
-
tradeId = self.
|
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.
|
1211
|
+
side = self.safe_string_2(trade, 'type', 'side')
|
1213
1212
|
else:
|
1214
|
-
side = self.
|
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://
|
1235
|
-
:see: https://
|
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.
|
1251
|
+
response = self.v2PublicGetFuturesDeals(self.extend(request, params))
|
1253
1252
|
else:
|
1254
|
-
response = self.
|
1253
|
+
response = self.v2PublicGetSpotDeals(self.extend(request, params))
|
1255
1254
|
#
|
1256
1255
|
# Spot and Swap
|
1257
1256
|
#
|
1258
|
-
#
|
1259
|
-
#
|
1260
|
-
#
|
1261
|
-
#
|
1262
|
-
#
|
1263
|
-
#
|
1264
|
-
#
|
1265
|
-
#
|
1266
|
-
#
|
1267
|
-
#
|
1268
|
-
#
|
1269
|
-
#
|
1270
|
-
#
|
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
|
-
# "
|
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(
|
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(
|
2097
|
-
# endAt(long) [optional] End time(
|
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',
|