ccxt 4.4.59__py2.py3-none-any.whl → 4.4.60__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 CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  # ----------------------------------------------------------------------------
24
24
 
25
- __version__ = '4.4.59'
25
+ __version__ = '4.4.60'
26
26
 
27
27
  # ----------------------------------------------------------------------------
28
28
 
ccxt/alpaca.py CHANGED
@@ -1138,9 +1138,9 @@ class alpaca(Exchange, ImplicitAPI):
1138
1138
  until = self.safe_integer(params, 'until')
1139
1139
  if until is not None:
1140
1140
  params = self.omit(params, 'until')
1141
- request['endTime'] = until
1141
+ request['endTime'] = self.iso8601(until)
1142
1142
  if since is not None:
1143
- request['after'] = since
1143
+ request['after'] = self.iso8601(since)
1144
1144
  if limit is not None:
1145
1145
  request['limit'] = limit
1146
1146
  response = self.traderPrivateGetV2Orders(self.extend(request, params))
@@ -1374,6 +1374,7 @@ class alpaca(Exchange, ImplicitAPI):
1374
1374
  :param int [limit]: the maximum number of trade structures to retrieve
1375
1375
  :param dict [params]: extra parameters specific to the exchange API endpoint
1376
1376
  :param int [params.until]: the latest time in ms to fetch trades for
1377
+ :param str [params.page_token]: page_token - used for paging
1377
1378
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1378
1379
  """
1379
1380
  self.load_markets()
@@ -1383,8 +1384,12 @@ class alpaca(Exchange, ImplicitAPI):
1383
1384
  }
1384
1385
  if symbol is not None:
1385
1386
  market = self.market(symbol)
1387
+ until = self.safe_integer(params, 'until')
1388
+ if until is not None:
1389
+ params = self.omit(params, 'until')
1390
+ request['until'] = self.iso8601(until)
1386
1391
  if since is not None:
1387
- request['after'] = since
1392
+ request['after'] = self.iso8601(since)
1388
1393
  if limit is not None:
1389
1394
  request['page_size'] = limit
1390
1395
  request, params = self.handle_until_option('until', request, params)
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.59'
7
+ __version__ = '4.4.60'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -1138,9 +1138,9 @@ class alpaca(Exchange, ImplicitAPI):
1138
1138
  until = self.safe_integer(params, 'until')
1139
1139
  if until is not None:
1140
1140
  params = self.omit(params, 'until')
1141
- request['endTime'] = until
1141
+ request['endTime'] = self.iso8601(until)
1142
1142
  if since is not None:
1143
- request['after'] = since
1143
+ request['after'] = self.iso8601(since)
1144
1144
  if limit is not None:
1145
1145
  request['limit'] = limit
1146
1146
  response = await self.traderPrivateGetV2Orders(self.extend(request, params))
@@ -1374,6 +1374,7 @@ class alpaca(Exchange, ImplicitAPI):
1374
1374
  :param int [limit]: the maximum number of trade structures to retrieve
1375
1375
  :param dict [params]: extra parameters specific to the exchange API endpoint
1376
1376
  :param int [params.until]: the latest time in ms to fetch trades for
1377
+ :param str [params.page_token]: page_token - used for paging
1377
1378
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1378
1379
  """
1379
1380
  await self.load_markets()
@@ -1383,8 +1384,12 @@ class alpaca(Exchange, ImplicitAPI):
1383
1384
  }
1384
1385
  if symbol is not None:
1385
1386
  market = self.market(symbol)
1387
+ until = self.safe_integer(params, 'until')
1388
+ if until is not None:
1389
+ params = self.omit(params, 'until')
1390
+ request['until'] = self.iso8601(until)
1386
1391
  if since is not None:
1387
- request['after'] = since
1392
+ request['after'] = self.iso8601(since)
1388
1393
  if limit is not None:
1389
1394
  request['page_size'] = limit
1390
1395
  request, params = self.handle_until_option('until', request, params)
@@ -2,7 +2,7 @@
2
2
 
3
3
  # -----------------------------------------------------------------------------
4
4
 
5
- __version__ = '4.4.59'
5
+ __version__ = '4.4.60'
6
6
 
7
7
  # -----------------------------------------------------------------------------
8
8
 
@@ -1440,6 +1440,9 @@ class Exchange(BaseExchange):
1440
1440
  async def create_orders(self, orders: List[OrderRequest], params={}):
1441
1441
  raise NotSupported(self.id + ' createOrders() is not supported yet')
1442
1442
 
1443
+ async def edit_orders(self, orders: List[OrderRequest], params={}):
1444
+ raise NotSupported(self.id + ' editOrders() is not supported yet')
1445
+
1443
1446
  async def create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1444
1447
  raise NotSupported(self.id + ' createOrderWs() is not supported yet')
1445
1448
 
@@ -86,6 +86,7 @@ class binance(Exchange, ImplicitAPI):
86
86
  'createTrailingPercentOrder': True,
87
87
  'createTriggerOrder': True,
88
88
  'editOrder': True,
89
+ 'editOrders': True,
89
90
  'fetchAccounts': None,
90
91
  'fetchBalance': True,
91
92
  'fetchBidsAsks': True,
@@ -5393,6 +5394,85 @@ class binance(Exchange, ImplicitAPI):
5393
5394
  else:
5394
5395
  return await self.edit_contract_order(id, symbol, type, side, amount, price, params)
5395
5396
 
5397
+ async def edit_orders(self, orders: List[OrderRequest], params={}):
5398
+ """
5399
+ edit a list of trade orders
5400
+
5401
+ https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Modify-Multiple-Orders
5402
+ https://developers.binance.com/docs/derivatives/coin-margined-futures/trade/Modify-Multiple-Orders
5403
+
5404
+ :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
5405
+ :param dict [params]: extra parameters specific to the exchange API endpoint
5406
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
5407
+ """
5408
+ await self.load_markets()
5409
+ ordersRequests = []
5410
+ orderSymbols = []
5411
+ for i in range(0, len(orders)):
5412
+ rawOrder = orders[i]
5413
+ marketId = self.safe_string(rawOrder, 'symbol')
5414
+ orderSymbols.append(marketId)
5415
+ id = self.safe_string(rawOrder, 'id')
5416
+ type = self.safe_string(rawOrder, 'type')
5417
+ side = self.safe_string(rawOrder, 'side')
5418
+ amount = self.safe_value(rawOrder, 'amount')
5419
+ price = self.safe_value(rawOrder, 'price')
5420
+ orderParams = self.safe_dict(rawOrder, 'params', {})
5421
+ isPortfolioMargin = None
5422
+ isPortfolioMargin, orderParams = self.handle_option_and_params_2(orderParams, 'editOrders', 'papi', 'portfolioMargin', False)
5423
+ if isPortfolioMargin:
5424
+ raise NotSupported(self.id + ' editOrders() does not support portfolio margin orders')
5425
+ orderRequest = self.edit_contract_order_request(id, marketId, type, side, amount, price, orderParams)
5426
+ ordersRequests.append(orderRequest)
5427
+ orderSymbols = self.market_symbols(orderSymbols, None, False, True, True)
5428
+ market = self.market(orderSymbols[0])
5429
+ if market['spot'] or market['option']:
5430
+ raise NotSupported(self.id + ' editOrders() does not support ' + market['type'] + ' orders')
5431
+ response = None
5432
+ request: dict = {
5433
+ 'batchOrders': ordersRequests,
5434
+ }
5435
+ request = self.extend(request, params)
5436
+ if market['linear']:
5437
+ response = await self.fapiPrivatePutBatchOrders(request)
5438
+ elif market['inverse']:
5439
+ response = await self.dapiPrivatePutBatchOrders(request)
5440
+ #
5441
+ # [
5442
+ # {
5443
+ # "code": -4005,
5444
+ # "msg": "Quantity greater than max quantity."
5445
+ # },
5446
+ # {
5447
+ # "orderId": 650640530,
5448
+ # "symbol": "LTCUSDT",
5449
+ # "status": "NEW",
5450
+ # "clientOrderId": "x-xcKtGhcu32184eb13585491289bbaf",
5451
+ # "price": "54.00",
5452
+ # "avgPrice": "0.00",
5453
+ # "origQty": "0.100",
5454
+ # "executedQty": "0.000",
5455
+ # "cumQty": "0.000",
5456
+ # "cumQuote": "0.00000",
5457
+ # "timeInForce": "GTC",
5458
+ # "type": "LIMIT",
5459
+ # "reduceOnly": False,
5460
+ # "closePosition": False,
5461
+ # "side": "BUY",
5462
+ # "positionSide": "BOTH",
5463
+ # "stopPrice": "0.00",
5464
+ # "workingType": "CONTRACT_PRICE",
5465
+ # "priceProtect": False,
5466
+ # "origType": "LIMIT",
5467
+ # "priceMatch": "NONE",
5468
+ # "selfTradePreventionMode": "NONE",
5469
+ # "goodTillDate": 0,
5470
+ # "updateTime": 1698073926929
5471
+ # }
5472
+ # ]
5473
+ #
5474
+ return self.parse_orders(response)
5475
+
5396
5476
  def parse_order_status(self, status: Str):
5397
5477
  statuses: dict = {
5398
5478
  'NEW': 'open',
@@ -11243,7 +11323,7 @@ class binance(Exchange, ImplicitAPI):
11243
11323
  params['newClientOrderId'] = brokerId + self.uuid22()
11244
11324
  query = None
11245
11325
  # handle batchOrders
11246
- if (path == 'batchOrders') and (method == 'POST'):
11326
+ if (path == 'batchOrders') and ((method == 'POST') or (method == 'PUT')):
11247
11327
  batchOrders = self.safe_value(params, 'batchOrders')
11248
11328
  queryBatch = (self.json(batchOrders))
11249
11329
  params['batchOrders'] = queryBatch
@@ -8856,7 +8856,8 @@ class bitget(Exchange, ImplicitAPI):
8856
8856
  if method == 'POST':
8857
8857
  headers['Content-Type'] = 'application/json'
8858
8858
  sandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
8859
- if sandboxMode:
8859
+ if sandboxMode and (path != 'v2/public/time'):
8860
+ # https://github.com/ccxt/ccxt/issues/25252#issuecomment-2662742336
8860
8861
  if headers is None:
8861
8862
  headers = {}
8862
8863
  headers['PAPTRADING'] = '1'
@@ -6525,10 +6525,13 @@ classic accounts only/ spot not supported* fetches information on an order made
6525
6525
  # }
6526
6526
  #
6527
6527
  timestamp = self.safe_integer(interest, 'timestamp')
6528
- value = self.safe_number_2(interest, 'open_interest', 'openInterest')
6528
+ openInterest = self.safe_number_2(interest, 'open_interest', 'openInterest')
6529
+ # the openInterest is in the base asset for linear and quote asset for inverse
6530
+ amount = openInterest if market['linear'] else None
6531
+ value = openInterest if market['inverse'] else None
6529
6532
  return self.safe_open_interest({
6530
6533
  'symbol': market['symbol'],
6531
- 'openInterestAmount': None,
6534
+ 'openInterestAmount': amount,
6532
6535
  'openInterestValue': value,
6533
6536
  'timestamp': timestamp,
6534
6537
  'datetime': self.iso8601(timestamp),
@@ -1882,7 +1882,7 @@ class hollaex(Exchange, ImplicitAPI):
1882
1882
  # "network":"https://api.hollaex.network"
1883
1883
  # }
1884
1884
  #
1885
- coins = self.safe_list(response, 'coins')
1885
+ coins = self.safe_dict(response, 'coins', {})
1886
1886
  return self.parse_deposit_withdraw_fees(coins, codes, 'symbol')
1887
1887
 
1888
1888
  def normalize_number_if_needed(self, number):
@@ -2885,7 +2885,7 @@ class oxfun(Exchange, ImplicitAPI):
2885
2885
  'AccessKey': self.apiKey,
2886
2886
  'Timestamp': datetime,
2887
2887
  'Signature': signature,
2888
- 'Nonce': nonce,
2888
+ 'Nonce': str(nonce),
2889
2889
  }
2890
2890
  return {'url': url, 'method': method, 'body': body, 'headers': headers}
2891
2891
 
ccxt/async_support/xt.py CHANGED
@@ -1394,9 +1394,15 @@ class xt(Exchange, ImplicitAPI):
1394
1394
  :param int [since]: timestamp in ms of the earliest candle to fetch
1395
1395
  :param int [limit]: the maximum amount of candles to fetch
1396
1396
  :param dict params: extra parameters specific to the xt api endpoint
1397
+ :param int [params.until]: timestamp in ms of the latest candle to fetch
1398
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1397
1399
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
1398
1400
  """
1399
1401
  await self.load_markets()
1402
+ paginate = False
1403
+ paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate', False)
1404
+ if paginate:
1405
+ return await self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1000)
1400
1406
  market = self.market(symbol)
1401
1407
  request = {
1402
1408
  'symbol': market['id'],
@@ -1406,6 +1412,12 @@ class xt(Exchange, ImplicitAPI):
1406
1412
  request['startTime'] = since
1407
1413
  if limit is not None:
1408
1414
  request['limit'] = limit
1415
+ else:
1416
+ request['limit'] = 1000
1417
+ until = self.safe_integer(params, 'until')
1418
+ params = self.omit(params, ['until'])
1419
+ if until is not None:
1420
+ request['endTime'] = until
1409
1421
  response = None
1410
1422
  if market['linear']:
1411
1423
  response = await self.publicLinearGetFutureMarketV1PublicQKline(self.extend(request, params))
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.59'
7
+ __version__ = '4.4.60'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -1871,6 +1871,7 @@ class Exchange(object):
1871
1871
  'createTriggerOrderWs': None,
1872
1872
  'deposit': None,
1873
1873
  'editOrder': 'emulated',
1874
+ 'editOrders': None,
1874
1875
  'editOrderWs': None,
1875
1876
  'fetchAccounts': None,
1876
1877
  'fetchBalance': True,
@@ -5178,6 +5179,9 @@ class Exchange(object):
5178
5179
  def create_orders(self, orders: List[OrderRequest], params={}):
5179
5180
  raise NotSupported(self.id + ' createOrders() is not supported yet')
5180
5181
 
5182
+ def edit_orders(self, orders: List[OrderRequest], params={}):
5183
+ raise NotSupported(self.id + ' editOrders() is not supported yet')
5184
+
5181
5185
  def create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
5182
5186
  raise NotSupported(self.id + ' createOrderWs() is not supported yet')
5183
5187
 
ccxt/binance.py CHANGED
@@ -85,6 +85,7 @@ class binance(Exchange, ImplicitAPI):
85
85
  'createTrailingPercentOrder': True,
86
86
  'createTriggerOrder': True,
87
87
  'editOrder': True,
88
+ 'editOrders': True,
88
89
  'fetchAccounts': None,
89
90
  'fetchBalance': True,
90
91
  'fetchBidsAsks': True,
@@ -5392,6 +5393,85 @@ class binance(Exchange, ImplicitAPI):
5392
5393
  else:
5393
5394
  return self.edit_contract_order(id, symbol, type, side, amount, price, params)
5394
5395
 
5396
+ def edit_orders(self, orders: List[OrderRequest], params={}):
5397
+ """
5398
+ edit a list of trade orders
5399
+
5400
+ https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Modify-Multiple-Orders
5401
+ https://developers.binance.com/docs/derivatives/coin-margined-futures/trade/Modify-Multiple-Orders
5402
+
5403
+ :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
5404
+ :param dict [params]: extra parameters specific to the exchange API endpoint
5405
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
5406
+ """
5407
+ self.load_markets()
5408
+ ordersRequests = []
5409
+ orderSymbols = []
5410
+ for i in range(0, len(orders)):
5411
+ rawOrder = orders[i]
5412
+ marketId = self.safe_string(rawOrder, 'symbol')
5413
+ orderSymbols.append(marketId)
5414
+ id = self.safe_string(rawOrder, 'id')
5415
+ type = self.safe_string(rawOrder, 'type')
5416
+ side = self.safe_string(rawOrder, 'side')
5417
+ amount = self.safe_value(rawOrder, 'amount')
5418
+ price = self.safe_value(rawOrder, 'price')
5419
+ orderParams = self.safe_dict(rawOrder, 'params', {})
5420
+ isPortfolioMargin = None
5421
+ isPortfolioMargin, orderParams = self.handle_option_and_params_2(orderParams, 'editOrders', 'papi', 'portfolioMargin', False)
5422
+ if isPortfolioMargin:
5423
+ raise NotSupported(self.id + ' editOrders() does not support portfolio margin orders')
5424
+ orderRequest = self.edit_contract_order_request(id, marketId, type, side, amount, price, orderParams)
5425
+ ordersRequests.append(orderRequest)
5426
+ orderSymbols = self.market_symbols(orderSymbols, None, False, True, True)
5427
+ market = self.market(orderSymbols[0])
5428
+ if market['spot'] or market['option']:
5429
+ raise NotSupported(self.id + ' editOrders() does not support ' + market['type'] + ' orders')
5430
+ response = None
5431
+ request: dict = {
5432
+ 'batchOrders': ordersRequests,
5433
+ }
5434
+ request = self.extend(request, params)
5435
+ if market['linear']:
5436
+ response = self.fapiPrivatePutBatchOrders(request)
5437
+ elif market['inverse']:
5438
+ response = self.dapiPrivatePutBatchOrders(request)
5439
+ #
5440
+ # [
5441
+ # {
5442
+ # "code": -4005,
5443
+ # "msg": "Quantity greater than max quantity."
5444
+ # },
5445
+ # {
5446
+ # "orderId": 650640530,
5447
+ # "symbol": "LTCUSDT",
5448
+ # "status": "NEW",
5449
+ # "clientOrderId": "x-xcKtGhcu32184eb13585491289bbaf",
5450
+ # "price": "54.00",
5451
+ # "avgPrice": "0.00",
5452
+ # "origQty": "0.100",
5453
+ # "executedQty": "0.000",
5454
+ # "cumQty": "0.000",
5455
+ # "cumQuote": "0.00000",
5456
+ # "timeInForce": "GTC",
5457
+ # "type": "LIMIT",
5458
+ # "reduceOnly": False,
5459
+ # "closePosition": False,
5460
+ # "side": "BUY",
5461
+ # "positionSide": "BOTH",
5462
+ # "stopPrice": "0.00",
5463
+ # "workingType": "CONTRACT_PRICE",
5464
+ # "priceProtect": False,
5465
+ # "origType": "LIMIT",
5466
+ # "priceMatch": "NONE",
5467
+ # "selfTradePreventionMode": "NONE",
5468
+ # "goodTillDate": 0,
5469
+ # "updateTime": 1698073926929
5470
+ # }
5471
+ # ]
5472
+ #
5473
+ return self.parse_orders(response)
5474
+
5395
5475
  def parse_order_status(self, status: Str):
5396
5476
  statuses: dict = {
5397
5477
  'NEW': 'open',
@@ -11242,7 +11322,7 @@ class binance(Exchange, ImplicitAPI):
11242
11322
  params['newClientOrderId'] = brokerId + self.uuid22()
11243
11323
  query = None
11244
11324
  # handle batchOrders
11245
- if (path == 'batchOrders') and (method == 'POST'):
11325
+ if (path == 'batchOrders') and ((method == 'POST') or (method == 'PUT')):
11246
11326
  batchOrders = self.safe_value(params, 'batchOrders')
11247
11327
  queryBatch = (self.json(batchOrders))
11248
11328
  params['batchOrders'] = queryBatch
ccxt/bitget.py CHANGED
@@ -8855,7 +8855,8 @@ class bitget(Exchange, ImplicitAPI):
8855
8855
  if method == 'POST':
8856
8856
  headers['Content-Type'] = 'application/json'
8857
8857
  sandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
8858
- if sandboxMode:
8858
+ if sandboxMode and (path != 'v2/public/time'):
8859
+ # https://github.com/ccxt/ccxt/issues/25252#issuecomment-2662742336
8859
8860
  if headers is None:
8860
8861
  headers = {}
8861
8862
  headers['PAPTRADING'] = '1'
ccxt/bybit.py CHANGED
@@ -6524,10 +6524,13 @@ classic accounts only/ spot not supported* fetches information on an order made
6524
6524
  # }
6525
6525
  #
6526
6526
  timestamp = self.safe_integer(interest, 'timestamp')
6527
- value = self.safe_number_2(interest, 'open_interest', 'openInterest')
6527
+ openInterest = self.safe_number_2(interest, 'open_interest', 'openInterest')
6528
+ # the openInterest is in the base asset for linear and quote asset for inverse
6529
+ amount = openInterest if market['linear'] else None
6530
+ value = openInterest if market['inverse'] else None
6528
6531
  return self.safe_open_interest({
6529
6532
  'symbol': market['symbol'],
6530
- 'openInterestAmount': None,
6533
+ 'openInterestAmount': amount,
6531
6534
  'openInterestValue': value,
6532
6535
  'timestamp': timestamp,
6533
6536
  'datetime': self.iso8601(timestamp),
ccxt/hollaex.py CHANGED
@@ -1882,7 +1882,7 @@ class hollaex(Exchange, ImplicitAPI):
1882
1882
  # "network":"https://api.hollaex.network"
1883
1883
  # }
1884
1884
  #
1885
- coins = self.safe_list(response, 'coins')
1885
+ coins = self.safe_dict(response, 'coins', {})
1886
1886
  return self.parse_deposit_withdraw_fees(coins, codes, 'symbol')
1887
1887
 
1888
1888
  def normalize_number_if_needed(self, number):
ccxt/oxfun.py CHANGED
@@ -2884,7 +2884,7 @@ class oxfun(Exchange, ImplicitAPI):
2884
2884
  'AccessKey': self.apiKey,
2885
2885
  'Timestamp': datetime,
2886
2886
  'Signature': signature,
2887
- 'Nonce': nonce,
2887
+ 'Nonce': str(nonce),
2888
2888
  }
2889
2889
  return {'url': url, 'method': method, 'body': body, 'headers': headers}
2890
2890
 
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.59'
7
+ __version__ = '4.4.60'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
ccxt/pro/xt.py CHANGED
@@ -4,8 +4,8 @@
4
4
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
5
 
6
6
  import ccxt.async_support
7
- from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp
8
- from ccxt.base.types import Any, Balances, Int, Market, Order, OrderBook, Str, Strings, Ticker, Tickers, Trade
7
+ from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp
8
+ from ccxt.base.types import Any, Balances, Int, Market, Order, OrderBook, Position, Str, Strings, Ticker, Tickers, Trade
9
9
  from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
11
 
@@ -25,7 +25,7 @@ class xt(ccxt.async_support.xt):
25
25
  'watchBalance': True,
26
26
  'watchOrders': True,
27
27
  'watchMyTrades': True,
28
- 'watchPositions': None, # TODO https://doc.xt.com/#futures_user_websocket_v2position
28
+ 'watchPositions': True,
29
29
  },
30
30
  'urls': {
31
31
  'api': {
@@ -45,6 +45,11 @@ class xt(ccxt.async_support.xt):
45
45
  'watchTickers': {
46
46
  'method': 'tickers', # agg_tickers(contract only)
47
47
  },
48
+ 'watchPositions': {
49
+ 'type': 'swap',
50
+ 'fetchPositionsSnapshot': True,
51
+ 'awaitPositionsSnapshot': True,
52
+ },
48
53
  },
49
54
  'streaming': {
50
55
  'keepAlive': 20000,
@@ -352,6 +357,106 @@ class xt(ccxt.async_support.xt):
352
357
  name = 'balance'
353
358
  return await self.subscribe(name, 'private', 'watchBalance', None, None, params)
354
359
 
360
+ async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
361
+ """
362
+
363
+ https://doc.xt.com/#futures_user_websocket_v2position
364
+
365
+ watch all open positions
366
+ :param str[]|None symbols: list of unified market symbols
367
+ :param number [since]: since timestamp
368
+ :param number [limit]: limit
369
+ :param dict params: extra parameters specific to the exchange API endpoint
370
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
371
+ """
372
+ await self.load_markets()
373
+ url = self.urls['api']['ws']['contract'] + '/' + 'user'
374
+ client = self.client(url)
375
+ self.set_positions_cache(client)
376
+ fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', True)
377
+ awaitPositionsSnapshot = self.handle_option('watchPositions', 'awaitPositionsSnapshot', True)
378
+ cache = self.positions
379
+ if fetchPositionsSnapshot and awaitPositionsSnapshot and self.is_empty(cache):
380
+ snapshot = await client.future('fetchPositionsSnapshot')
381
+ return self.filter_by_symbols_since_limit(snapshot, symbols, since, limit, True)
382
+ name = 'position'
383
+ newPositions = await self.subscribe(name, 'private', 'watchPositions', None, None, params)
384
+ if self.newUpdates:
385
+ return newPositions
386
+ return self.filter_by_symbols_since_limit(cache, symbols, since, limit, True)
387
+
388
+ def set_positions_cache(self, client: Client):
389
+ if self.positions is None:
390
+ self.positions = ArrayCacheBySymbolBySide()
391
+ fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot')
392
+ if fetchPositionsSnapshot:
393
+ messageHash = 'fetchPositionsSnapshot'
394
+ if not (messageHash in client.futures):
395
+ client.future(messageHash)
396
+ self.spawn(self.load_positions_snapshot, client, messageHash)
397
+
398
+ async def load_positions_snapshot(self, client, messageHash):
399
+ positions = await self.fetch_positions(None)
400
+ self.positions = ArrayCacheBySymbolBySide()
401
+ cache = self.positions
402
+ for i in range(0, len(positions)):
403
+ position = positions[i]
404
+ contracts = self.safe_number(position, 'contracts', 0)
405
+ if contracts > 0:
406
+ cache.append(position)
407
+ # don't remove the future from the .futures cache
408
+ future = client.futures[messageHash]
409
+ future.resolve(cache)
410
+ client.resolve(cache, 'position::contract')
411
+
412
+ def handle_position(self, client, message):
413
+ #
414
+ # {
415
+ # topic: 'position',
416
+ # event: 'position',
417
+ # data: {
418
+ # accountId: 245296,
419
+ # accountType: 0,
420
+ # symbol: 'eth_usdt',
421
+ # contractType: 'PERPETUAL',
422
+ # positionType: 'CROSSED',
423
+ # positionSide: 'LONG',
424
+ # positionSize: '1',
425
+ # closeOrderSize: '0',
426
+ # availableCloseSize: '1',
427
+ # realizedProfit: '-0.0121',
428
+ # entryPrice: '2637.87',
429
+ # openOrderSize: '1',
430
+ # isolatedMargin: '2.63787',
431
+ # openOrderMarginFrozen: '2.78832014',
432
+ # underlyingType: 'U_BASED',
433
+ # leverage: 10,
434
+ # welfareAccount: False,
435
+ # profitFixedLatest: {},
436
+ # closeProfit: '0.0000',
437
+ # totalFee: '-0.0158',
438
+ # totalFundFee: '0.0037',
439
+ # markPrice: '2690.96'
440
+ # }
441
+ # }
442
+ #
443
+ if self.positions is None:
444
+ self.positions = ArrayCacheBySymbolBySide()
445
+ cache = self.positions
446
+ data = self.safe_dict(message, 'data', {})
447
+ position = self.parse_position(data)
448
+ cache.append(position)
449
+ messageHashes = self.find_message_hashes(client, 'position::contract')
450
+ for i in range(0, len(messageHashes)):
451
+ messageHash = messageHashes[i]
452
+ parts = messageHash.split('::')
453
+ symbolsString = parts[1]
454
+ symbols = symbolsString.split(',')
455
+ positions = self.filter_by_array([position], 'symbol', symbols, False)
456
+ if not self.is_empty(positions):
457
+ client.resolve(positions, messageHash)
458
+ client.resolve([position], 'position::contract')
459
+
355
460
  def handle_ticker(self, client: Client, message: dict):
356
461
  #
357
462
  # spot
@@ -1036,6 +1141,7 @@ class xt(ccxt.async_support.xt):
1036
1141
  'agg_tickers': self.handle_tickers,
1037
1142
  'balance': self.handle_balance,
1038
1143
  'order': self.handle_order,
1144
+ 'position': self.handle_position,
1039
1145
  }
1040
1146
  method = self.safe_value(methods, topic)
1041
1147
  if topic == 'trade':
ccxt/test/tests_async.py CHANGED
@@ -620,10 +620,21 @@ class testMainClass:
620
620
  dump('[TEST_WARNING]' + error_message)
621
621
  return True
622
622
 
623
+ def check_constructor(self, exchange):
624
+ # todo: this might be moved in base tests later
625
+ if exchange.id == 'binance':
626
+ assert exchange.hostname is None, 'binance.com hostname should be empty'
627
+ assert exchange.urls['api']['public'] == 'https://api.binance.com/api/v3', 'https://api.binance.com/api/v3 does not match: ' + exchange.urls['api']['public']
628
+ assert ('lending/union/account' in exchange.api['sapi']['get']), 'SAPI should contain the endpoint lending/union/account, ' + json_stringify(exchange.api['sapi']['get'])
629
+ elif exchange.id == 'binanceus':
630
+ assert exchange.hostname == 'binance.us', 'binance.us hostname does not match ' + exchange.hostname
631
+ assert exchange.urls['api']['public'] == 'https://api.binance.us/api/v3', 'https://api.binance.us/api/v3 does not match: ' + exchange.urls['api']['public']
632
+
623
633
  async def start_test(self, exchange, symbol):
624
634
  # we do not need to test aliases
625
635
  if exchange.alias:
626
636
  return True
637
+ self.check_constructor(exchange)
627
638
  if self.sandbox or get_exchange_prop(exchange, 'sandbox'):
628
639
  exchange.set_sandbox_mode(True)
629
640
  try:
ccxt/test/tests_sync.py CHANGED
@@ -617,10 +617,21 @@ class testMainClass:
617
617
  dump('[TEST_WARNING]' + error_message)
618
618
  return True
619
619
 
620
+ def check_constructor(self, exchange):
621
+ # todo: this might be moved in base tests later
622
+ if exchange.id == 'binance':
623
+ assert exchange.hostname is None, 'binance.com hostname should be empty'
624
+ assert exchange.urls['api']['public'] == 'https://api.binance.com/api/v3', 'https://api.binance.com/api/v3 does not match: ' + exchange.urls['api']['public']
625
+ assert ('lending/union/account' in exchange.api['sapi']['get']), 'SAPI should contain the endpoint lending/union/account, ' + json_stringify(exchange.api['sapi']['get'])
626
+ elif exchange.id == 'binanceus':
627
+ assert exchange.hostname == 'binance.us', 'binance.us hostname does not match ' + exchange.hostname
628
+ assert exchange.urls['api']['public'] == 'https://api.binance.us/api/v3', 'https://api.binance.us/api/v3 does not match: ' + exchange.urls['api']['public']
629
+
620
630
  def start_test(self, exchange, symbol):
621
631
  # we do not need to test aliases
622
632
  if exchange.alias:
623
633
  return True
634
+ self.check_constructor(exchange)
624
635
  if self.sandbox or get_exchange_prop(exchange, 'sandbox'):
625
636
  exchange.set_sandbox_mode(True)
626
637
  try:
ccxt/xt.py CHANGED
@@ -1393,9 +1393,15 @@ class xt(Exchange, ImplicitAPI):
1393
1393
  :param int [since]: timestamp in ms of the earliest candle to fetch
1394
1394
  :param int [limit]: the maximum amount of candles to fetch
1395
1395
  :param dict params: extra parameters specific to the xt api endpoint
1396
+ :param int [params.until]: timestamp in ms of the latest candle to fetch
1397
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1396
1398
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
1397
1399
  """
1398
1400
  self.load_markets()
1401
+ paginate = False
1402
+ paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate', False)
1403
+ if paginate:
1404
+ return self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1000)
1399
1405
  market = self.market(symbol)
1400
1406
  request = {
1401
1407
  'symbol': market['id'],
@@ -1405,6 +1411,12 @@ class xt(Exchange, ImplicitAPI):
1405
1411
  request['startTime'] = since
1406
1412
  if limit is not None:
1407
1413
  request['limit'] = limit
1414
+ else:
1415
+ request['limit'] = 1000
1416
+ until = self.safe_integer(params, 'until')
1417
+ params = self.omit(params, ['until'])
1418
+ if until is not None:
1419
+ request['endTime'] = until
1408
1420
  response = None
1409
1421
  if market['linear']:
1410
1422
  response = self.publicLinearGetFutureMarketV1PublicQKline(self.extend(request, params))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ccxt
3
- Version: 4.4.59
3
+ Version: 4.4.60
4
4
  Summary: A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges
5
5
  Home-page: https://ccxt.com
6
6
  Author: Igor Kroitor
@@ -277,13 +277,13 @@ console.log(version, Object.keys(exchanges));
277
277
 
278
278
  All-in-one browser bundle (dependencies included), served from a CDN of your choice:
279
279
 
280
- * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.4.59/dist/ccxt.browser.min.js
281
- * unpkg: https://unpkg.com/ccxt@4.4.59/dist/ccxt.browser.min.js
280
+ * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.4.60/dist/ccxt.browser.min.js
281
+ * unpkg: https://unpkg.com/ccxt@4.4.60/dist/ccxt.browser.min.js
282
282
 
283
283
  CDNs are not updated in real-time and may have delays. Defaulting to the most recent version without specifying the version number is not recommended. Please, keep in mind that we are not responsible for the correct operation of those CDN servers.
284
284
 
285
285
  ```HTML
286
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.4.59/dist/ccxt.browser.min.js"></script>
286
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.4.60/dist/ccxt.browser.min.js"></script>
287
287
  ```
288
288
 
289
289
  Creates a global `ccxt` object:
@@ -1,10 +1,10 @@
1
- ccxt/__init__.py,sha256=1cEYeKYBirCudug5yRZ8hADBJ8aNERPcvYiv19gLRCo,16681
1
+ ccxt/__init__.py,sha256=Txply3epYWSMPmDKLgL4n6DF0TM-JZBhlt0WrhjDYAM,16681
2
2
  ccxt/ace.py,sha256=l_4-pNkkJBINgPsBtM4b9Ff6t8Tp59tKCXstLesMzvc,44752
3
- ccxt/alpaca.py,sha256=DKL-JnIL336gZUAmJe7B9-NObmEIsqjbAtFca6xzMvA,78137
3
+ ccxt/alpaca.py,sha256=t8ahjPZQEENMElUyPzH_1-I0i5VGsJpoUknpKl-IkKM,78428
4
4
  ccxt/ascendex.py,sha256=CoV4qMazVCUMn1J0wlE5sJIak_hfmVq0VOeHB6VOQBs,155992
5
5
  ccxt/bequant.py,sha256=gNe6tFy91-lEW8pEYv2-SmmjpwAm403ZxIpuN_QZqVw,1193
6
6
  ccxt/bigone.py,sha256=3FADYcYU_fryjR1a3EoLFc4VRnY5pa7bUaWx1gnoA-s,95960
7
- ccxt/binance.py,sha256=gfFdLQM_ajmTnG95SxjIZ0XxA_9MyRSgVu2zy5yKENk,682311
7
+ ccxt/binance.py,sha256=hgiSOBZjKk756qsMbZUlSHWQTeD9kXZJHMuQ-DXHCuA,686034
8
8
  ccxt/binancecoinm.py,sha256=UEJd_dZQkrLdJpaCE_t9aHCwJdxpjheyTaWJ8RKWIm8,1720
9
9
  ccxt/binanceus.py,sha256=fPaJxinZbmJbrXMW1aYW32n6fXX_VL7odjLEng77wdI,9500
10
10
  ccxt/binanceusdm.py,sha256=BI4hya6nydNHC7hiYw6FVk7QaQWHG6emVnCx1K6R02k,2650
@@ -16,7 +16,7 @@ ccxt/bitcoincom.py,sha256=kpGs1gz2443UrgEsWYeCR5L6FJyYqK5XLmFWaL-I0xM,541
16
16
  ccxt/bitfinex.py,sha256=PffXxsmaNCQywbPgyc8VBZD_gxYOZCW3ULvpZ8MAV9I,166078
17
17
  ccxt/bitfinex1.py,sha256=QOUR8evwrVP3XLUZ4z8cMmBCGIrji8G8RNKsxR6Y65g,74205
18
18
  ccxt/bitflyer.py,sha256=tSKipH_SKEK8iChF94sxIjizx_volR1xaElIF2PGABI,46888
19
- ccxt/bitget.py,sha256=WccOGUtwmXHPCbi7I9W2Oc7wXUyjm0-Sqh6wSj0I2JI,444420
19
+ ccxt/bitget.py,sha256=Y5mZPkjYd6oYkWZWOpKfzkTVKj_1aHfQLC9GRIyUUyc,444531
20
20
  ccxt/bithumb.py,sha256=akxyY_PY_7qnAkSEvG8V2DbOhfHZnCNW_OkJDUzUawY,50065
21
21
  ccxt/bitmart.py,sha256=j7p2CnPPax3TGa_WBwHpQGXIf6aSa6PhOjxPaY8yudk,240901
22
22
  ccxt/bitmex.py,sha256=bCgSeL8i0djDfb5aPXVljngTmmMpx73Cp6Kou5ngDGw,131447
@@ -34,7 +34,7 @@ ccxt/btcalpha.py,sha256=t9ku28FD2yE4rc-V4U-eRhsHKz4izMSCK8xb7wQ4kNE,39704
34
34
  ccxt/btcbox.py,sha256=nsJrbfky_4wC-O1oXb4oWr3EYiO49L-sa4-0NxB9Zkg,30034
35
35
  ccxt/btcmarkets.py,sha256=jC6RA5Tn1DR4FZpZln-KZKkz9WYT6o_MNJ6s6G-Dhjs,55829
36
36
  ccxt/btcturk.py,sha256=mNG1uJqcPgTQ0g2sozq5Up1xNndrF_vraYEYsOs3jKw,39482
37
- ccxt/bybit.py,sha256=-Qc8OXqtcEIM2MEWvrEIGkAmVTDzcIWq7aHsd_jy5rI,431672
37
+ ccxt/bybit.py,sha256=PNpIeRI-lUVfg3SJV4Zo97r6cLSmCwntrkvmJNI3cOk,431888
38
38
  ccxt/cex.py,sha256=QczrmAFcDyGK7pTKjdH4yVkG916War3_cigkqsEDlwQ,72342
39
39
  ccxt/coinbase.py,sha256=3MqYX9n4wCojQzFc_OFEGpPdn4ZR8wwnYdnt-uPgEL4,229962
40
40
  ccxt/coinbaseadvanced.py,sha256=Eb1X4_VtdNEu1q0Anr-MzdHG55OhCiZYgdeZv2kFuPg,577
@@ -63,7 +63,7 @@ ccxt/gateio.py,sha256=7KbnH56kBK0tb_CN-wT10jaF5DfTrnHarhu27eknsLI,484
63
63
  ccxt/gemini.py,sha256=S-MWX71z5eEw4VrPau0y9Aq2E7tiHbLWEIz1lSUMEjU,83581
64
64
  ccxt/hashkey.py,sha256=2K9duxYxXvLYRBeqAeUDe4UIdBAeJ5kp1Xqj9vWzGNM,191739
65
65
  ccxt/hitbtc.py,sha256=72r1Iwm3IzBKdg3-fPEtLgNJmf8M6bjWw-h0YcryQUo,159292
66
- ccxt/hollaex.py,sha256=3hcW9XJCQZZS7YZjjibMX4BdrtBJZJ4n9LruX2dUskA,79094
66
+ ccxt/hollaex.py,sha256=8t7uAozunXEjN3xSeWQXEt0xN5CCouNaQ4l0Dw1_03w,79098
67
67
  ccxt/htx.py,sha256=EWhazX3qIS5PQEnhuY85n1E3eEP2d81y3UgilrF1WVs,443502
68
68
  ccxt/huobi.py,sha256=rQI8HyRj6Jt9XgJYdTbu4tzu85sv0SWT3rvO_HY8r_E,477
69
69
  ccxt/huobijp.py,sha256=khqty8c-gxznCIhmOhup8nHhTHBZWwCjfH5VzXz4pL8,92912
@@ -88,7 +88,7 @@ ccxt/oceanex.py,sha256=YhvVgresX7nm8sFxD8Yr5pQI5IzuuRllW-JdA9RkDSM,44195
88
88
  ccxt/okcoin.py,sha256=m-rW6DcscZeS2Hl_MHmBow6w8Y6yiEpgQ8OYc6KnfeE,154750
89
89
  ccxt/okx.py,sha256=Z2a830X99DA1sNJPfL7fYhfu05pAhKOyqoVmR0GBLRg,392879
90
90
  ccxt/onetrading.py,sha256=mNmwMVK-7qQEW6L35kfN6OwqvGLiVXrot4B2SDx3_TQ,76305
91
- ccxt/oxfun.py,sha256=EI-Mmhu3EP7H4v0fkAt7uj1SEbhvLuoeBQy0t-Q6irE,127499
91
+ ccxt/oxfun.py,sha256=XfF-kErOOwLBHVpqxpXngFj8EZmXqAGtpmGE_2Q5Ssg,127504
92
92
  ccxt/p2b.py,sha256=2mkYFm3h_lFtgEu13F6sDgbj3UxYyTG-3R_l-w7NZiM,56725
93
93
  ccxt/paradex.py,sha256=J1MISnRxvi8fzylL-n4IjGo7f8jEn_sMvy-N7ep_kqc,88918
94
94
  ccxt/paymium.py,sha256=l6gBKUBEvfxgLzVZaaLq3-v_wD-I9S64Mdi_mf87_v4,26201
@@ -105,7 +105,7 @@ ccxt/wavesexchange.py,sha256=Syfi1W5yLpcu0Pe4MPhpJ9lWm1TRLfzUNdofTQDF7KA,119634
105
105
  ccxt/whitebit.py,sha256=NZ1gGUr5NMDKe1MSgb12cR5bMIDUkyqe6kFo5CIdpL8,123928
106
106
  ccxt/woo.py,sha256=dQNBff6RfaZubKaY5RToI2gGs3kWcHH3RtPhDcTdzGs,159378
107
107
  ccxt/woofipro.py,sha256=mbZLBhENAw7sXmbruZ3PzDgYR5EoinQPMLoFpDXU96w,120876
108
- ccxt/xt.py,sha256=sWzW_LQHfldJybtDr2NuDuOKDRKvlZsFdoFUAgfnh6M,211290
108
+ ccxt/xt.py,sha256=MRkoQWMGXp3P_FGaIxqzAmoda1u1Xl8Qp-BAplifJa8,212094
109
109
  ccxt/yobit.py,sha256=tyH_AYAXPGl28zR4s_0SQ9V1TYm7oYWkzeJ04qj9d9c,57703
110
110
  ccxt/zaif.py,sha256=-qt419JrCajq69n9jNC3hnZC5DcMnrkGDWnNS2Enxrg,31175
111
111
  ccxt/zonda.py,sha256=29gcWGBvS6b01Wu8QhBg60825kVxHJRqsDJdB-6eZ8U,85006
@@ -220,13 +220,13 @@ ccxt/abstract/xt.py,sha256=p0fG3O8kIeMYIvMlqxrhpXeo7lraee6lIlu9yqu6f10,27340
220
220
  ccxt/abstract/yobit.py,sha256=8ycfCO8ORFly9hc0Aa47sZyX4_ZKPXS9h9yJzI-uQ7Q,1339
221
221
  ccxt/abstract/zaif.py,sha256=m15WHdl3gYy0GOXNZ8NEH8eE7sVh8c0T_ITNuU8vXeU,3935
222
222
  ccxt/abstract/zonda.py,sha256=X-hCW0SdX3YKZWixDyW-O2211M58Rno8kKJ6quY7rw4,7183
223
- ccxt/async_support/__init__.py,sha256=mrWWJ3ZIOd9Dw7EkgKy_N7na6eXIsvGWBizMAMJfBNk,16504
223
+ ccxt/async_support/__init__.py,sha256=6oERvbIw0_-RKrWlet28njJvqz09NRo6SA2_HgMIn5I,16504
224
224
  ccxt/async_support/ace.py,sha256=BCcZ8TexOxR93v8dEICqhRlDvvzJPiLz999kp58GzwM,44976
225
- ccxt/async_support/alpaca.py,sha256=0x4N4Jj4fWpo6j6q672SlMj3tsybAubR9_8hhwqpSJE,78583
225
+ ccxt/async_support/alpaca.py,sha256=VHP3C7c3jIefKBSleXbTWjnY6RQnBGRNYe5HgrG0PVg,78874
226
226
  ccxt/async_support/ascendex.py,sha256=7t8avcGu6O-buamW81K7JTV5wctKC0qypg0yYMvKs7Y,156805
227
227
  ccxt/async_support/bequant.py,sha256=Szyla1q_L8o_mX09QYxltw4tfMWpxXkj95I4WxnjB8A,1207
228
228
  ccxt/async_support/bigone.py,sha256=1g0eoESEzEwVy7ryotNtSh8Tv8WuVPI4C1KG-NspU3Y,96414
229
- ccxt/async_support/binance.py,sha256=hRiogGpiVFdNQ_mmA5ZQzZvfaoVpqwrq0V4JTKtx788,685200
229
+ ccxt/async_support/binance.py,sha256=_E-4Xh0tr1Nelnh0NpQhsa2zLgktI4JkBK2yUWVJ0GQ,688947
230
230
  ccxt/async_support/binancecoinm.py,sha256=1NC5yuHlkNgXH5mEz20lU7O7u3pODa6fluSmHO7W5Lc,1758
231
231
  ccxt/async_support/binanceus.py,sha256=fD4Rm2iJZ6YZuJAbRt5TPh2p8dIyN8yQkovnSWKF6F8,9514
232
232
  ccxt/async_support/binanceusdm.py,sha256=7SvgLSpu0-VWHDP_WH8Zo-SEORsyF-tuHhWdQnFMf80,2688
@@ -238,7 +238,7 @@ ccxt/async_support/bitcoincom.py,sha256=NN_AWmT0tzikiwFDtf3aUqRXbgFTbdRIeL0kPbL5
238
238
  ccxt/async_support/bitfinex.py,sha256=H4Ujfun-VivWjlgWgWQl3jyLW_CnvLxyo67fRWXiQVk,166838
239
239
  ccxt/async_support/bitfinex1.py,sha256=mw8ecBPBiHFRHdQfQypCuhuPxx85-9E0CXnEoDMxUbI,74671
240
240
  ccxt/async_support/bitflyer.py,sha256=DoKSbGzqMRXt2d91fHG-DFd6ZuH0qIqzj9cYr0FyYCk,47214
241
- ccxt/async_support/bitget.py,sha256=a4ZmgxQ0BxFTVynthPQHiXkA3WSaIKK7qPq2bxWpzUs,446110
241
+ ccxt/async_support/bitget.py,sha256=gJVfyv5AnhnwDeYyo51aJ5Hn8JzL33ktoBWW1QlQ2FU,446221
242
242
  ccxt/async_support/bithumb.py,sha256=JUj5gTAtb71KlO-rpNOacV-m7isAzkjRfh3iS0JhSpY,50344
243
243
  ccxt/async_support/bitmart.py,sha256=D3Bw1wwe4FyAu3wcN-anuc5lklqZjuJPrTYGY2K5oSA,241953
244
244
  ccxt/async_support/bitmex.py,sha256=BG2V3EfAb0omoPnvfi3CcaWrernaMeJJ8WeEH2CiW1Y,132025
@@ -256,7 +256,7 @@ ccxt/async_support/btcalpha.py,sha256=KXc-Xl6ZeSwYkYYXPPMSQalbY-XwFCOvNCcVx9_qCZ
256
256
  ccxt/async_support/btcbox.py,sha256=bY4LZaCVh2eEyrHF0rRc65D8ws53oAcC0MqbJyU_odE,30258
257
257
  ccxt/async_support/btcmarkets.py,sha256=ByaubB2c6aGB5BQGi6mZq65EYHAWEEu7Tuoj9Kauucw,56179
258
258
  ccxt/async_support/btcturk.py,sha256=ox_4BvoFHyn8BJJTmJMX5-UB8tZt03KGAMMCqe8yUhE,39700
259
- ccxt/async_support/bybit.py,sha256=cIVghL16miJlN74gtnwa1KjkuBj3drZZbQ0g_CwEc20,433456
259
+ ccxt/async_support/bybit.py,sha256=WWHwGG5VwoDwxnIb4LFEFgL32L5Zz2VphIrWKLoJO9Y,433672
260
260
  ccxt/async_support/cex.py,sha256=dRHz1f0pW0JtjL7mMhU9TjrxJK-ttnAPa1B-tbpRBZM,72814
261
261
  ccxt/async_support/coinbase.py,sha256=iuA6M_QL2blA2TqZwCTl8n3fBLicJgqWZHIHhtTQTHI,231188
262
262
  ccxt/async_support/coinbaseadvanced.py,sha256=TnsUS2r5fvHIEfQmJh7J6Muyg8tPqDJphKYmK7gUQGE,591
@@ -285,7 +285,7 @@ ccxt/async_support/gateio.py,sha256=Sy9taiR0_0k4oh5GHjTjpwuCzskKiCCEQljuz7OxDVs,
285
285
  ccxt/async_support/gemini.py,sha256=5vYfQn8nk2geMmdGHU-_PvCO5PKYeMq3hoVLCdsrUjs,84105
286
286
  ccxt/async_support/hashkey.py,sha256=ouHE_QEZI4AMEcRNP1PMECQZ4PYN_Pnh7hOi0b6Ja0U,192581
287
287
  ccxt/async_support/hitbtc.py,sha256=qSpx8IRlwFSGEG971pboJroCfjRj0u2sZVtdWYveRbY,160356
288
- ccxt/async_support/hollaex.py,sha256=sDho1gE_uyNb2UPy80eiEdGpiDyK1gDSmd0sVNgd2Bo,79528
288
+ ccxt/async_support/hollaex.py,sha256=BV9mvkIadvhYBq5aExd2NSHqGQcAUz6a0mdaEfQ9E20,79532
289
289
  ccxt/async_support/htx.py,sha256=tofbGKEp8UJDvu2QUhlMLEvKX6UQxpE0v6nhvsRRxQc,445912
290
290
  ccxt/async_support/huobi.py,sha256=D4CTKw-2sl7iiX3yh7hMMkhBXHvQQ3to9_tW4WKm0rA,491
291
291
  ccxt/async_support/huobijp.py,sha256=i6Eb_r1K8xrVcmL-PG4bxmetseWxM0toUcKTkJ-aCfo,93412
@@ -310,7 +310,7 @@ ccxt/async_support/oceanex.py,sha256=_vi8sI3aucMmMPXwqqrpdfnWWHpfLYN_QaBpo2s9zvg
310
310
  ccxt/async_support/okcoin.py,sha256=zKUYe71ngQONUNvcUsk7LTt5OH9u0bWmf5xbmaQX2so,155274
311
311
  ccxt/async_support/okx.py,sha256=yf5JXeRS5DkqkI8Yhozm2NIlWuHFNdGTrSNdzM2u-AI,394544
312
312
  ccxt/async_support/onetrading.py,sha256=rHzlEI2JW61LbuNUtSZeICL7Pa71lwJthU8lJJn3O9M,76661
313
- ccxt/async_support/oxfun.py,sha256=7nfVtZ9GjpXhYTbUTdfv5fSklNr7pTKMXqy4Bp_VXyA,128043
313
+ ccxt/async_support/oxfun.py,sha256=Hd4A3Ym0UCoxINhjMuD_d19MP8K1Kkk7K6plK114e5k,128048
314
314
  ccxt/async_support/p2b.py,sha256=A_RPhOvbOMozI8Ypvw_Qzon5c6609l-fle3hYMT4j4w,56967
315
315
  ccxt/async_support/paradex.py,sha256=cNoBbTa3qFCQg5Avg0NpQJ1b3Lz-VQBMBhAfO9DjUP0,89526
316
316
  ccxt/async_support/paymium.py,sha256=RvV30CGIfKRRsttmdjRgbpNX0l92M8YzPkctlFqGs-M,26389
@@ -327,12 +327,12 @@ ccxt/async_support/wavesexchange.py,sha256=hUuCCBhpBraqWxFXmTfhjV51oUSRQQ0W4dR6x
327
327
  ccxt/async_support/whitebit.py,sha256=sXOLh3hmerQ144LfdRJ23WPrPSOhIQEosPy4we5HPqY,124590
328
328
  ccxt/async_support/woo.py,sha256=JwbO4M0lBIjRMAFOWMtyqCFtlA-QdNjlqSso63GXfjw,160364
329
329
  ccxt/async_support/woofipro.py,sha256=524-cOCsrsiMNooBgqZFVZG4I4SD_UOrTbDpOgYSGJM,121568
330
- ccxt/async_support/xt.py,sha256=aPBY2ZqbPPS-xqAw633egT43oT08nU2brzdR14CFOwM,212474
330
+ ccxt/async_support/xt.py,sha256=BJBfzPa_vMZkPCe7VNYSqHgsIJch4ZJTFvzKyFYH10k,213284
331
331
  ccxt/async_support/yobit.py,sha256=rv_uIgrPq53wmRQh80anwi1lv6ZUXl4QIDSvNSWA-Ro,58031
332
332
  ccxt/async_support/zaif.py,sha256=jZZv3ZjGQgkPNRfY5B5p5DNMvanHWTTS8m6BLBWm9tA,31357
333
333
  ccxt/async_support/zonda.py,sha256=2QL_B9CmBu4SU4K-Y8segpj57vzAd4aUT2H2cD3b07g,85320
334
334
  ccxt/async_support/base/__init__.py,sha256=aVYSsFi--b4InRs9zDN_wtCpj8odosAB726JdUHavrk,67
335
- ccxt/async_support/base/exchange.py,sha256=Pbbxx6REtlKYdGLlGKG8MBsRk77kgW104hYzI1t1cXc,116763
335
+ ccxt/async_support/base/exchange.py,sha256=KQvQnhK8OLRAmGG_Z560cvhd21mrke55ufbdBhmZeBU,116911
336
336
  ccxt/async_support/base/throttler.py,sha256=tvDVcdRUVYi8fZRlEcnqtgzcgB_KMUMRs5Pu8tuU-tU,1847
337
337
  ccxt/async_support/base/ws/__init__.py,sha256=uockzpLuwntKGZbs5EOWFe-Zg-k6Cj7GhNJLc_RX0so,1791
338
338
  ccxt/async_support/base/ws/aiohttp_client.py,sha256=Y5HxAVXyyYduj6b6SbbUZETlq3GrVMzrkW1r-TMgpb8,6329
@@ -346,10 +346,10 @@ ccxt/async_support/base/ws/order_book_side.py,sha256=GhnGUt78pJ-AYL_Dq9produGjmB
346
346
  ccxt/base/__init__.py,sha256=eTx1OE3HJjspFUQjGm6LBhaQiMKJnXjkdP-JUXknyQ0,1320
347
347
  ccxt/base/decimal_to_precision.py,sha256=fgWRBzRTtsf3r2INyS4f7WHlzgjB5YM1ekiwqD21aac,6634
348
348
  ccxt/base/errors.py,sha256=MvCrL_sAM3de616T6RE0PSxiF2xV6Qqz5b1y1ghidbk,4888
349
- ccxt/base/exchange.py,sha256=sD50mYjR6nLYq_tfa-5Ufw16xyDzjlm_xAn9mQlwGRc,318814
349
+ ccxt/base/exchange.py,sha256=cft8ezsceczVTY6TynPhMl2AP_BsEQJus9y9L2tgxKE,318992
350
350
  ccxt/base/precise.py,sha256=koce64Yrp6vFbGijJtUt-QQ6XhJgeGTCksZ871FPp_A,8886
351
351
  ccxt/base/types.py,sha256=asavKC4Fpuz9MGv1tJBld0j8CeojiP7nBj04Abusst4,10766
352
- ccxt/pro/__init__.py,sha256=sF9yea8HJ1-FZ6Eg2r6uOJeYWGSae9E1nSaXz5jeSE4,8023
352
+ ccxt/pro/__init__.py,sha256=7MNWko7piP273gCsAhOfhErrN02sOwSbGpuzPXZnzfI,8023
353
353
  ccxt/pro/alpaca.py,sha256=_WEorh5thYhvhn7R8hBvHW2m1P2foIbp8URjIt_9vcg,27623
354
354
  ccxt/pro/ascendex.py,sha256=P6a81iK_T6uyEK6JHcNQbjJwLvurrUeQVoQqvp2_IU8,37512
355
355
  ccxt/pro/bequant.py,sha256=reG2yXBhxn_TuOIg4J2BiLxl8Lw5Lag3IBMGBkiQCd0,1591
@@ -424,7 +424,7 @@ ccxt/pro/wazirx.py,sha256=7CJiHZX2AkB199CZv-gG-YZfD_M4n29un_TD8ixryeo,30231
424
424
  ccxt/pro/whitebit.py,sha256=JwzgvKemz15MKDe0KWY7DMELqVCNL1HDNw39DXpVL_Q,37020
425
425
  ccxt/pro/woo.py,sha256=X-7FKlqxakkXnWW_dA2z2Pk1z1Vcmws_gwreoxlfQ8M,51553
426
426
  ccxt/pro/woofipro.py,sha256=O8o5Jv4dujemKJoov8Gg4LiK9RBzPNeP3pA4XeUtRQE,51713
427
- ccxt/pro/xt.py,sha256=RrB9Up-3nu-kUgwH4GfRoZ__coLnsy1TRw2ObX6z_bk,48287
427
+ ccxt/pro/xt.py,sha256=HOpHgCwQvytxoJZTpSOV93BCkHNIZPjxFbyGEYZxBJc,53011
428
428
  ccxt/static_dependencies/__init__.py,sha256=tzFje8cloqmiIE6kola3EaYC0SnD1izWnri69hzHsSw,168
429
429
  ccxt/static_dependencies/ecdsa/__init__.py,sha256=Xaj0G79BLtBt2YZcOOMV8qOlQZ7fIJznNiHhiEEZfQA,594
430
430
  ccxt/static_dependencies/ecdsa/_version.py,sha256=eMIr0XQiX8_th_x4iAd0JFcYKLowY9dYz33-vKVFIPI,18461
@@ -652,12 +652,12 @@ ccxt/static_dependencies/toolz/curried/operator.py,sha256=ML92mknkAwzBl2NCm-4wer
652
652
  ccxt/static_dependencies/typing_inspect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
653
653
  ccxt/static_dependencies/typing_inspect/typing_inspect.py,sha256=5gIWomLPfuDpgd3gX1GlnX0MuXM3VorR4j2W2qXORiQ,28269
654
654
  ccxt/test/__init__.py,sha256=GKPbEcj0Rrz5HG-GUm-iY1IHhDYmlvcBXZAGk6-m2CI,141
655
- ccxt/test/tests_async.py,sha256=ZdM4VC9oTluH5CHv73shLK5U-nDDi_T1ZFLp1KJY5DE,89108
655
+ ccxt/test/tests_async.py,sha256=50VEDk5smqAlKOVzBJiAAXvwaVnJ3DjAqlx0oQGM694,90044
656
656
  ccxt/test/tests_helpers.py,sha256=egM69A2ZFYeVF5hwC1Qt-c5DOeClY5bv4jowmceeFV8,9736
657
657
  ccxt/test/tests_init.py,sha256=YitIlzsc-FQvtc6lZVPKlGcYYTJ2ezSDd2GCOxdoBnY,1164
658
- ccxt/test/tests_sync.py,sha256=iJ7h9p7qovC3BZ07bsVlzlVB6GW2TsKXTIr3f6l3ABM,88134
659
- ccxt-4.4.59.dist-info/LICENSE.txt,sha256=EIb9221AhMHV7xF1_55STFdKTFsnJVJYkRpY2Lnvo5w,1068
660
- ccxt-4.4.59.dist-info/METADATA,sha256=dtfATADQysRHDe8h4e3X5rB5wN4v3CbzyBKJqVz-xok,130334
661
- ccxt-4.4.59.dist-info/WHEEL,sha256=Kh9pAotZVRFj97E15yTA4iADqXdQfIVTHcNaZTjxeGM,110
662
- ccxt-4.4.59.dist-info/top_level.txt,sha256=CkQDuCTDKNcImPV60t36G6MdYfxsAPNiSaEwifVoVMo,5
663
- ccxt-4.4.59.dist-info/RECORD,,
658
+ ccxt/test/tests_sync.py,sha256=7e4M2yPC35AltBIMXnqnBss7T8VQttP51GTveG6E7Mg,89070
659
+ ccxt-4.4.60.dist-info/LICENSE.txt,sha256=EIb9221AhMHV7xF1_55STFdKTFsnJVJYkRpY2Lnvo5w,1068
660
+ ccxt-4.4.60.dist-info/METADATA,sha256=aVywAj-UYWqq2goJNMmu--fqRNsYuZbPGHsPRrvHVgY,130334
661
+ ccxt-4.4.60.dist-info/WHEEL,sha256=Kh9pAotZVRFj97E15yTA4iADqXdQfIVTHcNaZTjxeGM,110
662
+ ccxt-4.4.60.dist-info/top_level.txt,sha256=CkQDuCTDKNcImPV60t36G6MdYfxsAPNiSaEwifVoVMo,5
663
+ ccxt-4.4.60.dist-info/RECORD,,
File without changes