ccxt 4.4.18__py2.py3-none-any.whl → 4.4.20__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.18'
25
+ __version__ = '4.4.20'
26
26
 
27
27
  # ----------------------------------------------------------------------------
28
28
 
ccxt/abstract/binance.py CHANGED
@@ -482,6 +482,7 @@ class ImplicitAPI:
482
482
  fapipublic_get_constituents = fapiPublicGetConstituents = Entry('constituents', 'fapiPublic', 'GET', {'cost': 2})
483
483
  fapipublic_get_apitradingstatus = fapiPublicGetApiTradingStatus = Entry('apiTradingStatus', 'fapiPublic', 'GET', {'cost': 1, 'noSymbol': 10})
484
484
  fapipublic_get_lvtklines = fapiPublicGetLvtKlines = Entry('lvtKlines', 'fapiPublic', 'GET', {'cost': 1})
485
+ fapipublic_get_convert_exchangeinfo = fapiPublicGetConvertExchangeInfo = Entry('convert/exchangeInfo', 'fapiPublic', 'GET', {'cost': 4})
485
486
  fapidata_get_delivery_price = fapiDataGetDeliveryPrice = Entry('delivery-price', 'fapiData', 'GET', {'cost': 1})
486
487
  fapidata_get_openinteresthist = fapiDataGetOpenInterestHist = Entry('openInterestHist', 'fapiData', 'GET', {'cost': 1})
487
488
  fapidata_get_toplongshortaccountratio = fapiDataGetTopLongShortAccountRatio = Entry('topLongShortAccountRatio', 'fapiData', 'GET', {'cost': 1})
@@ -526,6 +527,7 @@ class ImplicitAPI:
526
527
  fapiprivate_get_feeburn = fapiPrivateGetFeeBurn = Entry('feeBurn', 'fapiPrivate', 'GET', {'cost': 1})
527
528
  fapiprivate_get_symbolconfig = fapiPrivateGetSymbolConfig = Entry('symbolConfig', 'fapiPrivate', 'GET', {'cost': 5})
528
529
  fapiprivate_get_accountconfig = fapiPrivateGetAccountConfig = Entry('accountConfig', 'fapiPrivate', 'GET', {'cost': 5})
530
+ fapiprivate_get_convert_orderstatus = fapiPrivateGetConvertOrderStatus = Entry('convert/orderStatus', 'fapiPrivate', 'GET', {'cost': 5})
529
531
  fapiprivate_post_batchorders = fapiPrivatePostBatchOrders = Entry('batchOrders', 'fapiPrivate', 'POST', {'cost': 5})
530
532
  fapiprivate_post_positionside_dual = fapiPrivatePostPositionSideDual = Entry('positionSide/dual', 'fapiPrivate', 'POST', {'cost': 1})
531
533
  fapiprivate_post_positionmargin = fapiPrivatePostPositionMargin = Entry('positionMargin', 'fapiPrivate', 'POST', {'cost': 1})
@@ -538,6 +540,8 @@ class ImplicitAPI:
538
540
  fapiprivate_post_apireferral_customization = fapiPrivatePostApiReferralCustomization = Entry('apiReferral/customization', 'fapiPrivate', 'POST', {'cost': 1})
539
541
  fapiprivate_post_apireferral_usercustomization = fapiPrivatePostApiReferralUserCustomization = Entry('apiReferral/userCustomization', 'fapiPrivate', 'POST', {'cost': 1})
540
542
  fapiprivate_post_feeburn = fapiPrivatePostFeeBurn = Entry('feeBurn', 'fapiPrivate', 'POST', {'cost': 1})
543
+ fapiprivate_post_convert_getquote = fapiPrivatePostConvertGetQuote = Entry('convert/getQuote', 'fapiPrivate', 'POST', {'cost': 200})
544
+ fapiprivate_post_convert_acceptquote = fapiPrivatePostConvertAcceptQuote = Entry('convert/acceptQuote', 'fapiPrivate', 'POST', {'cost': 20})
541
545
  fapiprivate_put_listenkey = fapiPrivatePutListenKey = Entry('listenKey', 'fapiPrivate', 'PUT', {'cost': 1})
542
546
  fapiprivate_put_order = fapiPrivatePutOrder = Entry('order', 'fapiPrivate', 'PUT', {'cost': 1})
543
547
  fapiprivate_put_batchorders = fapiPrivatePutBatchOrders = Entry('batchOrders', 'fapiPrivate', 'PUT', {'cost': 5})
@@ -482,6 +482,7 @@ class ImplicitAPI:
482
482
  fapipublic_get_constituents = fapiPublicGetConstituents = Entry('constituents', 'fapiPublic', 'GET', {'cost': 2})
483
483
  fapipublic_get_apitradingstatus = fapiPublicGetApiTradingStatus = Entry('apiTradingStatus', 'fapiPublic', 'GET', {'cost': 1, 'noSymbol': 10})
484
484
  fapipublic_get_lvtklines = fapiPublicGetLvtKlines = Entry('lvtKlines', 'fapiPublic', 'GET', {'cost': 1})
485
+ fapipublic_get_convert_exchangeinfo = fapiPublicGetConvertExchangeInfo = Entry('convert/exchangeInfo', 'fapiPublic', 'GET', {'cost': 4})
485
486
  fapidata_get_delivery_price = fapiDataGetDeliveryPrice = Entry('delivery-price', 'fapiData', 'GET', {'cost': 1})
486
487
  fapidata_get_openinteresthist = fapiDataGetOpenInterestHist = Entry('openInterestHist', 'fapiData', 'GET', {'cost': 1})
487
488
  fapidata_get_toplongshortaccountratio = fapiDataGetTopLongShortAccountRatio = Entry('topLongShortAccountRatio', 'fapiData', 'GET', {'cost': 1})
@@ -526,6 +527,7 @@ class ImplicitAPI:
526
527
  fapiprivate_get_feeburn = fapiPrivateGetFeeBurn = Entry('feeBurn', 'fapiPrivate', 'GET', {'cost': 1})
527
528
  fapiprivate_get_symbolconfig = fapiPrivateGetSymbolConfig = Entry('symbolConfig', 'fapiPrivate', 'GET', {'cost': 5})
528
529
  fapiprivate_get_accountconfig = fapiPrivateGetAccountConfig = Entry('accountConfig', 'fapiPrivate', 'GET', {'cost': 5})
530
+ fapiprivate_get_convert_orderstatus = fapiPrivateGetConvertOrderStatus = Entry('convert/orderStatus', 'fapiPrivate', 'GET', {'cost': 5})
529
531
  fapiprivate_post_batchorders = fapiPrivatePostBatchOrders = Entry('batchOrders', 'fapiPrivate', 'POST', {'cost': 5})
530
532
  fapiprivate_post_positionside_dual = fapiPrivatePostPositionSideDual = Entry('positionSide/dual', 'fapiPrivate', 'POST', {'cost': 1})
531
533
  fapiprivate_post_positionmargin = fapiPrivatePostPositionMargin = Entry('positionMargin', 'fapiPrivate', 'POST', {'cost': 1})
@@ -538,6 +540,8 @@ class ImplicitAPI:
538
540
  fapiprivate_post_apireferral_customization = fapiPrivatePostApiReferralCustomization = Entry('apiReferral/customization', 'fapiPrivate', 'POST', {'cost': 1})
539
541
  fapiprivate_post_apireferral_usercustomization = fapiPrivatePostApiReferralUserCustomization = Entry('apiReferral/userCustomization', 'fapiPrivate', 'POST', {'cost': 1})
540
542
  fapiprivate_post_feeburn = fapiPrivatePostFeeBurn = Entry('feeBurn', 'fapiPrivate', 'POST', {'cost': 1})
543
+ fapiprivate_post_convert_getquote = fapiPrivatePostConvertGetQuote = Entry('convert/getQuote', 'fapiPrivate', 'POST', {'cost': 200})
544
+ fapiprivate_post_convert_acceptquote = fapiPrivatePostConvertAcceptQuote = Entry('convert/acceptQuote', 'fapiPrivate', 'POST', {'cost': 20})
541
545
  fapiprivate_put_listenkey = fapiPrivatePutListenKey = Entry('listenKey', 'fapiPrivate', 'PUT', {'cost': 1})
542
546
  fapiprivate_put_order = fapiPrivatePutOrder = Entry('order', 'fapiPrivate', 'PUT', {'cost': 1})
543
547
  fapiprivate_put_batchorders = fapiPrivatePutBatchOrders = Entry('batchOrders', 'fapiPrivate', 'PUT', {'cost': 5})
@@ -534,6 +534,7 @@ class ImplicitAPI:
534
534
  fapipublic_get_constituents = fapiPublicGetConstituents = Entry('constituents', 'fapiPublic', 'GET', {'cost': 2})
535
535
  fapipublic_get_apitradingstatus = fapiPublicGetApiTradingStatus = Entry('apiTradingStatus', 'fapiPublic', 'GET', {'cost': 1, 'noSymbol': 10})
536
536
  fapipublic_get_lvtklines = fapiPublicGetLvtKlines = Entry('lvtKlines', 'fapiPublic', 'GET', {'cost': 1})
537
+ fapipublic_get_convert_exchangeinfo = fapiPublicGetConvertExchangeInfo = Entry('convert/exchangeInfo', 'fapiPublic', 'GET', {'cost': 4})
537
538
  fapidata_get_delivery_price = fapiDataGetDeliveryPrice = Entry('delivery-price', 'fapiData', 'GET', {'cost': 1})
538
539
  fapidata_get_openinteresthist = fapiDataGetOpenInterestHist = Entry('openInterestHist', 'fapiData', 'GET', {'cost': 1})
539
540
  fapidata_get_toplongshortaccountratio = fapiDataGetTopLongShortAccountRatio = Entry('topLongShortAccountRatio', 'fapiData', 'GET', {'cost': 1})
@@ -578,6 +579,7 @@ class ImplicitAPI:
578
579
  fapiprivate_get_feeburn = fapiPrivateGetFeeBurn = Entry('feeBurn', 'fapiPrivate', 'GET', {'cost': 1})
579
580
  fapiprivate_get_symbolconfig = fapiPrivateGetSymbolConfig = Entry('symbolConfig', 'fapiPrivate', 'GET', {'cost': 5})
580
581
  fapiprivate_get_accountconfig = fapiPrivateGetAccountConfig = Entry('accountConfig', 'fapiPrivate', 'GET', {'cost': 5})
582
+ fapiprivate_get_convert_orderstatus = fapiPrivateGetConvertOrderStatus = Entry('convert/orderStatus', 'fapiPrivate', 'GET', {'cost': 5})
581
583
  fapiprivate_post_batchorders = fapiPrivatePostBatchOrders = Entry('batchOrders', 'fapiPrivate', 'POST', {'cost': 5})
582
584
  fapiprivate_post_positionside_dual = fapiPrivatePostPositionSideDual = Entry('positionSide/dual', 'fapiPrivate', 'POST', {'cost': 1})
583
585
  fapiprivate_post_positionmargin = fapiPrivatePostPositionMargin = Entry('positionMargin', 'fapiPrivate', 'POST', {'cost': 1})
@@ -590,6 +592,8 @@ class ImplicitAPI:
590
592
  fapiprivate_post_apireferral_customization = fapiPrivatePostApiReferralCustomization = Entry('apiReferral/customization', 'fapiPrivate', 'POST', {'cost': 1})
591
593
  fapiprivate_post_apireferral_usercustomization = fapiPrivatePostApiReferralUserCustomization = Entry('apiReferral/userCustomization', 'fapiPrivate', 'POST', {'cost': 1})
592
594
  fapiprivate_post_feeburn = fapiPrivatePostFeeBurn = Entry('feeBurn', 'fapiPrivate', 'POST', {'cost': 1})
595
+ fapiprivate_post_convert_getquote = fapiPrivatePostConvertGetQuote = Entry('convert/getQuote', 'fapiPrivate', 'POST', {'cost': 200})
596
+ fapiprivate_post_convert_acceptquote = fapiPrivatePostConvertAcceptQuote = Entry('convert/acceptQuote', 'fapiPrivate', 'POST', {'cost': 20})
593
597
  fapiprivate_put_listenkey = fapiPrivatePutListenKey = Entry('listenKey', 'fapiPrivate', 'PUT', {'cost': 1})
594
598
  fapiprivate_put_order = fapiPrivatePutOrder = Entry('order', 'fapiPrivate', 'PUT', {'cost': 1})
595
599
  fapiprivate_put_batchorders = fapiPrivatePutBatchOrders = Entry('batchOrders', 'fapiPrivate', 'PUT', {'cost': 5})
@@ -482,6 +482,7 @@ class ImplicitAPI:
482
482
  fapipublic_get_constituents = fapiPublicGetConstituents = Entry('constituents', 'fapiPublic', 'GET', {'cost': 2})
483
483
  fapipublic_get_apitradingstatus = fapiPublicGetApiTradingStatus = Entry('apiTradingStatus', 'fapiPublic', 'GET', {'cost': 1, 'noSymbol': 10})
484
484
  fapipublic_get_lvtklines = fapiPublicGetLvtKlines = Entry('lvtKlines', 'fapiPublic', 'GET', {'cost': 1})
485
+ fapipublic_get_convert_exchangeinfo = fapiPublicGetConvertExchangeInfo = Entry('convert/exchangeInfo', 'fapiPublic', 'GET', {'cost': 4})
485
486
  fapidata_get_delivery_price = fapiDataGetDeliveryPrice = Entry('delivery-price', 'fapiData', 'GET', {'cost': 1})
486
487
  fapidata_get_openinteresthist = fapiDataGetOpenInterestHist = Entry('openInterestHist', 'fapiData', 'GET', {'cost': 1})
487
488
  fapidata_get_toplongshortaccountratio = fapiDataGetTopLongShortAccountRatio = Entry('topLongShortAccountRatio', 'fapiData', 'GET', {'cost': 1})
@@ -526,6 +527,7 @@ class ImplicitAPI:
526
527
  fapiprivate_get_feeburn = fapiPrivateGetFeeBurn = Entry('feeBurn', 'fapiPrivate', 'GET', {'cost': 1})
527
528
  fapiprivate_get_symbolconfig = fapiPrivateGetSymbolConfig = Entry('symbolConfig', 'fapiPrivate', 'GET', {'cost': 5})
528
529
  fapiprivate_get_accountconfig = fapiPrivateGetAccountConfig = Entry('accountConfig', 'fapiPrivate', 'GET', {'cost': 5})
530
+ fapiprivate_get_convert_orderstatus = fapiPrivateGetConvertOrderStatus = Entry('convert/orderStatus', 'fapiPrivate', 'GET', {'cost': 5})
529
531
  fapiprivate_post_batchorders = fapiPrivatePostBatchOrders = Entry('batchOrders', 'fapiPrivate', 'POST', {'cost': 5})
530
532
  fapiprivate_post_positionside_dual = fapiPrivatePostPositionSideDual = Entry('positionSide/dual', 'fapiPrivate', 'POST', {'cost': 1})
531
533
  fapiprivate_post_positionmargin = fapiPrivatePostPositionMargin = Entry('positionMargin', 'fapiPrivate', 'POST', {'cost': 1})
@@ -538,6 +540,8 @@ class ImplicitAPI:
538
540
  fapiprivate_post_apireferral_customization = fapiPrivatePostApiReferralCustomization = Entry('apiReferral/customization', 'fapiPrivate', 'POST', {'cost': 1})
539
541
  fapiprivate_post_apireferral_usercustomization = fapiPrivatePostApiReferralUserCustomization = Entry('apiReferral/userCustomization', 'fapiPrivate', 'POST', {'cost': 1})
540
542
  fapiprivate_post_feeburn = fapiPrivatePostFeeBurn = Entry('feeBurn', 'fapiPrivate', 'POST', {'cost': 1})
543
+ fapiprivate_post_convert_getquote = fapiPrivatePostConvertGetQuote = Entry('convert/getQuote', 'fapiPrivate', 'POST', {'cost': 200})
544
+ fapiprivate_post_convert_acceptquote = fapiPrivatePostConvertAcceptQuote = Entry('convert/acceptQuote', 'fapiPrivate', 'POST', {'cost': 20})
541
545
  fapiprivate_put_listenkey = fapiPrivatePutListenKey = Entry('listenKey', 'fapiPrivate', 'PUT', {'cost': 1})
542
546
  fapiprivate_put_order = fapiPrivatePutOrder = Entry('order', 'fapiPrivate', 'PUT', {'cost': 1})
543
547
  fapiprivate_put_batchorders = fapiPrivatePutBatchOrders = Entry('batchOrders', 'fapiPrivate', 'PUT', {'cost': 5})
@@ -219,6 +219,7 @@ class ImplicitAPI:
219
219
  futuresprivate_delete_withdrawals_withdrawalid = futuresPrivateDeleteWithdrawalsWithdrawalId = Entry('withdrawals/{withdrawalId}', 'futuresPrivate', 'DELETE', {'cost': 1})
220
220
  futuresprivate_delete_cancel_transfer_out = futuresPrivateDeleteCancelTransferOut = Entry('cancel/transfer-out', 'futuresPrivate', 'DELETE', {'cost': 1})
221
221
  futuresprivate_delete_sub_api_key = futuresPrivateDeleteSubApiKey = Entry('sub/api-key', 'futuresPrivate', 'DELETE', {'cost': 1})
222
+ futuresprivate_delete_orders_multi_cancel = futuresPrivateDeleteOrdersMultiCancel = Entry('orders/multi-cancel', 'futuresPrivate', 'DELETE', {'cost': 20})
222
223
  webexchange_get_currency_currency_chain_info = webExchangeGetCurrencyCurrencyChainInfo = Entry('currency/currency/chain-info', 'webExchange', 'GET', {'cost': 1})
223
224
  webexchange_get_contract_symbol_funding_rates = webExchangeGetContractSymbolFundingRates = Entry('contract/{symbol}/funding-rates', 'webExchange', 'GET', {'cost': 1})
224
225
  broker_get_broker_nd_info = brokerGetBrokerNdInfo = Entry('broker/nd/info', 'broker', 'GET', {'cost': 2})
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.18'
7
+ __version__ = '4.4.20'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  # -----------------------------------------------------------------------------
4
4
 
5
- __version__ = '4.4.18'
5
+ __version__ = '4.4.20'
6
6
 
7
7
  # -----------------------------------------------------------------------------
8
8
 
@@ -1908,6 +1908,8 @@ class Exchange(BaseExchange):
1908
1908
  i = 0
1909
1909
  errors = 0
1910
1910
  result = []
1911
+ timeframe = self.safe_string(params, 'timeframe')
1912
+ params = self.omit(params, 'timeframe') # reading the timeframe from the method arguments to avoid changing the signature
1911
1913
  while(i < maxCalls):
1912
1914
  try:
1913
1915
  if cursorValue is not None:
@@ -1919,6 +1921,8 @@ class Exchange(BaseExchange):
1919
1921
  response = await getattr(self, method)(params)
1920
1922
  elif method == 'getLeverageTiersPaginated' or method == 'fetchPositions':
1921
1923
  response = await getattr(self, method)(symbol, params)
1924
+ elif method == 'fetchOpenInterestHistory':
1925
+ response = await getattr(self, method)(symbol, timeframe, since, maxEntriesPerRequest, params)
1922
1926
  else:
1923
1927
  response = await getattr(self, method)(symbol, since, maxEntriesPerRequest, params)
1924
1928
  errors = 0
@@ -828,6 +828,7 @@ class binance(Exchange, ImplicitAPI):
828
828
  'constituents': 2,
829
829
  'apiTradingStatus': {'cost': 1, 'noSymbol': 10},
830
830
  'lvtKlines': 1,
831
+ 'convert/exchangeInfo': 4,
831
832
  },
832
833
  },
833
834
  'fapiData': {
@@ -881,6 +882,7 @@ class binance(Exchange, ImplicitAPI):
881
882
  'feeBurn': 1,
882
883
  'symbolConfig': 5,
883
884
  'accountConfig': 5,
885
+ 'convert/orderStatus': 5,
884
886
  },
885
887
  'post': {
886
888
  'batchOrders': 5,
@@ -896,6 +898,8 @@ class binance(Exchange, ImplicitAPI):
896
898
  'apiReferral/customization': 1,
897
899
  'apiReferral/userCustomization': 1,
898
900
  'feeBurn': 1,
901
+ 'convert/getQuote': 200, # 360 requests per hour
902
+ 'convert/acceptQuote': 20,
899
903
  },
900
904
  'put': {
901
905
  'listenKey': 1,
@@ -3162,14 +3166,15 @@ class binance(Exchange, ImplicitAPI):
3162
3166
  fees = self.fees
3163
3167
  linear = None
3164
3168
  inverse = None
3165
- strike = self.safe_string(market, 'strikePrice')
3166
3169
  symbol = base + '/' + quote
3170
+ strike = None
3167
3171
  if contract:
3168
3172
  if swap:
3169
3173
  symbol = symbol + ':' + settle
3170
3174
  elif future:
3171
3175
  symbol = symbol + ':' + settle + '-' + self.yymmdd(expiry)
3172
3176
  elif option:
3177
+ strike = self.number_to_string(self.parse_to_numeric(self.safe_string(market, 'strikePrice')))
3173
3178
  symbol = symbol + ':' + settle + '-' + self.yymmdd(expiry) + '-' + strike + '-' + self.safe_string(optionParts, 3)
3174
3179
  contractSize = self.safe_number_2(market, 'contractSize', 'unit', self.parse_number('1'))
3175
3180
  linear = settle == quote
@@ -5947,11 +5952,21 @@ class binance(Exchange, ImplicitAPI):
5947
5952
  if isPortfolioMargin:
5948
5953
  request['quantity'] = self.parse_to_numeric(amount)
5949
5954
  else:
5950
- request['quantity'] = self.amount_to_precision(symbol, amount)
5955
+ marketAmountPrecision = self.safe_string(market['precision'], 'amount')
5956
+ isPrecisionAvailable = (marketAmountPrecision is not None)
5957
+ if isPrecisionAvailable:
5958
+ request['quantity'] = self.amount_to_precision(symbol, amount)
5959
+ else:
5960
+ request['quantity'] = self.parse_to_numeric(amount) # some options don't have the precision available
5951
5961
  if priceIsRequired and not isPriceMatch:
5952
5962
  if price is None:
5953
5963
  raise InvalidOrder(self.id + ' createOrder() requires a price argument for a ' + type + ' order')
5954
- request['price'] = self.price_to_precision(symbol, price)
5964
+ pricePrecision = self.safe_string(market['precision'], 'price')
5965
+ isPricePrecisionAvailable = (pricePrecision is not None)
5966
+ if isPricePrecisionAvailable:
5967
+ request['price'] = self.price_to_precision(symbol, price)
5968
+ else:
5969
+ request['price'] = self.parse_to_numeric(price) # some options don't have the precision available
5955
5970
  if stopPriceIsRequired:
5956
5971
  if market['contract']:
5957
5972
  if stopPrice is None:
@@ -509,6 +509,7 @@ class bingx(Exchange, ImplicitAPI):
509
509
  },
510
510
  'networks': {
511
511
  'ARB': 'ARBITRUM',
512
+ 'MATIC': 'POLYGON',
512
513
  },
513
514
  },
514
515
  })
@@ -772,7 +773,7 @@ class bingx(Exchange, ImplicitAPI):
772
773
  isActive = False
773
774
  if (self.safe_string(market, 'apiStateOpen') == 'true') and (self.safe_string(market, 'apiStateClose') == 'true'):
774
775
  isActive = True # swap active
775
- elif self.safe_bool(market, 'apiStateSell') and self.safe_bool(market, 'apiStateBuy') and (self.safe_number(market, 'status') == 1):
776
+ elif self.safe_bool(market, 'apiStateSell') and self.safe_bool(market, 'apiStateBuy') and (self.safe_string(market, 'status') == '1'):
776
777
  isActive = True # spot active
777
778
  isInverse = None if (spot) else checkIsInverse
778
779
  isLinear = None if (spot) else checkIsLinear
@@ -1445,7 +1445,7 @@ class bitget(Exchange, ImplicitAPI):
1445
1445
  'ARB': 'ArbitrumOne',
1446
1446
  'ZKSYNC': 'zkSyncEra',
1447
1447
  'STARKNET': 'Starknet',
1448
- 'APT': 'APTOS',
1448
+ 'APT': 'Aptos',
1449
1449
  'MATIC': 'Polygon',
1450
1450
  'VIC': 'VICTION',
1451
1451
  'AVAXC': 'C-Chain',
@@ -6703,7 +6703,8 @@ class bybit(Exchange, ImplicitAPI):
6703
6703
  paginate = self.safe_bool(params, 'paginate')
6704
6704
  if paginate:
6705
6705
  params = self.omit(params, 'paginate')
6706
- return await self.fetch_paginated_call_deterministic('fetchOpenInterestHistory', symbol, since, limit, timeframe, params, 500)
6706
+ params['timeframe'] = timeframe
6707
+ return await self.fetch_paginated_call_cursor('fetchOpenInterestHistory', symbol, since, limit, params, 'nextPageCursor', 'cursor', None, 200)
6707
6708
  market = self.market(symbol)
6708
6709
  if market['spot'] or market['option']:
6709
6710
  raise BadRequest(self.id + ' fetchOpenInterestHistory() symbol does not support market ' + symbol)
@@ -4421,6 +4421,7 @@ class gate(Exchange, ImplicitAPI):
4421
4421
  """
4422
4422
  fetch all unfilled currently open orders
4423
4423
  :see: https://www.gate.io/docs/developers/apiv4/en/#list-all-open-orders
4424
+ :see: https://www.gate.io/docs/developers/apiv4/en/#retrieve-running-auto-order-list
4424
4425
  :param str symbol: unified market symbol
4425
4426
  :param int [since]: the earliest time in ms to fetch open orders for
4426
4427
  :param int [limit]: the maximum number of open orders structures to retrieve
ccxt/async_support/htx.py CHANGED
@@ -1254,6 +1254,16 @@ class htx(Exchange, ImplicitAPI):
1254
1254
  })
1255
1255
 
1256
1256
  async def fetch_status(self, params={}):
1257
+ """
1258
+ the latest known information on the availability of the exchange API
1259
+ :see: https://huobiapi.github.io/docs/spot/v1/en/#get-system-status
1260
+ :see: https://huobiapi.github.io/docs/dm/v1/en/#get-system-status
1261
+ :see: https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-system-status
1262
+ :see: https://huobiapi.github.io/docs/usdt_swap/v1/en/#get-system-status
1263
+ :see: https://huobiapi.github.io/docs/usdt_swap/v1/en/#query-whether-the-system-is-available # contractPublicGetHeartbeat
1264
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1265
+ :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
1266
+ """
1257
1267
  await self.load_markets()
1258
1268
  marketType = None
1259
1269
  marketType, params = self.handle_market_type_and_params('fetchStatus', None, params)
@@ -1465,6 +1475,8 @@ class htx(Exchange, ImplicitAPI):
1465
1475
  async def fetch_time(self, params={}):
1466
1476
  """
1467
1477
  fetches the current integer timestamp in milliseconds from the exchange server
1478
+ :see: https://huobiapi.github.io/docs/spot/v1/en/#get-current-timestamp
1479
+ :see: https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-current-system-timestamp
1468
1480
  :param dict [params]: extra parameters specific to the exchange API endpoint
1469
1481
  :returns int: the current integer timestamp in milliseconds from the exchange server
1470
1482
  """
@@ -1511,6 +1523,7 @@ class htx(Exchange, ImplicitAPI):
1511
1523
  async def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
1512
1524
  """
1513
1525
  fetch the trading fees for a market
1526
+ :see: https://huobiapi.github.io/docs/spot/v1/en/#get-current-fee-rate-applied-to-the-user
1514
1527
  :param str symbol: unified market symbol
1515
1528
  :param dict [params]: extra parameters specific to the exchange API endpoint
1516
1529
  :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
@@ -1554,6 +1567,13 @@ class htx(Exchange, ImplicitAPI):
1554
1567
  return result
1555
1568
 
1556
1569
  async def fetch_trading_limits_by_id(self, id: str, params={}):
1570
+ """
1571
+ * @ignore
1572
+ :see: https://huobiapi.github.io/docs/spot/v1/en/#get-current-fee-rate-applied-to-the-user
1573
+ :param str id: market id
1574
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1575
+ :returns dict: the limits object of a market structure
1576
+ """
1557
1577
  request: dict = {
1558
1578
  'symbol': id,
1559
1579
  }
@@ -1880,6 +1880,10 @@ class hyperliquid(Exchange, ImplicitAPI):
1880
1880
  statuses: dict = {
1881
1881
  'triggered': 'open',
1882
1882
  'filled': 'closed',
1883
+ 'open': 'open',
1884
+ 'canceled': 'canceled',
1885
+ 'rejected': 'rejected',
1886
+ 'marginCanceled': 'canceled',
1883
1887
  }
1884
1888
  return self.safe_string(statuses, status, status)
1885
1889
 
@@ -4725,7 +4725,7 @@ class kucoin(Exchange, ImplicitAPI):
4725
4725
  headers = headers if (headers is not None) else {}
4726
4726
  url = self.urls['api'][api]
4727
4727
  if not self.is_empty(query):
4728
- if (method == 'GET') or (method == 'DELETE'):
4728
+ if ((method == 'GET') or (method == 'DELETE')) and (path != 'orders/multi-cancel'):
4729
4729
  endpoint += '?' + self.rawencode(query)
4730
4730
  else:
4731
4731
  body = self.json(query)
@@ -46,6 +46,7 @@ class kucoinfutures(kucoin, ImplicitAPI):
46
46
  'addMargin': True,
47
47
  'cancelAllOrders': True,
48
48
  'cancelOrder': True,
49
+ 'cancelOrders': True,
49
50
  'closeAllPositions': False,
50
51
  'closePosition': True,
51
52
  'closePositions': False,
@@ -217,6 +218,7 @@ class kucoinfutures(kucoin, ImplicitAPI):
217
218
  'stopOrders': 1,
218
219
  'sub/api-key': 1,
219
220
  'orders/client-order/{clientOid}': 1,
221
+ 'orders/multi-cancel': 20,
220
222
  },
221
223
  },
222
224
  'webExchange': {
@@ -1584,6 +1586,61 @@ class kucoinfutures(kucoin, ImplicitAPI):
1584
1586
  #
1585
1587
  return self.safe_value(response, 'data')
1586
1588
 
1589
+ async def cancel_orders(self, ids, symbol: Str = None, params={}):
1590
+ """
1591
+ cancel multiple orders
1592
+ :see: https://www.kucoin.com/docs/rest/futures-trading/orders/batch-cancel-orders
1593
+ :param str[] ids: order ids
1594
+ :param str symbol: unified symbol of the market the order was made in
1595
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1596
+ :param str[] [params.clientOrderIds]: client order ids
1597
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1598
+ """
1599
+ await self.load_markets()
1600
+ market = None
1601
+ if symbol is not None:
1602
+ market = self.market(symbol)
1603
+ ordersRequests = []
1604
+ clientOrderIds = self.safe_list_2(params, 'clientOrderIds', 'clientOids', [])
1605
+ params = self.omit(params, ['clientOrderIds', 'clientOids'])
1606
+ useClientorderId = False
1607
+ for i in range(0, len(clientOrderIds)):
1608
+ useClientorderId = True
1609
+ if symbol is None:
1610
+ raise ArgumentsRequired(self.id + ' cancelOrders() requires a symbol argument when cancelling by clientOrderIds')
1611
+ ordersRequests.append({
1612
+ 'symbol': market['id'],
1613
+ 'clientOid': self.safe_string(clientOrderIds, i),
1614
+ })
1615
+ for i in range(0, len(ids)):
1616
+ ordersRequests.append(ids[i])
1617
+ requestKey = 'clientOidsList' if useClientorderId else 'orderIdsList'
1618
+ request: dict = {}
1619
+ request[requestKey] = ordersRequests
1620
+ response = await self.futuresPrivateDeleteOrdersMultiCancel(self.extend(request, params))
1621
+ #
1622
+ # {
1623
+ # "code": "200000",
1624
+ # "data":
1625
+ # [
1626
+ # {
1627
+ # "orderId": "80465574458560512",
1628
+ # "clientOid": null,
1629
+ # "code": "200",
1630
+ # "msg": "success"
1631
+ # },
1632
+ # {
1633
+ # "orderId": "80465575289094144",
1634
+ # "clientOid": null,
1635
+ # "code": "200",
1636
+ # "msg": "success"
1637
+ # }
1638
+ # ]
1639
+ # }
1640
+ #
1641
+ orders = self.safe_list(response, 'data', [])
1642
+ return self.parse_orders(orders, market)
1643
+
1587
1644
  async def cancel_all_orders(self, symbol: Str = None, params={}):
1588
1645
  """
1589
1646
  cancel all open orders
@@ -976,15 +976,15 @@ class lbank(Exchange, ImplicitAPI):
976
976
  limit = min(limit, 2000)
977
977
  if since is None:
978
978
  duration = self.parse_timeframe(timeframe)
979
- since = self.milliseconds() - duration * 1000 * limit
979
+ since = self.milliseconds() - (duration * 1000 * limit)
980
980
  request: dict = {
981
981
  'symbol': market['id'],
982
982
  'type': self.safe_string(self.timeframes, timeframe, timeframe),
983
983
  'time': self.parse_to_int(since / 1000),
984
- 'size': limit, # max 2000
984
+ 'size': min(limit + 1, 2000), # max 2000
985
985
  }
986
986
  response = await self.spotPublicGetKline(self.extend(request, params))
987
- ohlcvs = self.safe_value(response, 'data', [])
987
+ ohlcvs = self.safe_list(response, 'data', [])
988
988
  #
989
989
  #
990
990
  # [
@@ -82,6 +82,7 @@ class phemex(Exchange, ImplicitAPI):
82
82
  'fetchMarkOHLCV': False,
83
83
  'fetchMyTrades': True,
84
84
  'fetchOHLCV': True,
85
+ 'fetchOpenInterest': True,
85
86
  'fetchOpenOrders': True,
86
87
  'fetchOrder': True,
87
88
  'fetchOrderBook': True,
@@ -4494,6 +4495,77 @@ class phemex(Exchange, ImplicitAPI):
4494
4495
  data = self.safe_dict(response, 'data', {})
4495
4496
  return self.parse_transaction(data, currency)
4496
4497
 
4498
+ async def fetch_open_interest(self, symbol: str, params={}):
4499
+ """
4500
+ retrieves the open interest of a trading pair
4501
+ :see: https://phemex-docs.github.io/#query-24-hours-ticker
4502
+ :param str symbol: unified CCXT market symbol
4503
+ :param dict [params]: exchange specific parameters
4504
+ :returns dict} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure:
4505
+ """
4506
+ await self.load_markets()
4507
+ market = self.market(symbol)
4508
+ if not market['contract']:
4509
+ raise BadRequest(self.id + ' fetchOpenInterest is only supported for contract markets.')
4510
+ request: dict = {
4511
+ 'symbol': market['id'],
4512
+ }
4513
+ response = await self.v2GetMdV2Ticker24hr(self.extend(request, params))
4514
+ #
4515
+ # {
4516
+ # error: null,
4517
+ # id: '0',
4518
+ # result: {
4519
+ # closeRp: '67550.1',
4520
+ # fundingRateRr: '0.0001',
4521
+ # highRp: '68400',
4522
+ # indexPriceRp: '67567.15389794',
4523
+ # lowRp: '66096.4',
4524
+ # markPriceRp: '67550.1',
4525
+ # openInterestRv: '1848.1144186',
4526
+ # openRp: '66330',
4527
+ # predFundingRateRr: '0.0001',
4528
+ # symbol: 'BTCUSDT',
4529
+ # timestamp: '1729114315443343001',
4530
+ # turnoverRv: '228863389.3237532',
4531
+ # volumeRq: '3388.5600312'
4532
+ # }
4533
+ # }
4534
+ #
4535
+ result = self.safe_dict(response, 'result')
4536
+ return self.parse_open_interest(result, market)
4537
+
4538
+ def parse_open_interest(self, interest, market: Market = None):
4539
+ #
4540
+ # {
4541
+ # closeRp: '67550.1',
4542
+ # fundingRateRr: '0.0001',
4543
+ # highRp: '68400',
4544
+ # indexPriceRp: '67567.15389794',
4545
+ # lowRp: '66096.4',
4546
+ # markPriceRp: '67550.1',
4547
+ # openInterestRv: '1848.1144186',
4548
+ # openRp: '66330',
4549
+ # predFundingRateRr: '0.0001',
4550
+ # symbol: 'BTCUSDT',
4551
+ # timestamp: '1729114315443343001',
4552
+ # turnoverRv: '228863389.3237532',
4553
+ # volumeRq: '3388.5600312'
4554
+ # }
4555
+ #
4556
+ timestamp = self.safe_integer(interest, 'timestamp') / 1000000
4557
+ id = self.safe_string(interest, 'symbol')
4558
+ return self.safe_open_interest({
4559
+ 'info': interest,
4560
+ 'symbol': self.safe_symbol(id, market),
4561
+ 'baseVolume': self.safe_string(interest, 'volumeRq'),
4562
+ 'quoteVolume': None, # deprecated
4563
+ 'openInterestAmount': self.safe_string(interest, 'openInterestRv'),
4564
+ 'openInterestValue': None,
4565
+ 'timestamp': timestamp,
4566
+ 'datetime': self.iso8601(timestamp),
4567
+ }, market)
4568
+
4497
4569
  def handle_errors(self, httpCode: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
4498
4570
  if response is None:
4499
4571
  return None # fallback to default error handler
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.18'
7
+ __version__ = '4.4.20'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -5981,6 +5981,8 @@ class Exchange(object):
5981
5981
  i = 0
5982
5982
  errors = 0
5983
5983
  result = []
5984
+ timeframe = self.safe_string(params, 'timeframe')
5985
+ params = self.omit(params, 'timeframe') # reading the timeframe from the method arguments to avoid changing the signature
5984
5986
  while(i < maxCalls):
5985
5987
  try:
5986
5988
  if cursorValue is not None:
@@ -5992,6 +5994,8 @@ class Exchange(object):
5992
5994
  response = getattr(self, method)(params)
5993
5995
  elif method == 'getLeverageTiersPaginated' or method == 'fetchPositions':
5994
5996
  response = getattr(self, method)(symbol, params)
5997
+ elif method == 'fetchOpenInterestHistory':
5998
+ response = getattr(self, method)(symbol, timeframe, since, maxEntriesPerRequest, params)
5995
5999
  else:
5996
6000
  response = getattr(self, method)(symbol, since, maxEntriesPerRequest, params)
5997
6001
  errors = 0
ccxt/base/types.py CHANGED
@@ -360,6 +360,17 @@ class MarketMarginModes(TypedDict):
360
360
  cross: bool
361
361
  isolated: bool
362
362
 
363
+ class MinMax(TypedDict):
364
+ min: Num
365
+ max: Num
366
+
367
+ class MarketLimits(TypedDict):
368
+ amount: Optional[MinMax]
369
+ cost: Optional[MinMax]
370
+ leverage: Optional[MinMax]
371
+ price: Optional[MinMax]
372
+ market: Optional[MinMax]
373
+
363
374
  class MarketInterface(TypedDict):
364
375
  info: Dict[str, Any]
365
376
  id: Str
@@ -393,7 +404,7 @@ class MarketInterface(TypedDict):
393
404
  tierBased: bool
394
405
  feeSide: Str
395
406
  precision: Any
396
- limits: Any
407
+ limits: MarketLimits
397
408
  created: Int
398
409
 
399
410
  class Limit(TypedDict):