ccxt 4.4.34__py2.py3-none-any.whl → 4.4.35__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/bingx.py +1 -0
  3. ccxt/abstract/bitpanda.py +0 -12
  4. ccxt/abstract/bitrue.py +3 -3
  5. ccxt/abstract/okx.py +1 -0
  6. ccxt/abstract/onetrading.py +0 -12
  7. ccxt/abstract/xt.py +5 -5
  8. ccxt/async_support/__init__.py +1 -1
  9. ccxt/async_support/base/exchange.py +1 -1
  10. ccxt/async_support/bingx.py +324 -138
  11. ccxt/async_support/bitmex.py +1 -1
  12. ccxt/async_support/bitrue.py +2 -2
  13. ccxt/async_support/btcmarkets.py +3 -3
  14. ccxt/async_support/btcturk.py +19 -19
  15. ccxt/async_support/gate.py +142 -39
  16. ccxt/async_support/hyperliquid.py +68 -11
  17. ccxt/async_support/idex.py +3 -4
  18. ccxt/async_support/kraken.py +58 -49
  19. ccxt/async_support/kucoin.py +1 -1
  20. ccxt/async_support/okx.py +1 -0
  21. ccxt/async_support/onetrading.py +47 -369
  22. ccxt/async_support/xt.py +10 -10
  23. ccxt/base/exchange.py +2 -1
  24. ccxt/bingx.py +324 -138
  25. ccxt/bitmex.py +1 -1
  26. ccxt/bitrue.py +2 -2
  27. ccxt/btcmarkets.py +3 -3
  28. ccxt/btcturk.py +19 -19
  29. ccxt/gate.py +142 -39
  30. ccxt/hyperliquid.py +68 -11
  31. ccxt/idex.py +3 -4
  32. ccxt/kraken.py +58 -49
  33. ccxt/kucoin.py +1 -1
  34. ccxt/okx.py +1 -0
  35. ccxt/onetrading.py +47 -369
  36. ccxt/pro/__init__.py +1 -1
  37. ccxt/pro/bitrue.py +13 -11
  38. ccxt/pro/probit.py +54 -66
  39. ccxt/test/tests_async.py +29 -2
  40. ccxt/test/tests_sync.py +29 -2
  41. ccxt/xt.py +10 -10
  42. {ccxt-4.4.34.dist-info → ccxt-4.4.35.dist-info}/METADATA +4 -4
  43. {ccxt-4.4.34.dist-info → ccxt-4.4.35.dist-info}/RECORD +46 -46
  44. {ccxt-4.4.34.dist-info → ccxt-4.4.35.dist-info}/LICENSE.txt +0 -0
  45. {ccxt-4.4.34.dist-info → ccxt-4.4.35.dist-info}/WHEEL +0 -0
  46. {ccxt-4.4.34.dist-info → ccxt-4.4.35.dist-info}/top_level.txt +0 -0
@@ -1471,7 +1471,7 @@ class bitmex(Exchange, ImplicitAPI):
1471
1471
  }
1472
1472
  if limit is not None:
1473
1473
  request['count'] = limit # default 100, max 500
1474
- until = self.safe_integer_2(params, 'until', 'endTime')
1474
+ until = self.safe_integer(params, 'until')
1475
1475
  if until is not None:
1476
1476
  params = self.omit(params, ['until'])
1477
1477
  request['endTime'] = self.iso8601(until)
@@ -2940,7 +2940,7 @@ class bitrue(Exchange, ImplicitAPI):
2940
2940
  version = self.safe_string(api, 1)
2941
2941
  access = self.safe_string(api, 2)
2942
2942
  url = None
2943
- if type == 'api' and version == 'kline':
2943
+ if (type == 'api' and version == 'kline') or (type == 'open' and path.find('listenKey') >= 0):
2944
2944
  url = self.urls['api'][type]
2945
2945
  else:
2946
2946
  url = self.urls['api'][type] + '/' + version
@@ -2949,7 +2949,7 @@ class bitrue(Exchange, ImplicitAPI):
2949
2949
  if access == 'private':
2950
2950
  self.check_required_credentials()
2951
2951
  recvWindow = self.safe_integer(self.options, 'recvWindow', 5000)
2952
- if type == 'spot':
2952
+ if type == 'spot' or type == 'open':
2953
2953
  query = self.urlencode(self.extend({
2954
2954
  'timestamp': self.nonce(),
2955
2955
  'recvWindow': recvWindow,
@@ -313,7 +313,7 @@ class btcmarkets(Exchange, ImplicitAPI):
313
313
  type = self.parse_transaction_type(self.safe_string_lower(transaction, 'type'))
314
314
  if type == 'withdraw':
315
315
  type = 'withdrawal'
316
- cryptoPaymentDetail = self.safe_value(transaction, 'paymentDetail', {})
316
+ cryptoPaymentDetail = self.safe_dict(transaction, 'paymentDetail', {})
317
317
  txid = self.safe_string(cryptoPaymentDetail, 'txId')
318
318
  address = self.safe_string(cryptoPaymentDetail, 'address')
319
319
  tag = None
@@ -394,7 +394,7 @@ class btcmarkets(Exchange, ImplicitAPI):
394
394
  base = self.safe_currency_code(baseId)
395
395
  quote = self.safe_currency_code(quoteId)
396
396
  symbol = base + '/' + quote
397
- fees = self.safe_value(self.safe_value(self.options, 'fees', {}), quote, self.fees)
397
+ fees = self.safe_value(self.safe_dict(self.options, 'fees', {}), quote, self.fees)
398
398
  pricePrecision = self.parse_number(self.parse_precision(self.safe_string(market, 'priceDecimals')))
399
399
  minAmount = self.safe_number(market, 'minOrderAmount')
400
400
  maxAmount = self.safe_number(market, 'maxOrderAmount')
@@ -1016,7 +1016,7 @@ class btcmarkets(Exchange, ImplicitAPI):
1016
1016
  clientOrderId = self.safe_string(order, 'clientOrderId')
1017
1017
  timeInForce = self.safe_string(order, 'timeInForce')
1018
1018
  stopPrice = self.safe_number(order, 'triggerPrice')
1019
- postOnly = self.safe_value(order, 'postOnly')
1019
+ postOnly = self.safe_bool(order, 'postOnly')
1020
1020
  return self.safe_order({
1021
1021
  'info': order,
1022
1022
  'id': id,
@@ -205,8 +205,8 @@ class btcturk(Exchange, ImplicitAPI):
205
205
  # ],
206
206
  # }
207
207
  #
208
- data = self.safe_value(response, 'data')
209
- markets = self.safe_value(data, 'symbols', [])
208
+ data = self.safe_dict(response, 'data', {})
209
+ markets = self.safe_list(data, 'symbols', [])
210
210
  return self.parse_markets(markets)
211
211
 
212
212
  def parse_market(self, entry) -> Market:
@@ -215,7 +215,7 @@ class btcturk(Exchange, ImplicitAPI):
215
215
  quoteId = self.safe_string(entry, 'denominator')
216
216
  base = self.safe_currency_code(baseId)
217
217
  quote = self.safe_currency_code(quoteId)
218
- filters = self.safe_value(entry, 'filters', [])
218
+ filters = self.safe_list(entry, 'filters', [])
219
219
  minPrice = None
220
220
  maxPrice = None
221
221
  minAmount = None
@@ -282,7 +282,7 @@ class btcturk(Exchange, ImplicitAPI):
282
282
  }
283
283
 
284
284
  def parse_balance(self, response) -> Balances:
285
- data = self.safe_value(response, 'data', [])
285
+ data = self.safe_list(response, 'data', [])
286
286
  result: dict = {
287
287
  'info': response,
288
288
  'timestamp': None,
@@ -356,7 +356,7 @@ class btcturk(Exchange, ImplicitAPI):
356
356
  # ]
357
357
  # }
358
358
  # }
359
- data = self.safe_value(response, 'data')
359
+ data = self.safe_dict(response, 'data', {})
360
360
  timestamp = self.safe_integer(data, 'timestamp')
361
361
  return self.parse_order_book(data, market['symbol'], timestamp, 'bids', 'asks', 0, 1)
362
362
 
@@ -637,20 +637,20 @@ class btcturk(Exchange, ImplicitAPI):
637
637
 
638
638
  def parse_ohlcvs(self, ohlcvs, market=None, timeframe='1m', since: Int = None, limit: Int = None, tail: Bool = False):
639
639
  results = []
640
- timestamp = self.safe_value(ohlcvs, 't')
641
- high = self.safe_value(ohlcvs, 'h')
642
- open = self.safe_value(ohlcvs, 'o')
643
- low = self.safe_value(ohlcvs, 'l')
644
- close = self.safe_value(ohlcvs, 'c')
645
- volume = self.safe_value(ohlcvs, 'v')
640
+ timestamp = self.safe_list(ohlcvs, 't', [])
641
+ high = self.safe_list(ohlcvs, 'h', [])
642
+ open = self.safe_list(ohlcvs, 'o', [])
643
+ low = self.safe_list(ohlcvs, 'l', [])
644
+ close = self.safe_list(ohlcvs, 'c', [])
645
+ volume = self.safe_list(ohlcvs, 'v', [])
646
646
  for i in range(0, len(timestamp)):
647
647
  ohlcv: dict = {
648
- 'timestamp': self.safe_value(timestamp, i),
649
- 'high': self.safe_value(high, i),
650
- 'open': self.safe_value(open, i),
651
- 'low': self.safe_value(low, i),
652
- 'close': self.safe_value(close, i),
653
- 'volume': self.safe_value(volume, i),
648
+ 'timestamp': self.safe_integer(timestamp, i),
649
+ 'high': self.safe_number(high, i),
650
+ 'open': self.safe_number(open, i),
651
+ 'low': self.safe_number(low, i),
652
+ 'close': self.safe_number(close, i),
653
+ 'volume': self.safe_number(volume, i),
654
654
  }
655
655
  results.append(self.parse_ohlcv(ohlcv, market))
656
656
  sorted = self.sort_by(results, 0)
@@ -733,8 +733,8 @@ class btcturk(Exchange, ImplicitAPI):
733
733
  market = self.market(symbol)
734
734
  request['pairSymbol'] = market['id']
735
735
  response = await self.privateGetOpenOrders(self.extend(request, params))
736
- data = self.safe_value(response, 'data')
737
- bids = self.safe_value(data, 'bids', [])
736
+ data = self.safe_dict(response, 'data', {})
737
+ bids = self.safe_list(data, 'bids', [])
738
738
  asks = self.safe_list(data, 'asks', [])
739
739
  return self.parse_orders(self.array_concat(bids, asks), market, since, limit)
740
740
 
@@ -709,6 +709,110 @@ class gate(Exchange, ImplicitAPI):
709
709
  },
710
710
  },
711
711
  },
712
+ 'features': {
713
+ 'spot': {
714
+ 'sandbox': True,
715
+ 'createOrder': {
716
+ 'marginMode': True,
717
+ 'triggerPrice': True,
718
+ 'triggerDirection': True, # todo: implementation edit needed
719
+ 'triggerPriceType': None,
720
+ 'stopLossPrice': True,
721
+ 'takeProfitPrice': True,
722
+ 'attachedStopLossTakeProfit': None,
723
+ 'timeInForce': {
724
+ 'GTC': True,
725
+ 'IOC': True,
726
+ 'FOK': True,
727
+ 'PO': True,
728
+ 'GTD': False,
729
+ },
730
+ 'hedged': False,
731
+ 'trailing': False,
732
+ # exchange-specific features
733
+ 'iceberg': True,
734
+ 'selfTradePrevention': True,
735
+ },
736
+ 'createOrders': {
737
+ 'max': 40, # NOTE! max 10 per symbol
738
+ },
739
+ 'fetchMyTrades': {
740
+ 'marginMode': True,
741
+ 'limit': 1000,
742
+ 'daysBack': None,
743
+ 'untilDays': 30,
744
+ },
745
+ 'fetchOrder': {
746
+ 'marginMode': False,
747
+ 'trigger': True,
748
+ 'trailing': False,
749
+ },
750
+ 'fetchOpenOrders': {
751
+ 'marginMode': True,
752
+ 'trigger': True,
753
+ 'trailing': False,
754
+ 'limit': 100,
755
+ },
756
+ 'fetchOrders': None,
757
+ 'fetchClosedOrders': {
758
+ 'marginMode': True,
759
+ 'trigger': True,
760
+ 'trailing': False,
761
+ 'limit': 100,
762
+ 'untilDays': 30,
763
+ 'daysBackClosed': None,
764
+ 'daysBackCanceled': None,
765
+ },
766
+ 'fetchOHLCV': {
767
+ 'limit': 1000,
768
+ },
769
+ },
770
+ 'forDerivatives': {
771
+ 'extends': 'spot',
772
+ 'createOrder': {
773
+ 'marginMode': False,
774
+ 'triggerPriceType': {
775
+ 'last': True,
776
+ 'mark': True,
777
+ 'index': True,
778
+ },
779
+ },
780
+ 'createOrders': {
781
+ 'max': 10,
782
+ },
783
+ 'fetchMyTrades': {
784
+ 'marginMode': False,
785
+ 'untilDays': None,
786
+ },
787
+ 'fetchOpenOrders': {
788
+ 'marginMode': False,
789
+ },
790
+ 'fetchClosedOrders': {
791
+ 'marginMode': False,
792
+ 'untilDays': None,
793
+ 'limit': 1000,
794
+ },
795
+ 'fetchOHLCV': {
796
+ 'limit': 1999,
797
+ },
798
+ },
799
+ 'swap': {
800
+ 'linear': {
801
+ 'extends': 'forDerivatives',
802
+ },
803
+ 'inverse': {
804
+ 'extends': 'forDerivatives',
805
+ },
806
+ },
807
+ 'future': {
808
+ 'linear': {
809
+ 'extends': 'forDerivatives',
810
+ },
811
+ 'inverse': {
812
+ 'extends': 'forDerivatives',
813
+ },
814
+ },
815
+ },
712
816
  'precisionMode': TICK_SIZE,
713
817
  'fees': {
714
818
  'trading': {
@@ -1533,22 +1637,22 @@ class gate(Exchange, ImplicitAPI):
1533
1637
  request['settle'] = settle
1534
1638
  return [request, params]
1535
1639
 
1536
- def spot_order_prepare_request(self, market=None, stop=False, params={}):
1640
+ def spot_order_prepare_request(self, market=None, trigger=False, params={}):
1537
1641
  """
1538
1642
  @ignore
1539
1643
  Fills request params currency_pair, market and account where applicable for spot order methods like fetchOpenOrders, cancelAllOrders
1540
1644
  :param dict market: CCXT market
1541
- :param bool stop: True if for a stop order
1645
+ :param bool trigger: True if for a trigger order
1542
1646
  :param dict [params]: request parameters
1543
1647
  :returns: the api request object, and the new params object with non-needed parameters removed
1544
1648
  """
1545
- marginMode, query = self.get_margin_mode(stop, params)
1649
+ marginMode, query = self.get_margin_mode(trigger, params)
1546
1650
  request: dict = {}
1547
- if not stop:
1651
+ if not trigger:
1548
1652
  if market is None:
1549
- raise ArgumentsRequired(self.id + ' spotOrderPrepareRequest() requires a market argument for non-stop orders')
1653
+ raise ArgumentsRequired(self.id + ' spotOrderPrepareRequest() requires a market argument for non-trigger orders')
1550
1654
  request['account'] = marginMode
1551
- request['currency_pair'] = market['id'] # Should always be set for non-stop
1655
+ request['currency_pair'] = market['id'] # Should always be set for non-trigger
1552
1656
  return [request, query]
1553
1657
 
1554
1658
  def multi_order_spot_prepare_request(self, market=None, trigger=False, params={}):
@@ -1556,7 +1660,7 @@ class gate(Exchange, ImplicitAPI):
1556
1660
  @ignore
1557
1661
  Fills request params currency_pair, market and account where applicable for spot order methods like fetchOpenOrders, cancelAllOrders
1558
1662
  :param dict market: CCXT market
1559
- :param bool stop: True if for a stop order
1663
+ :param bool trigger: True if for a trigger order
1560
1664
  :param dict [params]: request parameters
1561
1665
  :returns: the api request object, and the new params object with non-needed parameters removed
1562
1666
  """
@@ -1566,17 +1670,17 @@ class gate(Exchange, ImplicitAPI):
1566
1670
  }
1567
1671
  if market is not None:
1568
1672
  if trigger:
1569
- # gate spot and margin stop orders use the term market instead of currency_pair, and normal instead of spot. Neither parameter is used when fetching/cancelling a single order. They are used for creating a single stop order, but createOrder does not call self method
1673
+ # gate spot and margin trigger orders use the term market instead of currency_pair, and normal instead of spot. Neither parameter is used when fetching/cancelling a single order. They are used for creating a single trigger order, but createOrder does not call self method
1570
1674
  request['market'] = market['id']
1571
1675
  else:
1572
1676
  request['currency_pair'] = market['id']
1573
1677
  return [request, query]
1574
1678
 
1575
- def get_margin_mode(self, stop, params):
1679
+ def get_margin_mode(self, trigger, params):
1576
1680
  """
1577
1681
  @ignore
1578
1682
  Gets the margin type for self api call
1579
- :param bool stop: True if for a stop order
1683
+ :param bool trigger: True if for a trigger order
1580
1684
  :param dict [params]: Request params
1581
1685
  :returns: The marginMode and the updated request params with marginMode removed, marginMode value is the value that can be read by the "account" property specified in gates api docs
1582
1686
  """
@@ -1589,12 +1693,12 @@ class gate(Exchange, ImplicitAPI):
1589
1693
  marginMode = 'margin'
1590
1694
  elif marginMode == '':
1591
1695
  marginMode = 'spot'
1592
- if stop:
1696
+ if trigger:
1593
1697
  if marginMode == 'spot':
1594
- # gate spot stop orders use the term normal instead of spot
1698
+ # gate spot trigger orders use the term normal instead of spot
1595
1699
  marginMode = 'normal'
1596
1700
  if marginMode == 'cross_margin':
1597
- raise BadRequest(self.id + ' getMarginMode() does not support stop orders for cross margin')
1701
+ raise BadRequest(self.id + ' getMarginMode() does not support trigger orders for cross margin')
1598
1702
  isUnifiedAccount = False
1599
1703
  isUnifiedAccount, params = self.handle_option_and_params(params, 'getMarginMode', 'unifiedAccount')
1600
1704
  if isUnifiedAccount:
@@ -2990,7 +3094,6 @@ class gate(Exchange, ImplicitAPI):
2990
3094
  request['limit'] = limit
2991
3095
  response = None
2992
3096
  if market['contract']:
2993
- maxLimit = 1999
2994
3097
  isMark = (price == 'mark')
2995
3098
  isIndex = (price == 'index')
2996
3099
  if isMark or isIndex:
@@ -3307,7 +3410,7 @@ class gate(Exchange, ImplicitAPI):
3307
3410
  params = self.omit(params, 'order_id')
3308
3411
  else:
3309
3412
  if market is not None:
3310
- request['currency_pair'] = market['id'] # Should always be set for non-stop
3413
+ request['currency_pair'] = market['id'] # Should always be set for non-trigger
3311
3414
  marginMode, params = self.get_margin_mode(False, params)
3312
3415
  request['account'] = marginMode
3313
3416
  if limit is not None:
@@ -3826,8 +3929,8 @@ class gate(Exchange, ImplicitAPI):
3826
3929
  takeProfitPrice = self.safe_value(params, 'takeProfitPrice')
3827
3930
  isStopLossOrder = stopLossPrice is not None
3828
3931
  isTakeProfitOrder = takeProfitPrice is not None
3829
- isStopOrder = isStopLossOrder or isTakeProfitOrder
3830
- nonTriggerOrder = not isStopOrder and (trigger is None)
3932
+ isTpsl = isStopLossOrder or isTakeProfitOrder
3933
+ nonTriggerOrder = not isTpsl and (trigger is None)
3831
3934
  orderRequest = self.create_order_request(symbol, type, side, amount, price, params)
3832
3935
  response = None
3833
3936
  if market['spot'] or market['margin']:
@@ -3976,7 +4079,7 @@ class gate(Exchange, ImplicitAPI):
3976
4079
  takeProfitPrice = self.safe_value(params, 'takeProfitPrice')
3977
4080
  isStopLossOrder = stopLossPrice is not None
3978
4081
  isTakeProfitOrder = takeProfitPrice is not None
3979
- isStopOrder = isStopLossOrder or isTakeProfitOrder
4082
+ isTpsl = isStopLossOrder or isTakeProfitOrder
3980
4083
  if isStopLossOrder and isTakeProfitOrder:
3981
4084
  raise ExchangeError(self.id + ' createOrder() stopLossPrice and takeProfitPrice cannot both be defined')
3982
4085
  reduceOnly = self.safe_value(params, 'reduceOnly')
@@ -4012,7 +4115,7 @@ class gate(Exchange, ImplicitAPI):
4012
4115
  signedAmount = Precise.string_neg(amountToPrecision) if (side == 'sell') else amountToPrecision
4013
4116
  amount = int(signedAmount)
4014
4117
  request = None
4015
- nonTriggerOrder = not isStopOrder and (trigger is None)
4118
+ nonTriggerOrder = not isTpsl and (trigger is None)
4016
4119
  if nonTriggerOrder:
4017
4120
  if contract:
4018
4121
  # contract order
@@ -4562,7 +4665,7 @@ class gate(Exchange, ImplicitAPI):
4562
4665
 
4563
4666
  def fetch_order_request(self, id: str, symbol: Str = None, params={}):
4564
4667
  market = None if (symbol is None) else self.market(symbol)
4565
- stop = self.safe_bool_n(params, ['trigger', 'is_stop_order', 'stop'], False)
4668
+ trigger = self.safe_bool_n(params, ['trigger', 'is_stop_order', 'stop'], False)
4566
4669
  params = self.omit(params, ['is_stop_order', 'stop', 'trigger'])
4567
4670
  clientOrderId = self.safe_string_2(params, 'text', 'clientOrderId')
4568
4671
  orderId = id
@@ -4573,7 +4676,7 @@ class gate(Exchange, ImplicitAPI):
4573
4676
  orderId = clientOrderId
4574
4677
  type, query = self.handle_market_type_and_params('fetchOrder', market, params)
4575
4678
  contract = (type == 'swap') or (type == 'future') or (type == 'option')
4576
- request, requestParams = self.prepare_request(market, type, query) if contract else self.spot_order_prepare_request(market, stop, query)
4679
+ request, requestParams = self.prepare_request(market, type, query) if contract else self.spot_order_prepare_request(market, trigger, query)
4577
4680
  request['order_id'] = str(orderId)
4578
4681
  return [request, requestParams]
4579
4682
 
@@ -4601,21 +4704,21 @@ class gate(Exchange, ImplicitAPI):
4601
4704
  market = None if (symbol is None) else self.market(symbol)
4602
4705
  result = self.handle_market_type_and_params('fetchOrder', market, params)
4603
4706
  type = self.safe_string(result, 0)
4604
- stop = self.safe_bool_n(params, ['trigger', 'is_stop_order', 'stop'], False)
4707
+ trigger = self.safe_bool_n(params, ['trigger', 'is_stop_order', 'stop'], False)
4605
4708
  request, requestParams = self.fetch_order_request(id, symbol, params)
4606
4709
  response = None
4607
4710
  if type == 'spot' or type == 'margin':
4608
- if stop:
4711
+ if trigger:
4609
4712
  response = await self.privateSpotGetPriceOrdersOrderId(self.extend(request, requestParams))
4610
4713
  else:
4611
4714
  response = await self.privateSpotGetOrdersOrderId(self.extend(request, requestParams))
4612
4715
  elif type == 'swap':
4613
- if stop:
4716
+ if trigger:
4614
4717
  response = await self.privateFuturesGetSettlePriceOrdersOrderId(self.extend(request, requestParams))
4615
4718
  else:
4616
4719
  response = await self.privateFuturesGetSettleOrdersOrderId(self.extend(request, requestParams))
4617
4720
  elif type == 'future':
4618
- if stop:
4721
+ if trigger:
4619
4722
  response = await self.privateDeliveryGetSettlePriceOrdersOrderId(self.extend(request, requestParams))
4620
4723
  else:
4621
4724
  response = await self.privateDeliveryGetSettleOrdersOrderId(self.extend(request, requestParams))
@@ -4636,7 +4739,7 @@ class gate(Exchange, ImplicitAPI):
4636
4739
  :param int [since]: the earliest time in ms to fetch open orders for
4637
4740
  :param int [limit]: the maximum number of open orders structures to retrieve
4638
4741
  :param dict [params]: extra parameters specific to the exchange API endpoint
4639
- :param bool [params.stop]: True for fetching stop orders
4742
+ :param bool [params.trigger]: True for fetching trigger orders
4640
4743
  :param str [params.type]: spot, margin, swap or future, if not provided self.options['defaultType'] is used
4641
4744
  :param str [params.marginMode]: 'cross' or 'isolated' - marginMode for type='margin', if not provided self.options['defaultMarginMode'] is used
4642
4745
  :param bool [params.unifiedAccount]: set to True for fetching unified account orders
@@ -4661,7 +4764,7 @@ class gate(Exchange, ImplicitAPI):
4661
4764
  :param int [since]: the earliest time in ms to fetch orders for
4662
4765
  :param int [limit]: the maximum number of order structures to retrieve
4663
4766
  :param dict [params]: extra parameters specific to the exchange API endpoint
4664
- :param bool [params.stop]: True for fetching stop orders
4767
+ :param bool [params.trigger]: True for fetching trigger orders
4665
4768
  :param str [params.type]: spot, swap or future, if not provided self.options['defaultType'] is used
4666
4769
  :param str [params.marginMode]: 'cross' or 'isolated' - marginMode for margin trading if not provided self.options['defaultMarginMode'] is used
4667
4770
  :param boolean [params.historical]: *swap only* True for using historical endpoint
@@ -4835,7 +4938,7 @@ class gate(Exchange, ImplicitAPI):
4835
4938
  # }
4836
4939
  # ]
4837
4940
  #
4838
- # spot stop
4941
+ # spot trigger
4839
4942
  #
4840
4943
  # [
4841
4944
  # {
@@ -4930,31 +5033,31 @@ class gate(Exchange, ImplicitAPI):
4930
5033
  :param str id: Order id
4931
5034
  :param str symbol: Unified market symbol
4932
5035
  :param dict [params]: Parameters specified by the exchange api
4933
- :param bool [params.stop]: True if the order to be cancelled is a trigger order
5036
+ :param bool [params.trigger]: True if the order to be cancelled is a trigger order
4934
5037
  :param bool [params.unifiedAccount]: set to True for canceling unified account orders
4935
5038
  :returns: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
4936
5039
  """
4937
5040
  await self.load_markets()
4938
5041
  await self.load_unified_status()
4939
5042
  market = None if (symbol is None) else self.market(symbol)
4940
- stop = self.safe_bool_n(params, ['is_stop_order', 'stop', 'trigger'], False)
5043
+ trigger = self.safe_bool_n(params, ['is_stop_order', 'stop', 'trigger'], False)
4941
5044
  params = self.omit(params, ['is_stop_order', 'stop', 'trigger'])
4942
5045
  type, query = self.handle_market_type_and_params('cancelOrder', market, params)
4943
- request, requestParams = self.spot_order_prepare_request(market, stop, query) if (type == 'spot' or type == 'margin') else self.prepare_request(market, type, query)
5046
+ request, requestParams = self.spot_order_prepare_request(market, trigger, query) if (type == 'spot' or type == 'margin') else self.prepare_request(market, type, query)
4944
5047
  request['order_id'] = id
4945
5048
  response = None
4946
5049
  if type == 'spot' or type == 'margin':
4947
- if stop:
5050
+ if trigger:
4948
5051
  response = await self.privateSpotDeletePriceOrdersOrderId(self.extend(request, requestParams))
4949
5052
  else:
4950
5053
  response = await self.privateSpotDeleteOrdersOrderId(self.extend(request, requestParams))
4951
5054
  elif type == 'swap':
4952
- if stop:
5055
+ if trigger:
4953
5056
  response = await self.privateFuturesDeleteSettlePriceOrdersOrderId(self.extend(request, requestParams))
4954
5057
  else:
4955
5058
  response = await self.privateFuturesDeleteSettleOrdersOrderId(self.extend(request, requestParams))
4956
5059
  elif type == 'future':
4957
- if stop:
5060
+ if trigger:
4958
5061
  response = await self.privateDeliveryDeleteSettlePriceOrdersOrderId(self.extend(request, requestParams))
4959
5062
  else:
4960
5063
  response = await self.privateDeliveryDeleteSettleOrdersOrderId(self.extend(request, requestParams))
@@ -5144,23 +5247,23 @@ class gate(Exchange, ImplicitAPI):
5144
5247
  await self.load_markets()
5145
5248
  await self.load_unified_status()
5146
5249
  market = None if (symbol is None) else self.market(symbol)
5147
- stop = self.safe_bool_2(params, 'stop', 'trigger')
5250
+ trigger = self.safe_bool_2(params, 'stop', 'trigger')
5148
5251
  params = self.omit(params, ['stop', 'trigger'])
5149
5252
  type, query = self.handle_market_type_and_params('cancelAllOrders', market, params)
5150
- request, requestParams = self.multi_order_spot_prepare_request(market, stop, query) if (type == 'spot') else self.prepare_request(market, type, query)
5253
+ request, requestParams = self.multi_order_spot_prepare_request(market, trigger, query) if (type == 'spot') else self.prepare_request(market, type, query)
5151
5254
  response = None
5152
5255
  if type == 'spot' or type == 'margin':
5153
- if stop:
5256
+ if trigger:
5154
5257
  response = await self.privateSpotDeletePriceOrders(self.extend(request, requestParams))
5155
5258
  else:
5156
5259
  response = await self.privateSpotDeleteOrders(self.extend(request, requestParams))
5157
5260
  elif type == 'swap':
5158
- if stop:
5261
+ if trigger:
5159
5262
  response = await self.privateFuturesDeleteSettlePriceOrders(self.extend(request, requestParams))
5160
5263
  else:
5161
5264
  response = await self.privateFuturesDeleteSettleOrders(self.extend(request, requestParams))
5162
5265
  elif type == 'future':
5163
- if stop:
5266
+ if trigger:
5164
5267
  response = await self.privateDeliveryDeleteSettlePriceOrders(self.extend(request, requestParams))
5165
5268
  else:
5166
5269
  response = await self.privateDeliveryDeleteSettleOrders(self.extend(request, requestParams))
@@ -12,12 +12,14 @@ from typing import List
12
12
  from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import ArgumentsRequired
14
14
  from ccxt.base.errors import BadRequest
15
+ from ccxt.base.errors import InsufficientFunds
15
16
  from ccxt.base.errors import InvalidOrder
16
17
  from ccxt.base.errors import OrderNotFound
17
18
  from ccxt.base.errors import NotSupported
18
19
  from ccxt.base.decimal_to_precision import ROUND
19
20
  from ccxt.base.decimal_to_precision import DECIMAL_PLACES
20
21
  from ccxt.base.decimal_to_precision import SIGNIFICANT_DIGITS
22
+ from ccxt.base.decimal_to_precision import TICK_SIZE
21
23
  from ccxt.base.precise import Precise
22
24
 
23
25
 
@@ -211,9 +213,11 @@ class hyperliquid(Exchange, ImplicitAPI):
211
213
  'User or API Wallet ': InvalidOrder,
212
214
  'Order has invalid size': InvalidOrder,
213
215
  'Order price cannot be more than 80% away from the reference price': InvalidOrder,
216
+ 'Order has zero size.': InvalidOrder,
217
+ 'Insufficient spot balance asset': InsufficientFunds,
214
218
  },
215
219
  },
216
- 'precisionMode': DECIMAL_PLACES,
220
+ 'precisionMode': TICK_SIZE,
217
221
  'commonCurrencies': {
218
222
  },
219
223
  'options': {
@@ -362,6 +366,48 @@ class hyperliquid(Exchange, ImplicitAPI):
362
366
  result.append(data)
363
367
  return self.parse_markets(result)
364
368
 
369
+ def calculate_price_precision(self, price: float, amountPrecision: float, maxDecimals: float):
370
+ """
371
+ Helper function to calculate the Hyperliquid DECIMAL_PLACES price precision
372
+ :param float price: the price to use in the calculation
373
+ :param int amountPrecision: the amountPrecision to use in the calculation
374
+ :param int maxDecimals: the maxDecimals to use in the calculation
375
+ :returns int: The calculated price precision
376
+ """
377
+ pricePrecision = 0
378
+ priceStr = self.number_to_string(price)
379
+ if priceStr is None:
380
+ return 0
381
+ priceSplitted = priceStr.split('.')
382
+ if Precise.string_eq(priceStr, '0'):
383
+ # Significant digits is always hasattr(self, 5) case
384
+ significantDigits = 5
385
+ # Integer digits is always hasattr(self, 0) case(0 doesn't count)
386
+ integerDigits = 0
387
+ # Calculate the price precision
388
+ pricePrecision = min(maxDecimals - amountPrecision, significantDigits - integerDigits)
389
+ elif Precise.string_gt(priceStr, '0') and Precise.string_lt(priceStr, '1'):
390
+ # Significant digits, always hasattr(self, 5) case
391
+ significantDigits = 5
392
+ # Get the part after the decimal separator
393
+ decimalPart = self.safe_string(priceSplitted, 1, '')
394
+ # Count the number of leading zeros in the decimal part
395
+ leadingZeros = 0
396
+ while((leadingZeros <= len(decimalPart)) and (decimalPart[leadingZeros] == '0')):
397
+ leadingZeros = leadingZeros + 1
398
+ # Calculate price precision based on leading zeros and significant digits
399
+ pricePrecision = leadingZeros + significantDigits
400
+ # Calculate the price precision based on maxDecimals - szDecimals and the calculated price precision from the previous step
401
+ pricePrecision = min(maxDecimals - amountPrecision, pricePrecision)
402
+ else:
403
+ # Count the numbers before the decimal separator
404
+ integerPart = self.safe_string(priceSplitted, 0, '')
405
+ # Get significant digits, take the max() of 5 and the integer digits count
406
+ significantDigits = max(5, len(integerPart))
407
+ # Calculate price precision based on maxDecimals - szDecimals and significantDigits - len(integerPart)
408
+ pricePrecision = min(maxDecimals - amountPrecision, significantDigits - len(integerPart))
409
+ return self.parse_to_int(pricePrecision)
410
+
365
411
  async def fetch_spot_markets(self, params={}) -> List[Market]:
366
412
  """
367
413
  retrieves data on all spot markets for hyperliquid
@@ -451,7 +497,11 @@ class hyperliquid(Exchange, ImplicitAPI):
451
497
  symbol = base + '/' + quote
452
498
  innerBaseTokenInfo = self.safe_dict(baseTokenInfo, 'spec', baseTokenInfo)
453
499
  # innerQuoteTokenInfo = self.safe_dict(quoteTokenInfo, 'spec', quoteTokenInfo)
454
- amountPrecision = self.safe_integer(innerBaseTokenInfo, 'szDecimals')
500
+ amountPrecisionStr = self.safe_string(innerBaseTokenInfo, 'szDecimals')
501
+ amountPrecision = int(amountPrecisionStr)
502
+ price = self.safe_number(extraData, 'midPx')
503
+ pricePrecision = self.calculate_price_precision(price, amountPrecision, 8)
504
+ pricePrecisionStr = self.number_to_string(pricePrecision)
455
505
  # quotePrecision = self.parse_number(self.parse_precision(self.safe_string(innerQuoteTokenInfo, 'szDecimals')))
456
506
  baseId = self.number_to_string(i + 10000)
457
507
  markets.append(self.safe_market_structure({
@@ -482,8 +532,8 @@ class hyperliquid(Exchange, ImplicitAPI):
482
532
  'strike': None,
483
533
  'optionType': None,
484
534
  'precision': {
485
- 'amount': amountPrecision, # decimal places
486
- 'price': 8 - amountPrecision, # MAX_DECIMALS is 8
535
+ 'amount': self.parse_number(self.parse_precision(amountPrecisionStr)),
536
+ 'price': self.parse_number(self.parse_precision(pricePrecisionStr)),
487
537
  },
488
538
  'limits': {
489
539
  'leverage': {
@@ -544,7 +594,11 @@ class hyperliquid(Exchange, ImplicitAPI):
544
594
  fees = self.safe_dict(self.fees, 'swap', {})
545
595
  taker = self.safe_number(fees, 'taker')
546
596
  maker = self.safe_number(fees, 'maker')
547
- amountPrecision = self.safe_integer(market, 'szDecimals')
597
+ amountPrecisionStr = self.safe_string(market, 'szDecimals')
598
+ amountPrecision = int(amountPrecisionStr)
599
+ price = self.safe_number(market, 'markPx', 0)
600
+ pricePrecision = self.calculate_price_precision(price, amountPrecision, 6)
601
+ pricePrecisionStr = self.number_to_string(pricePrecision)
548
602
  return self.safe_market_structure({
549
603
  'id': baseId,
550
604
  'symbol': symbol,
@@ -572,8 +626,8 @@ class hyperliquid(Exchange, ImplicitAPI):
572
626
  'strike': None,
573
627
  'optionType': None,
574
628
  'precision': {
575
- 'amount': amountPrecision, # decimal places
576
- 'price': 6 - amountPrecision, # MAX_DECIMALS is 6
629
+ 'amount': self.parse_number(self.parse_precision(amountPrecisionStr)),
630
+ 'price': self.parse_number(self.parse_precision(pricePrecisionStr)),
577
631
  },
578
632
  'limits': {
579
633
  'leverage': {
@@ -1040,10 +1094,13 @@ class hyperliquid(Exchange, ImplicitAPI):
1040
1094
 
1041
1095
  def price_to_precision(self, symbol: str, price) -> str:
1042
1096
  market = self.market(symbol)
1043
- # https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/tick-and-lot-size
1044
- result = self.decimal_to_precision(price, ROUND, 5, SIGNIFICANT_DIGITS, self.paddingMode)
1045
- decimalParsedResult = self.decimal_to_precision(result, ROUND, market['precision']['price'], self.precisionMode, self.paddingMode)
1046
- return decimalParsedResult
1097
+ priceStr = self.number_to_string(price)
1098
+ integerPart = priceStr.split('.')[0]
1099
+ significantDigits = max(5, len(integerPart))
1100
+ result = self.decimal_to_precision(price, ROUND, significantDigits, SIGNIFICANT_DIGITS, self.paddingMode)
1101
+ maxDecimals = 8 if market['spot'] else 6
1102
+ subtractedValue = maxDecimals - self.precision_from_string(self.safe_string(market['precision'], 'amount'))
1103
+ return self.decimal_to_precision(result, ROUND, subtractedValue, DECIMAL_PLACES, self.paddingMode)
1047
1104
 
1048
1105
  def hash_message(self, message):
1049
1106
  return '0x' + self.hash(message, 'keccak', 'hex')