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
@@ -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': {
@@ -946,6 +1050,7 @@ class gate(Exchange, ImplicitAPI):
946
1050
  except Exception as e:
947
1051
  # if the request fails, the unifiedAccount is disabled
948
1052
  self.options['unifiedAccount'] = False
1053
+ return self.options['unifiedAccount']
949
1054
 
950
1055
  async def upgrade_unified_trade_account(self, params={}):
951
1056
  return await self.privateUnifiedPutUnifiedMode(params)
@@ -1532,22 +1637,22 @@ class gate(Exchange, ImplicitAPI):
1532
1637
  request['settle'] = settle
1533
1638
  return [request, params]
1534
1639
 
1535
- def spot_order_prepare_request(self, market=None, stop=False, params={}):
1640
+ def spot_order_prepare_request(self, market=None, trigger=False, params={}):
1536
1641
  """
1537
1642
  @ignore
1538
1643
  Fills request params currency_pair, market and account where applicable for spot order methods like fetchOpenOrders, cancelAllOrders
1539
1644
  :param dict market: CCXT market
1540
- :param bool stop: True if for a stop order
1645
+ :param bool trigger: True if for a trigger order
1541
1646
  :param dict [params]: request parameters
1542
1647
  :returns: the api request object, and the new params object with non-needed parameters removed
1543
1648
  """
1544
- marginMode, query = self.get_margin_mode(stop, params)
1649
+ marginMode, query = self.get_margin_mode(trigger, params)
1545
1650
  request: dict = {}
1546
- if not stop:
1651
+ if not trigger:
1547
1652
  if market is None:
1548
- 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')
1549
1654
  request['account'] = marginMode
1550
- 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
1551
1656
  return [request, query]
1552
1657
 
1553
1658
  def multi_order_spot_prepare_request(self, market=None, trigger=False, params={}):
@@ -1555,7 +1660,7 @@ class gate(Exchange, ImplicitAPI):
1555
1660
  @ignore
1556
1661
  Fills request params currency_pair, market and account where applicable for spot order methods like fetchOpenOrders, cancelAllOrders
1557
1662
  :param dict market: CCXT market
1558
- :param bool stop: True if for a stop order
1663
+ :param bool trigger: True if for a trigger order
1559
1664
  :param dict [params]: request parameters
1560
1665
  :returns: the api request object, and the new params object with non-needed parameters removed
1561
1666
  """
@@ -1565,17 +1670,17 @@ class gate(Exchange, ImplicitAPI):
1565
1670
  }
1566
1671
  if market is not None:
1567
1672
  if trigger:
1568
- # 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
1569
1674
  request['market'] = market['id']
1570
1675
  else:
1571
1676
  request['currency_pair'] = market['id']
1572
1677
  return [request, query]
1573
1678
 
1574
- def get_margin_mode(self, stop, params):
1679
+ def get_margin_mode(self, trigger, params):
1575
1680
  """
1576
1681
  @ignore
1577
1682
  Gets the margin type for self api call
1578
- :param bool stop: True if for a stop order
1683
+ :param bool trigger: True if for a trigger order
1579
1684
  :param dict [params]: Request params
1580
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
1581
1686
  """
@@ -1588,12 +1693,12 @@ class gate(Exchange, ImplicitAPI):
1588
1693
  marginMode = 'margin'
1589
1694
  elif marginMode == '':
1590
1695
  marginMode = 'spot'
1591
- if stop:
1696
+ if trigger:
1592
1697
  if marginMode == 'spot':
1593
- # gate spot stop orders use the term normal instead of spot
1698
+ # gate spot trigger orders use the term normal instead of spot
1594
1699
  marginMode = 'normal'
1595
1700
  if marginMode == 'cross_margin':
1596
- 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')
1597
1702
  isUnifiedAccount = False
1598
1703
  isUnifiedAccount, params = self.handle_option_and_params(params, 'getMarginMode', 'unifiedAccount')
1599
1704
  if isUnifiedAccount:
@@ -2989,7 +3094,6 @@ class gate(Exchange, ImplicitAPI):
2989
3094
  request['limit'] = limit
2990
3095
  response = None
2991
3096
  if market['contract']:
2992
- maxLimit = 1999
2993
3097
  isMark = (price == 'mark')
2994
3098
  isIndex = (price == 'index')
2995
3099
  if isMark or isIndex:
@@ -3306,7 +3410,7 @@ class gate(Exchange, ImplicitAPI):
3306
3410
  params = self.omit(params, 'order_id')
3307
3411
  else:
3308
3412
  if market is not None:
3309
- 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
3310
3414
  marginMode, params = self.get_margin_mode(False, params)
3311
3415
  request['account'] = marginMode
3312
3416
  if limit is not None:
@@ -3825,8 +3929,8 @@ class gate(Exchange, ImplicitAPI):
3825
3929
  takeProfitPrice = self.safe_value(params, 'takeProfitPrice')
3826
3930
  isStopLossOrder = stopLossPrice is not None
3827
3931
  isTakeProfitOrder = takeProfitPrice is not None
3828
- isStopOrder = isStopLossOrder or isTakeProfitOrder
3829
- nonTriggerOrder = not isStopOrder and (trigger is None)
3932
+ isTpsl = isStopLossOrder or isTakeProfitOrder
3933
+ nonTriggerOrder = not isTpsl and (trigger is None)
3830
3934
  orderRequest = self.create_order_request(symbol, type, side, amount, price, params)
3831
3935
  response = None
3832
3936
  if market['spot'] or market['margin']:
@@ -3975,7 +4079,7 @@ class gate(Exchange, ImplicitAPI):
3975
4079
  takeProfitPrice = self.safe_value(params, 'takeProfitPrice')
3976
4080
  isStopLossOrder = stopLossPrice is not None
3977
4081
  isTakeProfitOrder = takeProfitPrice is not None
3978
- isStopOrder = isStopLossOrder or isTakeProfitOrder
4082
+ isTpsl = isStopLossOrder or isTakeProfitOrder
3979
4083
  if isStopLossOrder and isTakeProfitOrder:
3980
4084
  raise ExchangeError(self.id + ' createOrder() stopLossPrice and takeProfitPrice cannot both be defined')
3981
4085
  reduceOnly = self.safe_value(params, 'reduceOnly')
@@ -4011,7 +4115,7 @@ class gate(Exchange, ImplicitAPI):
4011
4115
  signedAmount = Precise.string_neg(amountToPrecision) if (side == 'sell') else amountToPrecision
4012
4116
  amount = int(signedAmount)
4013
4117
  request = None
4014
- nonTriggerOrder = not isStopOrder and (trigger is None)
4118
+ nonTriggerOrder = not isTpsl and (trigger is None)
4015
4119
  if nonTriggerOrder:
4016
4120
  if contract:
4017
4121
  # contract order
@@ -4561,7 +4665,7 @@ class gate(Exchange, ImplicitAPI):
4561
4665
 
4562
4666
  def fetch_order_request(self, id: str, symbol: Str = None, params={}):
4563
4667
  market = None if (symbol is None) else self.market(symbol)
4564
- 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)
4565
4669
  params = self.omit(params, ['is_stop_order', 'stop', 'trigger'])
4566
4670
  clientOrderId = self.safe_string_2(params, 'text', 'clientOrderId')
4567
4671
  orderId = id
@@ -4572,7 +4676,7 @@ class gate(Exchange, ImplicitAPI):
4572
4676
  orderId = clientOrderId
4573
4677
  type, query = self.handle_market_type_and_params('fetchOrder', market, params)
4574
4678
  contract = (type == 'swap') or (type == 'future') or (type == 'option')
4575
- 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)
4576
4680
  request['order_id'] = str(orderId)
4577
4681
  return [request, requestParams]
4578
4682
 
@@ -4600,21 +4704,21 @@ class gate(Exchange, ImplicitAPI):
4600
4704
  market = None if (symbol is None) else self.market(symbol)
4601
4705
  result = self.handle_market_type_and_params('fetchOrder', market, params)
4602
4706
  type = self.safe_string(result, 0)
4603
- 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)
4604
4708
  request, requestParams = self.fetch_order_request(id, symbol, params)
4605
4709
  response = None
4606
4710
  if type == 'spot' or type == 'margin':
4607
- if stop:
4711
+ if trigger:
4608
4712
  response = await self.privateSpotGetPriceOrdersOrderId(self.extend(request, requestParams))
4609
4713
  else:
4610
4714
  response = await self.privateSpotGetOrdersOrderId(self.extend(request, requestParams))
4611
4715
  elif type == 'swap':
4612
- if stop:
4716
+ if trigger:
4613
4717
  response = await self.privateFuturesGetSettlePriceOrdersOrderId(self.extend(request, requestParams))
4614
4718
  else:
4615
4719
  response = await self.privateFuturesGetSettleOrdersOrderId(self.extend(request, requestParams))
4616
4720
  elif type == 'future':
4617
- if stop:
4721
+ if trigger:
4618
4722
  response = await self.privateDeliveryGetSettlePriceOrdersOrderId(self.extend(request, requestParams))
4619
4723
  else:
4620
4724
  response = await self.privateDeliveryGetSettleOrdersOrderId(self.extend(request, requestParams))
@@ -4635,7 +4739,7 @@ class gate(Exchange, ImplicitAPI):
4635
4739
  :param int [since]: the earliest time in ms to fetch open orders for
4636
4740
  :param int [limit]: the maximum number of open orders structures to retrieve
4637
4741
  :param dict [params]: extra parameters specific to the exchange API endpoint
4638
- :param bool [params.stop]: True for fetching stop orders
4742
+ :param bool [params.trigger]: True for fetching trigger orders
4639
4743
  :param str [params.type]: spot, margin, swap or future, if not provided self.options['defaultType'] is used
4640
4744
  :param str [params.marginMode]: 'cross' or 'isolated' - marginMode for type='margin', if not provided self.options['defaultMarginMode'] is used
4641
4745
  :param bool [params.unifiedAccount]: set to True for fetching unified account orders
@@ -4660,7 +4764,7 @@ class gate(Exchange, ImplicitAPI):
4660
4764
  :param int [since]: the earliest time in ms to fetch orders for
4661
4765
  :param int [limit]: the maximum number of order structures to retrieve
4662
4766
  :param dict [params]: extra parameters specific to the exchange API endpoint
4663
- :param bool [params.stop]: True for fetching stop orders
4767
+ :param bool [params.trigger]: True for fetching trigger orders
4664
4768
  :param str [params.type]: spot, swap or future, if not provided self.options['defaultType'] is used
4665
4769
  :param str [params.marginMode]: 'cross' or 'isolated' - marginMode for margin trading if not provided self.options['defaultMarginMode'] is used
4666
4770
  :param boolean [params.historical]: *swap only* True for using historical endpoint
@@ -4834,7 +4938,7 @@ class gate(Exchange, ImplicitAPI):
4834
4938
  # }
4835
4939
  # ]
4836
4940
  #
4837
- # spot stop
4941
+ # spot trigger
4838
4942
  #
4839
4943
  # [
4840
4944
  # {
@@ -4929,31 +5033,31 @@ class gate(Exchange, ImplicitAPI):
4929
5033
  :param str id: Order id
4930
5034
  :param str symbol: Unified market symbol
4931
5035
  :param dict [params]: Parameters specified by the exchange api
4932
- :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
4933
5037
  :param bool [params.unifiedAccount]: set to True for canceling unified account orders
4934
5038
  :returns: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
4935
5039
  """
4936
5040
  await self.load_markets()
4937
5041
  await self.load_unified_status()
4938
5042
  market = None if (symbol is None) else self.market(symbol)
4939
- 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)
4940
5044
  params = self.omit(params, ['is_stop_order', 'stop', 'trigger'])
4941
5045
  type, query = self.handle_market_type_and_params('cancelOrder', market, params)
4942
- 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)
4943
5047
  request['order_id'] = id
4944
5048
  response = None
4945
5049
  if type == 'spot' or type == 'margin':
4946
- if stop:
5050
+ if trigger:
4947
5051
  response = await self.privateSpotDeletePriceOrdersOrderId(self.extend(request, requestParams))
4948
5052
  else:
4949
5053
  response = await self.privateSpotDeleteOrdersOrderId(self.extend(request, requestParams))
4950
5054
  elif type == 'swap':
4951
- if stop:
5055
+ if trigger:
4952
5056
  response = await self.privateFuturesDeleteSettlePriceOrdersOrderId(self.extend(request, requestParams))
4953
5057
  else:
4954
5058
  response = await self.privateFuturesDeleteSettleOrdersOrderId(self.extend(request, requestParams))
4955
5059
  elif type == 'future':
4956
- if stop:
5060
+ if trigger:
4957
5061
  response = await self.privateDeliveryDeleteSettlePriceOrdersOrderId(self.extend(request, requestParams))
4958
5062
  else:
4959
5063
  response = await self.privateDeliveryDeleteSettleOrdersOrderId(self.extend(request, requestParams))
@@ -5143,23 +5247,23 @@ class gate(Exchange, ImplicitAPI):
5143
5247
  await self.load_markets()
5144
5248
  await self.load_unified_status()
5145
5249
  market = None if (symbol is None) else self.market(symbol)
5146
- stop = self.safe_bool_2(params, 'stop', 'trigger')
5250
+ trigger = self.safe_bool_2(params, 'stop', 'trigger')
5147
5251
  params = self.omit(params, ['stop', 'trigger'])
5148
5252
  type, query = self.handle_market_type_and_params('cancelAllOrders', market, params)
5149
- 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)
5150
5254
  response = None
5151
5255
  if type == 'spot' or type == 'margin':
5152
- if stop:
5256
+ if trigger:
5153
5257
  response = await self.privateSpotDeletePriceOrders(self.extend(request, requestParams))
5154
5258
  else:
5155
5259
  response = await self.privateSpotDeleteOrders(self.extend(request, requestParams))
5156
5260
  elif type == 'swap':
5157
- if stop:
5261
+ if trigger:
5158
5262
  response = await self.privateFuturesDeleteSettlePriceOrders(self.extend(request, requestParams))
5159
5263
  else:
5160
5264
  response = await self.privateFuturesDeleteSettleOrders(self.extend(request, requestParams))
5161
5265
  elif type == 'future':
5162
- if stop:
5266
+ if trigger:
5163
5267
  response = await self.privateDeliveryDeleteSettlePriceOrders(self.extend(request, requestParams))
5164
5268
  else:
5165
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
 
@@ -56,6 +58,8 @@ class hyperliquid(Exchange, ImplicitAPI):
56
58
  'createOrder': True,
57
59
  'createOrders': True,
58
60
  'createReduceOnlyOrder': True,
61
+ 'createStopOrder': True,
62
+ 'createTriggerOrder': True,
59
63
  'editOrder': True,
60
64
  'fetchAccounts': False,
61
65
  'fetchBalance': True,
@@ -209,9 +213,11 @@ class hyperliquid(Exchange, ImplicitAPI):
209
213
  'User or API Wallet ': InvalidOrder,
210
214
  'Order has invalid size': InvalidOrder,
211
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,
212
218
  },
213
219
  },
214
- 'precisionMode': DECIMAL_PLACES,
220
+ 'precisionMode': TICK_SIZE,
215
221
  'commonCurrencies': {
216
222
  },
217
223
  'options': {
@@ -360,6 +366,48 @@ class hyperliquid(Exchange, ImplicitAPI):
360
366
  result.append(data)
361
367
  return self.parse_markets(result)
362
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
+
363
411
  async def fetch_spot_markets(self, params={}) -> List[Market]:
364
412
  """
365
413
  retrieves data on all spot markets for hyperliquid
@@ -449,7 +497,11 @@ class hyperliquid(Exchange, ImplicitAPI):
449
497
  symbol = base + '/' + quote
450
498
  innerBaseTokenInfo = self.safe_dict(baseTokenInfo, 'spec', baseTokenInfo)
451
499
  # innerQuoteTokenInfo = self.safe_dict(quoteTokenInfo, 'spec', quoteTokenInfo)
452
- 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)
453
505
  # quotePrecision = self.parse_number(self.parse_precision(self.safe_string(innerQuoteTokenInfo, 'szDecimals')))
454
506
  baseId = self.number_to_string(i + 10000)
455
507
  markets.append(self.safe_market_structure({
@@ -480,8 +532,8 @@ class hyperliquid(Exchange, ImplicitAPI):
480
532
  'strike': None,
481
533
  'optionType': None,
482
534
  'precision': {
483
- 'amount': amountPrecision, # decimal places
484
- '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)),
485
537
  },
486
538
  'limits': {
487
539
  'leverage': {
@@ -542,7 +594,11 @@ class hyperliquid(Exchange, ImplicitAPI):
542
594
  fees = self.safe_dict(self.fees, 'swap', {})
543
595
  taker = self.safe_number(fees, 'taker')
544
596
  maker = self.safe_number(fees, 'maker')
545
- 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)
546
602
  return self.safe_market_structure({
547
603
  'id': baseId,
548
604
  'symbol': symbol,
@@ -570,8 +626,8 @@ class hyperliquid(Exchange, ImplicitAPI):
570
626
  'strike': None,
571
627
  'optionType': None,
572
628
  'precision': {
573
- 'amount': amountPrecision, # decimal places
574
- '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)),
575
631
  },
576
632
  'limits': {
577
633
  'leverage': {
@@ -1038,10 +1094,13 @@ class hyperliquid(Exchange, ImplicitAPI):
1038
1094
 
1039
1095
  def price_to_precision(self, symbol: str, price) -> str:
1040
1096
  market = self.market(symbol)
1041
- # https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/tick-and-lot-size
1042
- result = self.decimal_to_precision(price, ROUND, 5, SIGNIFICANT_DIGITS, self.paddingMode)
1043
- decimalParsedResult = self.decimal_to_precision(result, ROUND, market['precision']['price'], self.precisionMode, self.paddingMode)
1044
- 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)
1045
1104
 
1046
1105
  def hash_message(self, message):
1047
1106
  return '0x' + self.hash(message, 'keccak', 'hex')
@@ -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
  async 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': {