ccxt 4.4.68__py2.py3-none-any.whl → 4.4.70__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 (43) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/bybit.py +4 -0
  3. ccxt/abstract/myokx.py +3 -0
  4. ccxt/abstract/okx.py +3 -0
  5. ccxt/abstract/paradex.py +23 -0
  6. ccxt/abstract/tradeogre.py +2 -1
  7. ccxt/async_support/__init__.py +1 -1
  8. ccxt/async_support/base/exchange.py +5 -1
  9. ccxt/async_support/binance.py +17 -3
  10. ccxt/async_support/bitget.py +47 -262
  11. ccxt/async_support/bitstamp.py +2 -3
  12. ccxt/async_support/bybit.py +7 -0
  13. ccxt/async_support/coinbase.py +24 -9
  14. ccxt/async_support/cryptomus.py +122 -6
  15. ccxt/async_support/hyperliquid.py +17 -8
  16. ccxt/async_support/okx.py +4 -0
  17. ccxt/async_support/paradex.py +173 -5
  18. ccxt/async_support/phemex.py +2 -2
  19. ccxt/async_support/tradeogre.py +31 -11
  20. ccxt/async_support/whitebit.py +210 -2
  21. ccxt/base/exchange.py +1 -2
  22. ccxt/binance.py +17 -3
  23. ccxt/bitget.py +47 -262
  24. ccxt/bitstamp.py +2 -3
  25. ccxt/bybit.py +7 -0
  26. ccxt/coinbase.py +24 -9
  27. ccxt/cryptomus.py +122 -6
  28. ccxt/hyperliquid.py +17 -8
  29. ccxt/okx.py +4 -0
  30. ccxt/paradex.py +173 -5
  31. ccxt/phemex.py +2 -2
  32. ccxt/pro/__init__.py +1 -1
  33. ccxt/pro/bitget.py +28 -3
  34. ccxt/pro/bybit.py +81 -37
  35. ccxt/test/tests_async.py +25 -3
  36. ccxt/test/tests_sync.py +25 -3
  37. ccxt/tradeogre.py +31 -11
  38. ccxt/whitebit.py +210 -2
  39. {ccxt-4.4.68.dist-info → ccxt-4.4.70.dist-info}/METADATA +4 -4
  40. {ccxt-4.4.68.dist-info → ccxt-4.4.70.dist-info}/RECORD +43 -43
  41. {ccxt-4.4.68.dist-info → ccxt-4.4.70.dist-info}/LICENSE.txt +0 -0
  42. {ccxt-4.4.68.dist-info → ccxt-4.4.70.dist-info}/WHEEL +0 -0
  43. {ccxt-4.4.68.dist-info → ccxt-4.4.70.dist-info}/top_level.txt +0 -0
ccxt/coinbase.py CHANGED
@@ -335,6 +335,7 @@ class coinbase(Exchange, ImplicitAPI):
335
335
  'INSUFFICIENT_FUND': BadRequest,
336
336
  'PERMISSION_DENIED': PermissionDenied,
337
337
  'INVALID_ARGUMENT': BadRequest,
338
+ 'PREVIEW_STOP_PRICE_ABOVE_LAST_TRADE_PRICE': InvalidOrder,
338
339
  },
339
340
  'broad': {
340
341
  'request timestamp expired': InvalidNonce, # {"errors":[{"id":"authentication_error","message":"request timestamp expired"}]}
@@ -4088,6 +4089,7 @@ class coinbase(Exchange, ImplicitAPI):
4088
4089
  'amount': self.number_to_string(amount),
4089
4090
  'currency': code.upper(), # need to use code in case depositing USD etc.
4090
4091
  'payment_method': id,
4092
+ 'commit': True, # otheriwse the deposit does not go through
4091
4093
  }
4092
4094
  response = self.v2PrivatePostAccountsAccountIdDeposits(self.extend(request, params))
4093
4095
  #
@@ -4690,11 +4692,6 @@ class coinbase(Exchange, ImplicitAPI):
4690
4692
  return result
4691
4693
 
4692
4694
  def parse_portfolio_details(self, portfolioData: dict):
4693
- """
4694
- Parse a Coinbase portfolio JSON object and extract relevant trading information.
4695
- :param Dict portfolioData: The JSON response containing portfolio details
4696
- :returns any[]: List of dictionaries with parsed portfolio position data
4697
- """
4698
4695
  breakdown = portfolioData['breakdown']
4699
4696
  portfolioInfo = self.safe_dict(breakdown, 'portfolio', {})
4700
4697
  portfolioName = self.safe_string(portfolioInfo, 'name', 'Unknown')
@@ -4867,19 +4864,37 @@ class coinbase(Exchange, ImplicitAPI):
4867
4864
  # ]
4868
4865
  # }
4869
4866
  # or
4870
- # {
4867
+ # {
4868
+ # "success": False,
4869
+ # "error_response": {
4871
4870
  # "error": "UNKNOWN_FAILURE_REASON",
4872
4871
  # "message": "",
4873
4872
  # "error_details": "",
4874
- # "preview_failure_reason": "PREVIEW_STOP_PRICE_BELOW_LAST_TRADE_PRICE"
4875
- # }
4873
+ # "preview_failure_reason": "PREVIEW_STOP_PRICE_ABOVE_LAST_TRADE_PRICE"
4874
+ # },
4875
+ # "order_configuration": {
4876
+ # "stop_limit_stop_limit_gtc": {
4877
+ # "base_size": "0.0001",
4878
+ # "limit_price": "2000",
4879
+ # "stop_price": "2005",
4880
+ # "stop_direction": "STOP_DIRECTION_STOP_DOWN",
4881
+ # "reduce_only": False
4882
+ # }
4883
+ # }
4884
+ # }
4876
4885
  #
4877
4886
  errorCode = self.safe_string(response, 'error')
4878
4887
  if errorCode is not None:
4879
- errorMessage = self.safe_string_2(response, 'error_description', 'preview_failure_reason')
4888
+ errorMessage = self.safe_string_2(response, 'error_description', 'error')
4880
4889
  self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
4881
4890
  self.throw_broadly_matched_exception(self.exceptions['broad'], errorMessage, feedback)
4882
4891
  raise ExchangeError(feedback)
4892
+ errorResponse = self.safe_dict(response, 'error_response')
4893
+ if errorResponse is not None:
4894
+ errorMessageInner = self.safe_string_2(errorResponse, 'preview_failure_reason', 'preview_failure_reason')
4895
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errorMessageInner, feedback)
4896
+ self.throw_broadly_matched_exception(self.exceptions['broad'], errorMessageInner, feedback)
4897
+ raise ExchangeError(feedback)
4883
4898
  errors = self.safe_list(response, 'errors')
4884
4899
  if errors is not None:
4885
4900
  if isinstance(errors, list):
ccxt/cryptomus.py CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.cryptomus import ImplicitAPI
8
- from ccxt.base.types import Any, Balances, Currencies, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade
8
+ from ccxt.base.types import Any, Balances, Currencies, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFees
9
9
  from typing import List
10
10
  from ccxt.base.errors import ExchangeError
11
11
  from ccxt.base.errors import ArgumentsRequired
@@ -23,7 +23,7 @@ class cryptomus(Exchange, ImplicitAPI):
23
23
  'name': 'Cryptomus',
24
24
  'countries': ['CA'],
25
25
  'rateLimit': 100, # todo check
26
- 'version': 'v1',
26
+ 'version': 'v2',
27
27
  'certified': False,
28
28
  'pro': False,
29
29
  'has': {
@@ -105,7 +105,7 @@ class cryptomus(Exchange, ImplicitAPI):
105
105
  'fetchTime': False,
106
106
  'fetchTrades': True,
107
107
  'fetchTradingFee': False,
108
- 'fetchTradingFees': False,
108
+ 'fetchTradingFees': True,
109
109
  'fetchTransactions': False,
110
110
  'fetchTransfers': False,
111
111
  'fetchWithdrawals': False,
@@ -143,9 +143,9 @@ class cryptomus(Exchange, ImplicitAPI):
143
143
  'private': {
144
144
  'get': {
145
145
  'v2/user-api/exchange/orders': 1, # done
146
- 'v2/user-api/exchange/orders/history': 1,
146
+ 'v2/user-api/exchange/orders/history': 1, # done
147
147
  'v2/user-api/exchange/account/balance': 1, # done
148
- 'v2/user-api/exchange/account/tariffs': 1,
148
+ 'v2/user-api/exchange/account/tariffs': 1, # done
149
149
  'v2/user-api/payment/services': 1,
150
150
  'v2/user-api/payout/services': 1,
151
151
  'v2/user-api/transaction/list': 1,
@@ -231,7 +231,9 @@ class cryptomus(Exchange, ImplicitAPI):
231
231
  def fetch_markets(self, params={}) -> List[Market]:
232
232
  """
233
233
  retrieves data on all markets for the exchange
234
+
234
235
  https://doc.cryptomus.com/personal/market-cap/tickers
236
+
235
237
  :param dict [params]: extra parameters specific to the exchange API endpoint
236
238
  :returns dict[]: an array of objects representing market data
237
239
  """
@@ -339,7 +341,9 @@ class cryptomus(Exchange, ImplicitAPI):
339
341
  def fetch_currencies(self, params={}) -> Currencies:
340
342
  """
341
343
  fetches all available currencies on an exchange
344
+
342
345
  https://doc.cryptomus.com/personal/market-cap/assets
346
+
343
347
  :param dict [params]: extra parameters specific to the exchange API endpoint
344
348
  :returns dict: an associative dictionary of currencies
345
349
  """
@@ -466,7 +470,9 @@ class cryptomus(Exchange, ImplicitAPI):
466
470
  def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
467
471
  """
468
472
  fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
473
+
469
474
  https://doc.cryptomus.com/personal/market-cap/tickers
475
+
470
476
  :param str[] [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
471
477
  :param dict [params]: extra parameters specific to the exchange API endpoint
472
478
  :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -528,7 +534,9 @@ class cryptomus(Exchange, ImplicitAPI):
528
534
  def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
529
535
  """
530
536
  fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
537
+
531
538
  https://doc.cryptomus.com/personal/market-cap/orderbook
539
+
532
540
  :param str symbol: unified symbol of the market to fetch the order book for
533
541
  :param int [limit]: the maximum amount of order book entries to return
534
542
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -570,7 +578,9 @@ class cryptomus(Exchange, ImplicitAPI):
570
578
  def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
571
579
  """
572
580
  get the list of most recent trades for a particular symbol
581
+
573
582
  https://doc.cryptomus.com/personal/market-cap/trades
583
+
574
584
  :param str symbol: unified symbol of the market to fetch trades for
575
585
  :param int [since]: timestamp in ms of the earliest trade to fetch
576
586
  :param int [limit]: the maximum amount of trades to fetch(maximum value is 100)
@@ -634,7 +644,9 @@ class cryptomus(Exchange, ImplicitAPI):
634
644
  def fetch_balance(self, params={}) -> Balances:
635
645
  """
636
646
  query for balance and get the amount of funds available for trading or funds locked in orders
647
+
637
648
  https://doc.cryptomus.com/personal/converts/balance
649
+
638
650
  :param dict [params]: extra parameters specific to the exchange API endpoint
639
651
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
640
652
  """
@@ -679,8 +691,10 @@ class cryptomus(Exchange, ImplicitAPI):
679
691
  def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
680
692
  """
681
693
  create a trade order
694
+
682
695
  https://doc.cryptomus.com/personal/exchange/market-order-creation
683
696
  https://doc.cryptomus.com/personal/exchange/limit-order-creation
697
+
684
698
  :param str symbol: unified symbol of the market to create an order in
685
699
  :param str type: 'market' or 'limit' or for spot
686
700
  :param str side: 'buy' or 'sell'
@@ -688,7 +702,6 @@ class cryptomus(Exchange, ImplicitAPI):
688
702
  :param float [price]: the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders(only for limit orders)
689
703
  :param dict [params]: extra parameters specific to the exchange API endpoint
690
704
  :param float [params.cost]: *market buy only* the quote quantity that can be used alternative for the amount
691
- :param dict [params]: extra parameters specific to the exchange API endpoint
692
705
  :param str [params.clientOrderId]: a unique identifier for the order(optional)
693
706
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
694
707
  """
@@ -742,7 +755,9 @@ class cryptomus(Exchange, ImplicitAPI):
742
755
  def cancel_order(self, id: str, symbol: Str = None, params={}):
743
756
  """
744
757
  cancels an open limit order
758
+
745
759
  https://doc.cryptomus.com/personal/exchange/limit-order-cancellation
760
+
746
761
  :param str id: order id
747
762
  :param str symbol: unified symbol of the market the order was made in(not used in cryptomus)
748
763
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -762,7 +777,9 @@ class cryptomus(Exchange, ImplicitAPI):
762
777
  def fetch_canceled_and_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
763
778
  """
764
779
  fetches information on multiple orders made by the user
780
+
765
781
  https://doc.cryptomus.com/personal/exchange/history-of-completed-orders
782
+
766
783
  :param str symbol: unified market symbol of the market orders were made in(not used in cryptomus)
767
784
  :param int [since]: the earliest time in ms to fetch orders for(not used in cryptomus)
768
785
  :param int [limit]: the maximum number of order structures to retrieve(not used in cryptomus)
@@ -832,7 +849,9 @@ class cryptomus(Exchange, ImplicitAPI):
832
849
  def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
833
850
  """
834
851
  fetch all unfilled currently open orders
852
+
835
853
  https://doc.cryptomus.com/personal/exchange/list-of-active-orders
854
+
836
855
  :param str symbol: unified market symbol
837
856
  :param int [since]: the earliest time in ms to fetch open orders for(not used in cryptomus)
838
857
  :param int [limit]: the maximum number of open orders structures to retrieve(not used in cryptomus)
@@ -993,6 +1012,103 @@ class cryptomus(Exchange, ImplicitAPI):
993
1012
  }
994
1013
  return self.safe_string(statuses, status, status)
995
1014
 
1015
+ def fetch_trading_fees(self, params={}) -> TradingFees:
1016
+ """
1017
+ fetch the trading fees for multiple markets
1018
+
1019
+ https://trade-docs.coinlist.co/?javascript--nodejs#list-fees
1020
+
1021
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1022
+ :returns dict: a dictionary of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>` indexed by market symbols
1023
+ """
1024
+ response = self.privateGetV2UserApiExchangeAccountTariffs(params)
1025
+ #
1026
+ # {
1027
+ # result: {
1028
+ # equivalent_currency_code: 'USD',
1029
+ # current_tariff_step: {
1030
+ # step: '0',
1031
+ # from_turnover: '0.00000000',
1032
+ # maker_percent: '0.08',
1033
+ # taker_percent: '0.1'
1034
+ # },
1035
+ # tariff_steps: [
1036
+ # {
1037
+ # step: '0',
1038
+ # from_turnover: '0.00000000',
1039
+ # maker_percent: '0.08',
1040
+ # taker_percent: '0.1'
1041
+ # },
1042
+ # {
1043
+ # step: '1',
1044
+ # from_turnover: '100001.00000000',
1045
+ # maker_percent: '0.06',
1046
+ # taker_percent: '0.095'
1047
+ # },
1048
+ # {
1049
+ # step: '2',
1050
+ # from_turnover: '250001.00000000',
1051
+ # maker_percent: '0.055',
1052
+ # taker_percent: '0.085'
1053
+ # },
1054
+ # {
1055
+ # step: '3',
1056
+ # from_turnover: '500001.00000000',
1057
+ # maker_percent: '0.05',
1058
+ # taker_percent: '0.075'
1059
+ # },
1060
+ # {
1061
+ # step: '4',
1062
+ # from_turnover: '2500001.00000000',
1063
+ # maker_percent: '0.04',
1064
+ # taker_percent: '0.07'
1065
+ # }
1066
+ # ],
1067
+ # daily_turnover: '0.00000000',
1068
+ # monthly_turnover: '77.52062617',
1069
+ # circulation_funds: '25.48900443'
1070
+ # }
1071
+ # }
1072
+ #
1073
+ data = self.safe_dict(response, 'result', {})
1074
+ currentFeeTier = self.safe_dict(data, 'current_tariff_step', {})
1075
+ makerFee = self.safe_string(currentFeeTier, 'maker_percent')
1076
+ takerFee = self.safe_string(currentFeeTier, 'taker_percent')
1077
+ makerFee = Precise.string_div(makerFee, '100')
1078
+ takerFee = Precise.string_div(takerFee, '100')
1079
+ feeTiers = self.safe_list(data, 'tariff_steps', [])
1080
+ result: dict = {}
1081
+ tiers = self.parse_fee_tiers(feeTiers)
1082
+ for i in range(0, len(self.symbols)):
1083
+ symbol = self.symbols[i]
1084
+ result[symbol] = {
1085
+ 'info': response,
1086
+ 'symbol': symbol,
1087
+ 'maker': self.parse_number(makerFee),
1088
+ 'taker': self.parse_number(takerFee),
1089
+ 'percentage': True,
1090
+ 'tierBased': True,
1091
+ 'tiers': tiers,
1092
+ }
1093
+ return result
1094
+
1095
+ def parse_fee_tiers(self, feeTiers, market: Market = None):
1096
+ takerFees = []
1097
+ makerFees = []
1098
+ for i in range(0, len(feeTiers)):
1099
+ tier = feeTiers[i]
1100
+ turnover = self.safe_number(tier, 'from_turnover')
1101
+ taker = self.safe_string(tier, 'taker_percent')
1102
+ maker = self.safe_string(tier, 'maker_percent')
1103
+ maker = Precise.string_div(maker, '100')
1104
+ taker = Precise.string_div(taker, '100')
1105
+ makerFees.append([turnover, self.parse_number(maker)])
1106
+ takerFees.append([turnover, self.parse_number(taker)])
1107
+ return {
1108
+ 'maker': makerFees,
1109
+ 'taker': takerFees,
1110
+ }
1111
+
996
1112
  def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
997
1113
  endpoint = self.implode_params(path, params)
998
1114
  params = self.omit(params, self.extract_params(path))
ccxt/hyperliquid.py CHANGED
@@ -837,7 +837,7 @@ class hyperliquid(Exchange, ImplicitAPI):
837
837
  'info': response,
838
838
  'USDC': {
839
839
  'total': self.safe_number(data, 'accountValue'),
840
- 'free': self.safe_number(response, 'withdrawable'),
840
+ 'used': self.safe_number(data, 'totalMarginUsed'),
841
841
  },
842
842
  }
843
843
  timestamp = self.safe_integer(response, 'time')
@@ -1756,11 +1756,12 @@ class hyperliquid(Exchange, ImplicitAPI):
1756
1756
  isTrigger = (stopLossPrice or takeProfitPrice)
1757
1757
  reduceOnly = self.safe_bool(orderParams, 'reduceOnly', False)
1758
1758
  orderParams = self.omit(orderParams, ['slippage', 'timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'clientOrderId', 'client_id', 'postOnly', 'reduceOnly'])
1759
- px = str(price)
1759
+ px = self.number_to_string(price)
1760
1760
  if isMarket:
1761
- px = str(Precise.string_mul(price), Precise.string_add('1', slippage)) if (isBuy) else str(Precise.string_mul(price), Precise.string_sub('1', slippage))
1761
+ px = Precise.string_mul(px, Precise.string_add('1', slippage)) if (isBuy) else Precise.string_mul(px, Precise.string_sub('1', slippage))
1762
+ px = self.price_to_precision(symbol, px)
1762
1763
  else:
1763
- px = self.price_to_precision(symbol, str(price))
1764
+ px = self.price_to_precision(symbol, px)
1764
1765
  sz = self.amount_to_precision(symbol, amount)
1765
1766
  orderType: dict = {}
1766
1767
  if isTrigger:
@@ -2242,6 +2243,10 @@ class hyperliquid(Exchange, ImplicitAPI):
2242
2243
  side = 'sell' if (side == 'A') else 'buy'
2243
2244
  totalAmount = self.safe_string_2(entry, 'origSz', 'totalSz')
2244
2245
  remaining = self.safe_string(entry, 'sz')
2246
+ tif = self.safe_string_upper(entry, 'tif')
2247
+ postOnly = None
2248
+ if tif is not None:
2249
+ postOnly = (tif == 'ALO')
2245
2250
  return self.safe_order({
2246
2251
  'info': order,
2247
2252
  'id': self.safe_string(entry, 'oid'),
@@ -2252,8 +2257,8 @@ class hyperliquid(Exchange, ImplicitAPI):
2252
2257
  'lastUpdateTimestamp': self.safe_integer(order, 'statusTimestamp'),
2253
2258
  'symbol': symbol,
2254
2259
  'type': self.parse_order_type(self.safe_string_lower(entry, 'orderType')),
2255
- 'timeInForce': self.safe_string_upper(entry, 'tif'),
2256
- 'postOnly': None,
2260
+ 'timeInForce': tif,
2261
+ 'postOnly': postOnly,
2257
2262
  'reduceOnly': self.safe_bool(entry, 'reduceOnly'),
2258
2263
  'side': side,
2259
2264
  'price': self.safe_string(entry, 'limitPx'),
@@ -2371,6 +2376,10 @@ class hyperliquid(Exchange, ImplicitAPI):
2371
2376
  if side is not None:
2372
2377
  side = 'sell' if (side == 'A') else 'buy'
2373
2378
  fee = self.safe_string(trade, 'fee')
2379
+ takerOrMaker = None
2380
+ crossed = self.safe_bool(trade, 'crossed')
2381
+ if crossed is not None:
2382
+ takerOrMaker = 'taker' if crossed else 'maker'
2374
2383
  return self.safe_trade({
2375
2384
  'info': trade,
2376
2385
  'timestamp': timestamp,
@@ -2380,7 +2389,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2380
2389
  'order': self.safe_string(trade, 'oid'),
2381
2390
  'type': None,
2382
2391
  'side': side,
2383
- 'takerOrMaker': None,
2392
+ 'takerOrMaker': takerOrMaker,
2384
2393
  'price': price,
2385
2394
  'amount': amount,
2386
2395
  'cost': None,
@@ -2927,7 +2936,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2927
2936
  'tagTo': None,
2928
2937
  'tagFrom': None,
2929
2938
  'type': None,
2930
- 'amount': self.safe_integer(delta, 'usdc'),
2939
+ 'amount': self.safe_number(delta, 'usdc'),
2931
2940
  'currency': None,
2932
2941
  'status': self.safe_string(transaction, 'status'),
2933
2942
  'updated': None,
ccxt/okx.py CHANGED
@@ -332,7 +332,9 @@ class okx(Exchange, ImplicitAPI):
332
332
  'trade/easy-convert-currency-list': 20,
333
333
  'trade/easy-convert-history': 20,
334
334
  'trade/one-click-repay-currency-list': 20,
335
+ 'trade/one-click-repay-currency-list-v2': 20,
335
336
  'trade/one-click-repay-history': 20,
337
+ 'trade/one-click-repay-history-v2': 20,
336
338
  'trade/account-rate-limit': 1,
337
339
  # asset
338
340
  'asset/currencies': 5 / 3,
@@ -489,6 +491,7 @@ class okx(Exchange, ImplicitAPI):
489
491
  'trade/cancel-advance-algos': 1,
490
492
  'trade/easy-convert': 20,
491
493
  'trade/one-click-repay': 20,
494
+ 'trade/one-click-repay-v2': 20,
492
495
  'trade/mass-cancel': 4,
493
496
  'trade/cancel-all-after': 10,
494
497
  # asset
@@ -3043,6 +3046,7 @@ class okx(Exchange, ImplicitAPI):
3043
3046
  :param str [params.trailingPercent]: the percent to trail away from the current market price
3044
3047
  :param str [params.tpOrdKind]: 'condition' or 'limit', the default is 'condition'
3045
3048
  :param bool [params.hedged]: *swap and future only* True for hedged mode, False for one way mode
3049
+ :param str [params.marginMode]: 'cross' or 'isolated', the default is 'cross'
3046
3050
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
3047
3051
  """
3048
3052
  self.load_markets()
ccxt/paradex.py CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.paradex import ImplicitAPI
8
- from ccxt.base.types import Any, Balances, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
8
+ from ccxt.base.types import Any, Balances, Currency, Int, Leverage, MarginMode, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
9
9
  from typing import List
10
10
  from ccxt.base.errors import ExchangeError
11
11
  from ccxt.base.errors import AuthenticationError
@@ -79,10 +79,10 @@ class paradex(Exchange, ImplicitAPI):
79
79
  'fetchIsolatedBorrowRate': False,
80
80
  'fetchIsolatedBorrowRates': False,
81
81
  'fetchLedger': False,
82
- 'fetchLeverage': False,
82
+ 'fetchLeverage': True,
83
83
  'fetchLeverageTiers': False,
84
84
  'fetchLiquidations': True,
85
- 'fetchMarginMode': None,
85
+ 'fetchMarginMode': True,
86
86
  'fetchMarketLeverageTiers': False,
87
87
  'fetchMarkets': True,
88
88
  'fetchMarkOHLCV': False,
@@ -116,8 +116,8 @@ class paradex(Exchange, ImplicitAPI):
116
116
  'repayCrossMargin': False,
117
117
  'repayIsolatedMargin': False,
118
118
  'sandbox': True,
119
- 'setLeverage': False,
120
- 'setMarginMode': False,
119
+ 'setLeverage': True,
120
+ 'setMarginMode': True,
121
121
  'setPositionMode': False,
122
122
  'transfer': False,
123
123
  'withdraw': False,
@@ -159,12 +159,23 @@ class paradex(Exchange, ImplicitAPI):
159
159
  'system/state': 1,
160
160
  'system/time': 1,
161
161
  'trades': 1,
162
+ 'vaults': 1,
163
+ 'vaults/balance': 1,
164
+ 'vaults/config': 1,
165
+ 'vaults/history': 1,
166
+ 'vaults/positions': 1,
167
+ 'vaults/summary': 1,
168
+ 'vaults/transfers': 1,
162
169
  },
163
170
  },
164
171
  'private': {
165
172
  'get': {
166
173
  'account': 1,
174
+ 'account/info': 1,
175
+ 'account/history': 1,
176
+ 'account/margin': 1,
167
177
  'account/profile': 1,
178
+ 'account/subaccounts': 1,
168
179
  'balance': 1,
169
180
  'fills': 1,
170
181
  'funding/payments': 1,
@@ -177,20 +188,34 @@ class paradex(Exchange, ImplicitAPI):
177
188
  'orders/by_client_id/{client_id}': 1,
178
189
  'orders/{order_id}': 1,
179
190
  'points_data/{market}/{program}': 1,
191
+ 'referrals/qr-code': 1,
180
192
  'referrals/summary': 1,
181
193
  'transfers': 1,
194
+ 'algo/orders': 1,
195
+ 'algo/orders-history': 1,
196
+ 'algo/orders/{algo_id}': 1,
197
+ 'vaults/account-summary': 1,
182
198
  },
183
199
  'post': {
200
+ 'account/margin/{market}': 1,
201
+ 'account/profile/max_slippage': 1,
184
202
  'account/profile/referral_code': 1,
185
203
  'account/profile/username': 1,
186
204
  'auth': 1,
187
205
  'onboarding': 1,
188
206
  'orders': 1,
207
+ 'orders/batch': 1,
208
+ 'algo/orders': 1,
209
+ 'vaults': 1,
210
+ },
211
+ 'put': {
212
+ 'orders/{order_id}': 1,
189
213
  },
190
214
  'delete': {
191
215
  'orders': 1,
192
216
  'orders/by_client_id/{client_id}': 1,
193
217
  'orders/{order_id}': 1,
218
+ 'algo/orders/{algo_id}': 1,
194
219
  },
195
220
  },
196
221
  },
@@ -2063,6 +2088,149 @@ class paradex(Exchange, ImplicitAPI):
2063
2088
  }
2064
2089
  return self.safe_string(statuses, status, status)
2065
2090
 
2091
+ def fetch_margin_mode(self, symbol: str, params={}) -> MarginMode:
2092
+ """
2093
+ fetches the margin mode of a specific symbol
2094
+
2095
+ https://docs.api.testnet.paradex.trade/#get-account-margin-configuration
2096
+
2097
+ :param str symbol: unified symbol of the market the order was made in
2098
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2099
+ :returns dict: a `margin mode structure <https://docs.ccxt.com/#/?id=margin-mode-structure>`
2100
+ """
2101
+ self.authenticate_rest()
2102
+ self.load_markets()
2103
+ market = self.market(symbol)
2104
+ request: dict = {
2105
+ 'market': market['id'],
2106
+ }
2107
+ response = self.privateGetAccountMargin(self.extend(request, params))
2108
+ #
2109
+ # {
2110
+ # "account": "0x6343248026a845b39a8a73fbe9c7ef0a841db31ed5c61ec1446aa9d25e54dbc",
2111
+ # "configs": [
2112
+ # {
2113
+ # "market": "SOL-USD-PERP",
2114
+ # "leverage": 50,
2115
+ # "margin_type": "CROSS"
2116
+ # }
2117
+ # ]
2118
+ # }
2119
+ #
2120
+ configs = self.safe_list(response, 'configs')
2121
+ return self.parse_margin_mode(self.safe_dict(configs, 0), market)
2122
+
2123
+ def parse_margin_mode(self, rawMarginMode: dict, market=None) -> MarginMode:
2124
+ marketId = self.safe_string(rawMarginMode, 'market')
2125
+ market = self.safe_market(marketId, market)
2126
+ marginMode = self.safe_string_lower(rawMarginMode, 'margin_type')
2127
+ return {
2128
+ 'info': rawMarginMode,
2129
+ 'symbol': market['symbol'],
2130
+ 'marginMode': marginMode,
2131
+ }
2132
+
2133
+ def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
2134
+ """
2135
+ set margin mode to 'cross' or 'isolated'
2136
+
2137
+ https://docs.api.testnet.paradex.trade/#set-margin-configuration
2138
+
2139
+ :param str marginMode: 'cross' or 'isolated'
2140
+ :param str symbol: unified market symbol
2141
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2142
+ :param float [params.leverage]: the rate of leverage
2143
+ :returns dict: response from the exchange
2144
+ """
2145
+ self.check_required_argument('setMarginMode', symbol, 'symbol')
2146
+ self.authenticate_rest()
2147
+ self.load_markets()
2148
+ market: Market = self.market(symbol)
2149
+ leverage: Str = None
2150
+ leverage, params = self.handle_option_and_params(params, 'setMarginMode', 'leverage', 1)
2151
+ request: dict = {
2152
+ 'market': market['id'],
2153
+ 'leverage': leverage,
2154
+ 'margin_type': self.encode_margin_mode(marginMode),
2155
+ }
2156
+ return self.privatePostAccountMarginMarket(self.extend(request, params))
2157
+
2158
+ def fetch_leverage(self, symbol: str, params={}) -> Leverage:
2159
+ """
2160
+ fetch the set leverage for a market
2161
+
2162
+ https://docs.api.testnet.paradex.trade/#get-account-margin-configuration
2163
+
2164
+ :param str symbol: unified market symbol
2165
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2166
+ :returns dict: a `leverage structure <https://docs.ccxt.com/#/?id=leverage-structure>`
2167
+ """
2168
+ self.authenticate_rest()
2169
+ self.load_markets()
2170
+ market = self.market(symbol)
2171
+ request: dict = {
2172
+ 'market': market['id'],
2173
+ }
2174
+ response = self.privateGetAccountMargin(self.extend(request, params))
2175
+ #
2176
+ # {
2177
+ # "account": "0x6343248026a845b39a8a73fbe9c7ef0a841db31ed5c61ec1446aa9d25e54dbc",
2178
+ # "configs": [
2179
+ # {
2180
+ # "market": "SOL-USD-PERP",
2181
+ # "leverage": 50,
2182
+ # "margin_type": "CROSS"
2183
+ # }
2184
+ # ]
2185
+ # }
2186
+ #
2187
+ configs = self.safe_list(response, 'configs')
2188
+ return self.parse_leverage(self.safe_dict(configs, 0), market)
2189
+
2190
+ def parse_leverage(self, leverage: dict, market: Market = None) -> Leverage:
2191
+ marketId = self.safe_string(leverage, 'market')
2192
+ market = self.safe_market(marketId, market)
2193
+ marginMode = self.safe_string_lower(leverage, 'margin_type')
2194
+ return {
2195
+ 'info': leverage,
2196
+ 'symbol': self.safe_symbol(marketId, market),
2197
+ 'marginMode': marginMode,
2198
+ 'longLeverage': self.safe_integer(leverage, 'leverage'),
2199
+ 'shortLeverage': self.safe_integer(leverage, 'leverage'),
2200
+ }
2201
+
2202
+ def encode_margin_mode(self, mode):
2203
+ modes = {
2204
+ 'cross': 'CROSS',
2205
+ 'isolated': 'ISOLATED',
2206
+ }
2207
+ return self.safe_string(modes, mode, mode)
2208
+
2209
+ def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
2210
+ """
2211
+ set the level of leverage for a market
2212
+
2213
+ https://docs.api.testnet.paradex.trade/#set-margin-configuration
2214
+
2215
+ :param float leverage: the rate of leverage
2216
+ :param str [symbol]: unified market symbol(is mandatory for swap markets)
2217
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2218
+ :param str [params.marginMode]: 'cross' or 'isolated'
2219
+ :returns dict: response from the exchange
2220
+ """
2221
+ self.check_required_argument('setLeverage', symbol, 'symbol')
2222
+ self.authenticate_rest()
2223
+ self.load_markets()
2224
+ market: Market = self.market(symbol)
2225
+ marginMode: Str = None
2226
+ marginMode, params = self.handle_margin_mode_and_params('setLeverage', params, 'cross')
2227
+ request: dict = {
2228
+ 'market': market['id'],
2229
+ 'leverage': leverage,
2230
+ 'margin_type': self.encode_margin_mode(marginMode),
2231
+ }
2232
+ return self.privatePostAccountMarginMarket(self.extend(request, params))
2233
+
2066
2234
  def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
2067
2235
  url = self.implode_hostname(self.urls['api'][self.version]) + '/' + self.implode_params(path, params)
2068
2236
  query = self.omit(params, self.extract_params(path))