ccxt 4.4.33__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 (100) hide show
  1. ccxt/__init__.py +3 -1
  2. ccxt/abstract/bingx.py +17 -0
  3. ccxt/abstract/bitbank.py +5 -0
  4. ccxt/abstract/bitfinex2.py +1 -0
  5. ccxt/abstract/bitpanda.py +0 -12
  6. ccxt/abstract/bitrue.py +3 -3
  7. ccxt/abstract/ellipx.py +25 -0
  8. ccxt/abstract/okx.py +1 -0
  9. ccxt/abstract/onetrading.py +0 -12
  10. ccxt/abstract/xt.py +5 -5
  11. ccxt/alpaca.py +2 -0
  12. ccxt/async_support/__init__.py +3 -1
  13. ccxt/async_support/alpaca.py +2 -0
  14. ccxt/async_support/base/exchange.py +1 -1
  15. ccxt/async_support/binance.py +19 -15
  16. ccxt/async_support/bingx.py +479 -146
  17. ccxt/async_support/bitbank.py +5 -0
  18. ccxt/async_support/bitbns.py +2 -0
  19. ccxt/async_support/bitfinex2.py +1 -0
  20. ccxt/async_support/bitget.py +174 -40
  21. ccxt/async_support/bitmex.py +3 -1
  22. ccxt/async_support/bitopro.py +3 -0
  23. ccxt/async_support/bitrue.py +3 -2
  24. ccxt/async_support/btcmarkets.py +5 -3
  25. ccxt/async_support/btcturk.py +19 -19
  26. ccxt/async_support/bybit.py +13 -10
  27. ccxt/async_support/cex.py +13 -4
  28. ccxt/async_support/coinbase.py +3 -2
  29. ccxt/async_support/coinex.py +1 -0
  30. ccxt/async_support/coinone.py +7 -7
  31. ccxt/async_support/coinsph.py +7 -7
  32. ccxt/async_support/coinspot.py +39 -39
  33. ccxt/async_support/cryptocom.py +36 -34
  34. ccxt/async_support/ellipx.py +1828 -0
  35. ccxt/async_support/gate.py +143 -39
  36. ccxt/async_support/hyperliquid.py +70 -11
  37. ccxt/async_support/idex.py +3 -4
  38. ccxt/async_support/kraken.py +58 -49
  39. ccxt/async_support/krakenfutures.py +3 -1
  40. ccxt/async_support/kucoin.py +1 -1
  41. ccxt/async_support/okcoin.py +2 -0
  42. ccxt/async_support/okx.py +15 -10
  43. ccxt/async_support/onetrading.py +67 -370
  44. ccxt/async_support/paradex.py +2 -0
  45. ccxt/async_support/phemex.py +16 -0
  46. ccxt/async_support/poloniex.py +3 -1
  47. ccxt/async_support/poloniexfutures.py +3 -1
  48. ccxt/async_support/vertex.py +2 -0
  49. ccxt/async_support/woo.py +69 -69
  50. ccxt/async_support/xt.py +10 -10
  51. ccxt/base/exchange.py +28 -7
  52. ccxt/binance.py +19 -15
  53. ccxt/bingx.py +479 -146
  54. ccxt/bitbank.py +5 -0
  55. ccxt/bitbns.py +2 -0
  56. ccxt/bitfinex2.py +1 -0
  57. ccxt/bitget.py +174 -40
  58. ccxt/bitmex.py +3 -1
  59. ccxt/bitopro.py +3 -0
  60. ccxt/bitrue.py +3 -2
  61. ccxt/btcmarkets.py +5 -3
  62. ccxt/btcturk.py +19 -19
  63. ccxt/bybit.py +13 -10
  64. ccxt/cex.py +13 -4
  65. ccxt/coinbase.py +3 -2
  66. ccxt/coinex.py +1 -0
  67. ccxt/coinone.py +7 -7
  68. ccxt/coinsph.py +7 -7
  69. ccxt/coinspot.py +39 -39
  70. ccxt/cryptocom.py +36 -34
  71. ccxt/ellipx.py +1828 -0
  72. ccxt/gate.py +143 -39
  73. ccxt/hyperliquid.py +70 -11
  74. ccxt/idex.py +3 -4
  75. ccxt/kraken.py +58 -49
  76. ccxt/krakenfutures.py +3 -1
  77. ccxt/kucoin.py +1 -1
  78. ccxt/okcoin.py +2 -0
  79. ccxt/okx.py +15 -10
  80. ccxt/onetrading.py +67 -370
  81. ccxt/paradex.py +2 -0
  82. ccxt/phemex.py +16 -0
  83. ccxt/poloniex.py +3 -1
  84. ccxt/poloniexfutures.py +3 -1
  85. ccxt/pro/__init__.py +1 -1
  86. ccxt/pro/bitrue.py +13 -11
  87. ccxt/pro/idex.py +15 -0
  88. ccxt/pro/probit.py +58 -68
  89. ccxt/pro/woo.py +15 -15
  90. ccxt/test/tests_async.py +29 -2
  91. ccxt/test/tests_helpers.py +0 -2
  92. ccxt/test/tests_sync.py +29 -2
  93. ccxt/vertex.py +2 -0
  94. ccxt/woo.py +69 -69
  95. ccxt/xt.py +10 -10
  96. {ccxt-4.4.33.dist-info → ccxt-4.4.35.dist-info}/METADATA +9 -8
  97. {ccxt-4.4.33.dist-info → ccxt-4.4.35.dist-info}/RECORD +100 -97
  98. {ccxt-4.4.33.dist-info → ccxt-4.4.35.dist-info}/LICENSE.txt +0 -0
  99. {ccxt-4.4.33.dist-info → ccxt-4.4.35.dist-info}/WHEEL +0 -0
  100. {ccxt-4.4.33.dist-info → ccxt-4.4.35.dist-info}/top_level.txt +0 -0
ccxt/gate.py CHANGED
@@ -708,6 +708,110 @@ class gate(Exchange, ImplicitAPI):
708
708
  },
709
709
  },
710
710
  },
711
+ 'features': {
712
+ 'spot': {
713
+ 'sandbox': True,
714
+ 'createOrder': {
715
+ 'marginMode': True,
716
+ 'triggerPrice': True,
717
+ 'triggerDirection': True, # todo: implementation edit needed
718
+ 'triggerPriceType': None,
719
+ 'stopLossPrice': True,
720
+ 'takeProfitPrice': True,
721
+ 'attachedStopLossTakeProfit': None,
722
+ 'timeInForce': {
723
+ 'GTC': True,
724
+ 'IOC': True,
725
+ 'FOK': True,
726
+ 'PO': True,
727
+ 'GTD': False,
728
+ },
729
+ 'hedged': False,
730
+ 'trailing': False,
731
+ # exchange-specific features
732
+ 'iceberg': True,
733
+ 'selfTradePrevention': True,
734
+ },
735
+ 'createOrders': {
736
+ 'max': 40, # NOTE! max 10 per symbol
737
+ },
738
+ 'fetchMyTrades': {
739
+ 'marginMode': True,
740
+ 'limit': 1000,
741
+ 'daysBack': None,
742
+ 'untilDays': 30,
743
+ },
744
+ 'fetchOrder': {
745
+ 'marginMode': False,
746
+ 'trigger': True,
747
+ 'trailing': False,
748
+ },
749
+ 'fetchOpenOrders': {
750
+ 'marginMode': True,
751
+ 'trigger': True,
752
+ 'trailing': False,
753
+ 'limit': 100,
754
+ },
755
+ 'fetchOrders': None,
756
+ 'fetchClosedOrders': {
757
+ 'marginMode': True,
758
+ 'trigger': True,
759
+ 'trailing': False,
760
+ 'limit': 100,
761
+ 'untilDays': 30,
762
+ 'daysBackClosed': None,
763
+ 'daysBackCanceled': None,
764
+ },
765
+ 'fetchOHLCV': {
766
+ 'limit': 1000,
767
+ },
768
+ },
769
+ 'forDerivatives': {
770
+ 'extends': 'spot',
771
+ 'createOrder': {
772
+ 'marginMode': False,
773
+ 'triggerPriceType': {
774
+ 'last': True,
775
+ 'mark': True,
776
+ 'index': True,
777
+ },
778
+ },
779
+ 'createOrders': {
780
+ 'max': 10,
781
+ },
782
+ 'fetchMyTrades': {
783
+ 'marginMode': False,
784
+ 'untilDays': None,
785
+ },
786
+ 'fetchOpenOrders': {
787
+ 'marginMode': False,
788
+ },
789
+ 'fetchClosedOrders': {
790
+ 'marginMode': False,
791
+ 'untilDays': None,
792
+ 'limit': 1000,
793
+ },
794
+ 'fetchOHLCV': {
795
+ 'limit': 1999,
796
+ },
797
+ },
798
+ 'swap': {
799
+ 'linear': {
800
+ 'extends': 'forDerivatives',
801
+ },
802
+ 'inverse': {
803
+ 'extends': 'forDerivatives',
804
+ },
805
+ },
806
+ 'future': {
807
+ 'linear': {
808
+ 'extends': 'forDerivatives',
809
+ },
810
+ 'inverse': {
811
+ 'extends': 'forDerivatives',
812
+ },
813
+ },
814
+ },
711
815
  'precisionMode': TICK_SIZE,
712
816
  'fees': {
713
817
  'trading': {
@@ -945,6 +1049,7 @@ class gate(Exchange, ImplicitAPI):
945
1049
  except Exception as e:
946
1050
  # if the request fails, the unifiedAccount is disabled
947
1051
  self.options['unifiedAccount'] = False
1052
+ return self.options['unifiedAccount']
948
1053
 
949
1054
  def upgrade_unified_trade_account(self, params={}):
950
1055
  return self.privateUnifiedPutUnifiedMode(params)
@@ -1531,22 +1636,22 @@ class gate(Exchange, ImplicitAPI):
1531
1636
  request['settle'] = settle
1532
1637
  return [request, params]
1533
1638
 
1534
- def spot_order_prepare_request(self, market=None, stop=False, params={}):
1639
+ def spot_order_prepare_request(self, market=None, trigger=False, params={}):
1535
1640
  """
1536
1641
  @ignore
1537
1642
  Fills request params currency_pair, market and account where applicable for spot order methods like fetchOpenOrders, cancelAllOrders
1538
1643
  :param dict market: CCXT market
1539
- :param bool stop: True if for a stop order
1644
+ :param bool trigger: True if for a trigger order
1540
1645
  :param dict [params]: request parameters
1541
1646
  :returns: the api request object, and the new params object with non-needed parameters removed
1542
1647
  """
1543
- marginMode, query = self.get_margin_mode(stop, params)
1648
+ marginMode, query = self.get_margin_mode(trigger, params)
1544
1649
  request: dict = {}
1545
- if not stop:
1650
+ if not trigger:
1546
1651
  if market is None:
1547
- raise ArgumentsRequired(self.id + ' spotOrderPrepareRequest() requires a market argument for non-stop orders')
1652
+ raise ArgumentsRequired(self.id + ' spotOrderPrepareRequest() requires a market argument for non-trigger orders')
1548
1653
  request['account'] = marginMode
1549
- request['currency_pair'] = market['id'] # Should always be set for non-stop
1654
+ request['currency_pair'] = market['id'] # Should always be set for non-trigger
1550
1655
  return [request, query]
1551
1656
 
1552
1657
  def multi_order_spot_prepare_request(self, market=None, trigger=False, params={}):
@@ -1554,7 +1659,7 @@ class gate(Exchange, ImplicitAPI):
1554
1659
  @ignore
1555
1660
  Fills request params currency_pair, market and account where applicable for spot order methods like fetchOpenOrders, cancelAllOrders
1556
1661
  :param dict market: CCXT market
1557
- :param bool stop: True if for a stop order
1662
+ :param bool trigger: True if for a trigger order
1558
1663
  :param dict [params]: request parameters
1559
1664
  :returns: the api request object, and the new params object with non-needed parameters removed
1560
1665
  """
@@ -1564,17 +1669,17 @@ class gate(Exchange, ImplicitAPI):
1564
1669
  }
1565
1670
  if market is not None:
1566
1671
  if trigger:
1567
- # 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
1672
+ # 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
1568
1673
  request['market'] = market['id']
1569
1674
  else:
1570
1675
  request['currency_pair'] = market['id']
1571
1676
  return [request, query]
1572
1677
 
1573
- def get_margin_mode(self, stop, params):
1678
+ def get_margin_mode(self, trigger, params):
1574
1679
  """
1575
1680
  @ignore
1576
1681
  Gets the margin type for self api call
1577
- :param bool stop: True if for a stop order
1682
+ :param bool trigger: True if for a trigger order
1578
1683
  :param dict [params]: Request params
1579
1684
  :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
1580
1685
  """
@@ -1587,12 +1692,12 @@ class gate(Exchange, ImplicitAPI):
1587
1692
  marginMode = 'margin'
1588
1693
  elif marginMode == '':
1589
1694
  marginMode = 'spot'
1590
- if stop:
1695
+ if trigger:
1591
1696
  if marginMode == 'spot':
1592
- # gate spot stop orders use the term normal instead of spot
1697
+ # gate spot trigger orders use the term normal instead of spot
1593
1698
  marginMode = 'normal'
1594
1699
  if marginMode == 'cross_margin':
1595
- raise BadRequest(self.id + ' getMarginMode() does not support stop orders for cross margin')
1700
+ raise BadRequest(self.id + ' getMarginMode() does not support trigger orders for cross margin')
1596
1701
  isUnifiedAccount = False
1597
1702
  isUnifiedAccount, params = self.handle_option_and_params(params, 'getMarginMode', 'unifiedAccount')
1598
1703
  if isUnifiedAccount:
@@ -2988,7 +3093,6 @@ class gate(Exchange, ImplicitAPI):
2988
3093
  request['limit'] = limit
2989
3094
  response = None
2990
3095
  if market['contract']:
2991
- maxLimit = 1999
2992
3096
  isMark = (price == 'mark')
2993
3097
  isIndex = (price == 'index')
2994
3098
  if isMark or isIndex:
@@ -3305,7 +3409,7 @@ class gate(Exchange, ImplicitAPI):
3305
3409
  params = self.omit(params, 'order_id')
3306
3410
  else:
3307
3411
  if market is not None:
3308
- request['currency_pair'] = market['id'] # Should always be set for non-stop
3412
+ request['currency_pair'] = market['id'] # Should always be set for non-trigger
3309
3413
  marginMode, params = self.get_margin_mode(False, params)
3310
3414
  request['account'] = marginMode
3311
3415
  if limit is not None:
@@ -3824,8 +3928,8 @@ class gate(Exchange, ImplicitAPI):
3824
3928
  takeProfitPrice = self.safe_value(params, 'takeProfitPrice')
3825
3929
  isStopLossOrder = stopLossPrice is not None
3826
3930
  isTakeProfitOrder = takeProfitPrice is not None
3827
- isStopOrder = isStopLossOrder or isTakeProfitOrder
3828
- nonTriggerOrder = not isStopOrder and (trigger is None)
3931
+ isTpsl = isStopLossOrder or isTakeProfitOrder
3932
+ nonTriggerOrder = not isTpsl and (trigger is None)
3829
3933
  orderRequest = self.create_order_request(symbol, type, side, amount, price, params)
3830
3934
  response = None
3831
3935
  if market['spot'] or market['margin']:
@@ -3974,7 +4078,7 @@ class gate(Exchange, ImplicitAPI):
3974
4078
  takeProfitPrice = self.safe_value(params, 'takeProfitPrice')
3975
4079
  isStopLossOrder = stopLossPrice is not None
3976
4080
  isTakeProfitOrder = takeProfitPrice is not None
3977
- isStopOrder = isStopLossOrder or isTakeProfitOrder
4081
+ isTpsl = isStopLossOrder or isTakeProfitOrder
3978
4082
  if isStopLossOrder and isTakeProfitOrder:
3979
4083
  raise ExchangeError(self.id + ' createOrder() stopLossPrice and takeProfitPrice cannot both be defined')
3980
4084
  reduceOnly = self.safe_value(params, 'reduceOnly')
@@ -4010,7 +4114,7 @@ class gate(Exchange, ImplicitAPI):
4010
4114
  signedAmount = Precise.string_neg(amountToPrecision) if (side == 'sell') else amountToPrecision
4011
4115
  amount = int(signedAmount)
4012
4116
  request = None
4013
- nonTriggerOrder = not isStopOrder and (trigger is None)
4117
+ nonTriggerOrder = not isTpsl and (trigger is None)
4014
4118
  if nonTriggerOrder:
4015
4119
  if contract:
4016
4120
  # contract order
@@ -4560,7 +4664,7 @@ class gate(Exchange, ImplicitAPI):
4560
4664
 
4561
4665
  def fetch_order_request(self, id: str, symbol: Str = None, params={}):
4562
4666
  market = None if (symbol is None) else self.market(symbol)
4563
- stop = self.safe_bool_n(params, ['trigger', 'is_stop_order', 'stop'], False)
4667
+ trigger = self.safe_bool_n(params, ['trigger', 'is_stop_order', 'stop'], False)
4564
4668
  params = self.omit(params, ['is_stop_order', 'stop', 'trigger'])
4565
4669
  clientOrderId = self.safe_string_2(params, 'text', 'clientOrderId')
4566
4670
  orderId = id
@@ -4571,7 +4675,7 @@ class gate(Exchange, ImplicitAPI):
4571
4675
  orderId = clientOrderId
4572
4676
  type, query = self.handle_market_type_and_params('fetchOrder', market, params)
4573
4677
  contract = (type == 'swap') or (type == 'future') or (type == 'option')
4574
- request, requestParams = self.prepare_request(market, type, query) if contract else self.spot_order_prepare_request(market, stop, query)
4678
+ request, requestParams = self.prepare_request(market, type, query) if contract else self.spot_order_prepare_request(market, trigger, query)
4575
4679
  request['order_id'] = str(orderId)
4576
4680
  return [request, requestParams]
4577
4681
 
@@ -4599,21 +4703,21 @@ class gate(Exchange, ImplicitAPI):
4599
4703
  market = None if (symbol is None) else self.market(symbol)
4600
4704
  result = self.handle_market_type_and_params('fetchOrder', market, params)
4601
4705
  type = self.safe_string(result, 0)
4602
- stop = self.safe_bool_n(params, ['trigger', 'is_stop_order', 'stop'], False)
4706
+ trigger = self.safe_bool_n(params, ['trigger', 'is_stop_order', 'stop'], False)
4603
4707
  request, requestParams = self.fetch_order_request(id, symbol, params)
4604
4708
  response = None
4605
4709
  if type == 'spot' or type == 'margin':
4606
- if stop:
4710
+ if trigger:
4607
4711
  response = self.privateSpotGetPriceOrdersOrderId(self.extend(request, requestParams))
4608
4712
  else:
4609
4713
  response = self.privateSpotGetOrdersOrderId(self.extend(request, requestParams))
4610
4714
  elif type == 'swap':
4611
- if stop:
4715
+ if trigger:
4612
4716
  response = self.privateFuturesGetSettlePriceOrdersOrderId(self.extend(request, requestParams))
4613
4717
  else:
4614
4718
  response = self.privateFuturesGetSettleOrdersOrderId(self.extend(request, requestParams))
4615
4719
  elif type == 'future':
4616
- if stop:
4720
+ if trigger:
4617
4721
  response = self.privateDeliveryGetSettlePriceOrdersOrderId(self.extend(request, requestParams))
4618
4722
  else:
4619
4723
  response = self.privateDeliveryGetSettleOrdersOrderId(self.extend(request, requestParams))
@@ -4634,7 +4738,7 @@ class gate(Exchange, ImplicitAPI):
4634
4738
  :param int [since]: the earliest time in ms to fetch open orders for
4635
4739
  :param int [limit]: the maximum number of open orders structures to retrieve
4636
4740
  :param dict [params]: extra parameters specific to the exchange API endpoint
4637
- :param bool [params.stop]: True for fetching stop orders
4741
+ :param bool [params.trigger]: True for fetching trigger orders
4638
4742
  :param str [params.type]: spot, margin, swap or future, if not provided self.options['defaultType'] is used
4639
4743
  :param str [params.marginMode]: 'cross' or 'isolated' - marginMode for type='margin', if not provided self.options['defaultMarginMode'] is used
4640
4744
  :param bool [params.unifiedAccount]: set to True for fetching unified account orders
@@ -4659,7 +4763,7 @@ class gate(Exchange, ImplicitAPI):
4659
4763
  :param int [since]: the earliest time in ms to fetch orders for
4660
4764
  :param int [limit]: the maximum number of order structures to retrieve
4661
4765
  :param dict [params]: extra parameters specific to the exchange API endpoint
4662
- :param bool [params.stop]: True for fetching stop orders
4766
+ :param bool [params.trigger]: True for fetching trigger orders
4663
4767
  :param str [params.type]: spot, swap or future, if not provided self.options['defaultType'] is used
4664
4768
  :param str [params.marginMode]: 'cross' or 'isolated' - marginMode for margin trading if not provided self.options['defaultMarginMode'] is used
4665
4769
  :param boolean [params.historical]: *swap only* True for using historical endpoint
@@ -4833,7 +4937,7 @@ class gate(Exchange, ImplicitAPI):
4833
4937
  # }
4834
4938
  # ]
4835
4939
  #
4836
- # spot stop
4940
+ # spot trigger
4837
4941
  #
4838
4942
  # [
4839
4943
  # {
@@ -4928,31 +5032,31 @@ class gate(Exchange, ImplicitAPI):
4928
5032
  :param str id: Order id
4929
5033
  :param str symbol: Unified market symbol
4930
5034
  :param dict [params]: Parameters specified by the exchange api
4931
- :param bool [params.stop]: True if the order to be cancelled is a trigger order
5035
+ :param bool [params.trigger]: True if the order to be cancelled is a trigger order
4932
5036
  :param bool [params.unifiedAccount]: set to True for canceling unified account orders
4933
5037
  :returns: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
4934
5038
  """
4935
5039
  self.load_markets()
4936
5040
  self.load_unified_status()
4937
5041
  market = None if (symbol is None) else self.market(symbol)
4938
- stop = self.safe_bool_n(params, ['is_stop_order', 'stop', 'trigger'], False)
5042
+ trigger = self.safe_bool_n(params, ['is_stop_order', 'stop', 'trigger'], False)
4939
5043
  params = self.omit(params, ['is_stop_order', 'stop', 'trigger'])
4940
5044
  type, query = self.handle_market_type_and_params('cancelOrder', market, params)
4941
- request, requestParams = self.spot_order_prepare_request(market, stop, query) if (type == 'spot' or type == 'margin') else self.prepare_request(market, type, query)
5045
+ request, requestParams = self.spot_order_prepare_request(market, trigger, query) if (type == 'spot' or type == 'margin') else self.prepare_request(market, type, query)
4942
5046
  request['order_id'] = id
4943
5047
  response = None
4944
5048
  if type == 'spot' or type == 'margin':
4945
- if stop:
5049
+ if trigger:
4946
5050
  response = self.privateSpotDeletePriceOrdersOrderId(self.extend(request, requestParams))
4947
5051
  else:
4948
5052
  response = self.privateSpotDeleteOrdersOrderId(self.extend(request, requestParams))
4949
5053
  elif type == 'swap':
4950
- if stop:
5054
+ if trigger:
4951
5055
  response = self.privateFuturesDeleteSettlePriceOrdersOrderId(self.extend(request, requestParams))
4952
5056
  else:
4953
5057
  response = self.privateFuturesDeleteSettleOrdersOrderId(self.extend(request, requestParams))
4954
5058
  elif type == 'future':
4955
- if stop:
5059
+ if trigger:
4956
5060
  response = self.privateDeliveryDeleteSettlePriceOrdersOrderId(self.extend(request, requestParams))
4957
5061
  else:
4958
5062
  response = self.privateDeliveryDeleteSettleOrdersOrderId(self.extend(request, requestParams))
@@ -5142,23 +5246,23 @@ class gate(Exchange, ImplicitAPI):
5142
5246
  self.load_markets()
5143
5247
  self.load_unified_status()
5144
5248
  market = None if (symbol is None) else self.market(symbol)
5145
- stop = self.safe_bool_2(params, 'stop', 'trigger')
5249
+ trigger = self.safe_bool_2(params, 'stop', 'trigger')
5146
5250
  params = self.omit(params, ['stop', 'trigger'])
5147
5251
  type, query = self.handle_market_type_and_params('cancelAllOrders', market, params)
5148
- request, requestParams = self.multi_order_spot_prepare_request(market, stop, query) if (type == 'spot') else self.prepare_request(market, type, query)
5252
+ request, requestParams = self.multi_order_spot_prepare_request(market, trigger, query) if (type == 'spot') else self.prepare_request(market, type, query)
5149
5253
  response = None
5150
5254
  if type == 'spot' or type == 'margin':
5151
- if stop:
5255
+ if trigger:
5152
5256
  response = self.privateSpotDeletePriceOrders(self.extend(request, requestParams))
5153
5257
  else:
5154
5258
  response = self.privateSpotDeleteOrders(self.extend(request, requestParams))
5155
5259
  elif type == 'swap':
5156
- if stop:
5260
+ if trigger:
5157
5261
  response = self.privateFuturesDeleteSettlePriceOrders(self.extend(request, requestParams))
5158
5262
  else:
5159
5263
  response = self.privateFuturesDeleteSettleOrders(self.extend(request, requestParams))
5160
5264
  elif type == 'future':
5161
- if stop:
5265
+ if trigger:
5162
5266
  response = self.privateDeliveryDeleteSettlePriceOrders(self.extend(request, requestParams))
5163
5267
  else:
5164
5268
  response = self.privateDeliveryDeleteSettleOrders(self.extend(request, requestParams))
ccxt/hyperliquid.py CHANGED
@@ -11,12 +11,14 @@ from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import ArgumentsRequired
13
13
  from ccxt.base.errors import BadRequest
14
+ from ccxt.base.errors import InsufficientFunds
14
15
  from ccxt.base.errors import InvalidOrder
15
16
  from ccxt.base.errors import OrderNotFound
16
17
  from ccxt.base.errors import NotSupported
17
18
  from ccxt.base.decimal_to_precision import ROUND
18
19
  from ccxt.base.decimal_to_precision import DECIMAL_PLACES
19
20
  from ccxt.base.decimal_to_precision import SIGNIFICANT_DIGITS
21
+ from ccxt.base.decimal_to_precision import TICK_SIZE
20
22
  from ccxt.base.precise import Precise
21
23
 
22
24
 
@@ -55,6 +57,8 @@ class hyperliquid(Exchange, ImplicitAPI):
55
57
  'createOrder': True,
56
58
  'createOrders': True,
57
59
  'createReduceOnlyOrder': True,
60
+ 'createStopOrder': True,
61
+ 'createTriggerOrder': True,
58
62
  'editOrder': True,
59
63
  'fetchAccounts': False,
60
64
  'fetchBalance': True,
@@ -208,9 +212,11 @@ class hyperliquid(Exchange, ImplicitAPI):
208
212
  'User or API Wallet ': InvalidOrder,
209
213
  'Order has invalid size': InvalidOrder,
210
214
  'Order price cannot be more than 80% away from the reference price': InvalidOrder,
215
+ 'Order has zero size.': InvalidOrder,
216
+ 'Insufficient spot balance asset': InsufficientFunds,
211
217
  },
212
218
  },
213
- 'precisionMode': DECIMAL_PLACES,
219
+ 'precisionMode': TICK_SIZE,
214
220
  'commonCurrencies': {
215
221
  },
216
222
  'options': {
@@ -359,6 +365,48 @@ class hyperliquid(Exchange, ImplicitAPI):
359
365
  result.append(data)
360
366
  return self.parse_markets(result)
361
367
 
368
+ def calculate_price_precision(self, price: float, amountPrecision: float, maxDecimals: float):
369
+ """
370
+ Helper function to calculate the Hyperliquid DECIMAL_PLACES price precision
371
+ :param float price: the price to use in the calculation
372
+ :param int amountPrecision: the amountPrecision to use in the calculation
373
+ :param int maxDecimals: the maxDecimals to use in the calculation
374
+ :returns int: The calculated price precision
375
+ """
376
+ pricePrecision = 0
377
+ priceStr = self.number_to_string(price)
378
+ if priceStr is None:
379
+ return 0
380
+ priceSplitted = priceStr.split('.')
381
+ if Precise.string_eq(priceStr, '0'):
382
+ # Significant digits is always hasattr(self, 5) case
383
+ significantDigits = 5
384
+ # Integer digits is always hasattr(self, 0) case(0 doesn't count)
385
+ integerDigits = 0
386
+ # Calculate the price precision
387
+ pricePrecision = min(maxDecimals - amountPrecision, significantDigits - integerDigits)
388
+ elif Precise.string_gt(priceStr, '0') and Precise.string_lt(priceStr, '1'):
389
+ # Significant digits, always hasattr(self, 5) case
390
+ significantDigits = 5
391
+ # Get the part after the decimal separator
392
+ decimalPart = self.safe_string(priceSplitted, 1, '')
393
+ # Count the number of leading zeros in the decimal part
394
+ leadingZeros = 0
395
+ while((leadingZeros <= len(decimalPart)) and (decimalPart[leadingZeros] == '0')):
396
+ leadingZeros = leadingZeros + 1
397
+ # Calculate price precision based on leading zeros and significant digits
398
+ pricePrecision = leadingZeros + significantDigits
399
+ # Calculate the price precision based on maxDecimals - szDecimals and the calculated price precision from the previous step
400
+ pricePrecision = min(maxDecimals - amountPrecision, pricePrecision)
401
+ else:
402
+ # Count the numbers before the decimal separator
403
+ integerPart = self.safe_string(priceSplitted, 0, '')
404
+ # Get significant digits, take the max() of 5 and the integer digits count
405
+ significantDigits = max(5, len(integerPart))
406
+ # Calculate price precision based on maxDecimals - szDecimals and significantDigits - len(integerPart)
407
+ pricePrecision = min(maxDecimals - amountPrecision, significantDigits - len(integerPart))
408
+ return self.parse_to_int(pricePrecision)
409
+
362
410
  def fetch_spot_markets(self, params={}) -> List[Market]:
363
411
  """
364
412
  retrieves data on all spot markets for hyperliquid
@@ -448,7 +496,11 @@ class hyperliquid(Exchange, ImplicitAPI):
448
496
  symbol = base + '/' + quote
449
497
  innerBaseTokenInfo = self.safe_dict(baseTokenInfo, 'spec', baseTokenInfo)
450
498
  # innerQuoteTokenInfo = self.safe_dict(quoteTokenInfo, 'spec', quoteTokenInfo)
451
- amountPrecision = self.safe_integer(innerBaseTokenInfo, 'szDecimals')
499
+ amountPrecisionStr = self.safe_string(innerBaseTokenInfo, 'szDecimals')
500
+ amountPrecision = int(amountPrecisionStr)
501
+ price = self.safe_number(extraData, 'midPx')
502
+ pricePrecision = self.calculate_price_precision(price, amountPrecision, 8)
503
+ pricePrecisionStr = self.number_to_string(pricePrecision)
452
504
  # quotePrecision = self.parse_number(self.parse_precision(self.safe_string(innerQuoteTokenInfo, 'szDecimals')))
453
505
  baseId = self.number_to_string(i + 10000)
454
506
  markets.append(self.safe_market_structure({
@@ -479,8 +531,8 @@ class hyperliquid(Exchange, ImplicitAPI):
479
531
  'strike': None,
480
532
  'optionType': None,
481
533
  'precision': {
482
- 'amount': amountPrecision, # decimal places
483
- 'price': 8 - amountPrecision, # MAX_DECIMALS is 8
534
+ 'amount': self.parse_number(self.parse_precision(amountPrecisionStr)),
535
+ 'price': self.parse_number(self.parse_precision(pricePrecisionStr)),
484
536
  },
485
537
  'limits': {
486
538
  'leverage': {
@@ -541,7 +593,11 @@ class hyperliquid(Exchange, ImplicitAPI):
541
593
  fees = self.safe_dict(self.fees, 'swap', {})
542
594
  taker = self.safe_number(fees, 'taker')
543
595
  maker = self.safe_number(fees, 'maker')
544
- amountPrecision = self.safe_integer(market, 'szDecimals')
596
+ amountPrecisionStr = self.safe_string(market, 'szDecimals')
597
+ amountPrecision = int(amountPrecisionStr)
598
+ price = self.safe_number(market, 'markPx', 0)
599
+ pricePrecision = self.calculate_price_precision(price, amountPrecision, 6)
600
+ pricePrecisionStr = self.number_to_string(pricePrecision)
545
601
  return self.safe_market_structure({
546
602
  'id': baseId,
547
603
  'symbol': symbol,
@@ -569,8 +625,8 @@ class hyperliquid(Exchange, ImplicitAPI):
569
625
  'strike': None,
570
626
  'optionType': None,
571
627
  'precision': {
572
- 'amount': amountPrecision, # decimal places
573
- 'price': 6 - amountPrecision, # MAX_DECIMALS is 6
628
+ 'amount': self.parse_number(self.parse_precision(amountPrecisionStr)),
629
+ 'price': self.parse_number(self.parse_precision(pricePrecisionStr)),
574
630
  },
575
631
  'limits': {
576
632
  'leverage': {
@@ -1037,10 +1093,13 @@ class hyperliquid(Exchange, ImplicitAPI):
1037
1093
 
1038
1094
  def price_to_precision(self, symbol: str, price) -> str:
1039
1095
  market = self.market(symbol)
1040
- # https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/tick-and-lot-size
1041
- result = self.decimal_to_precision(price, ROUND, 5, SIGNIFICANT_DIGITS, self.paddingMode)
1042
- decimalParsedResult = self.decimal_to_precision(result, ROUND, market['precision']['price'], self.precisionMode, self.paddingMode)
1043
- return decimalParsedResult
1096
+ priceStr = self.number_to_string(price)
1097
+ integerPart = priceStr.split('.')[0]
1098
+ significantDigits = max(5, len(integerPart))
1099
+ result = self.decimal_to_precision(price, ROUND, significantDigits, SIGNIFICANT_DIGITS, self.paddingMode)
1100
+ maxDecimals = 8 if market['spot'] else 6
1101
+ subtractedValue = maxDecimals - self.precision_from_string(self.safe_string(market['precision'], 'amount'))
1102
+ return self.decimal_to_precision(result, ROUND, subtractedValue, DECIMAL_PLACES, self.paddingMode)
1044
1103
 
1045
1104
  def hash_message(self, message):
1046
1105
  return '0x' + self.hash(message, 'keccak', 'hex')
ccxt/idex.py CHANGED
@@ -19,7 +19,6 @@ from ccxt.base.errors import DDoSProtection
19
19
  from ccxt.base.errors import ExchangeNotAvailable
20
20
  from ccxt.base.decimal_to_precision import ROUND
21
21
  from ccxt.base.decimal_to_precision import TRUNCATE
22
- from ccxt.base.decimal_to_precision import DECIMAL_PLACES
23
22
  from ccxt.base.decimal_to_precision import TICK_SIZE
24
23
  from ccxt.base.decimal_to_precision import PAD_WITH_ZERO
25
24
  from ccxt.base.precise import Precise
@@ -206,10 +205,8 @@ class idex(Exchange, ImplicitAPI):
206
205
  # {"code":"INVALID_PARAMETER","message":"invalid value provided for request parameter \"price\": all quantities and prices must be below 100 billion, above 0, need to be provided, and always require 4 decimals ending with 4 zeroes"}
207
206
  #
208
207
  market = self.market(symbol)
209
- info = self.safe_value(market, 'info', {})
210
- quoteAssetPrecision = self.safe_integer(info, 'quoteAssetPrecision')
211
208
  price = self.decimal_to_precision(price, ROUND, market['precision']['price'], self.precisionMode)
212
- return self.decimal_to_precision(price, TRUNCATE, quoteAssetPrecision, DECIMAL_PLACES, PAD_WITH_ZERO)
209
+ return self.decimal_to_precision(price, TRUNCATE, market['precision']['quote'], TICK_SIZE, PAD_WITH_ZERO)
213
210
 
214
211
  def fetch_markets(self, params={}) -> List[Market]:
215
212
  """
@@ -316,6 +313,8 @@ class idex(Exchange, ImplicitAPI):
316
313
  'precision': {
317
314
  'amount': basePrecision,
318
315
  'price': self.safe_number(entry, 'tickSize'),
316
+ 'base': basePrecision,
317
+ 'quote': quotePrecision,
319
318
  },
320
319
  'limits': {
321
320
  'leverage': {