ccxt 4.4.63__py2.py3-none-any.whl → 4.4.68__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 (60) hide show
  1. ccxt/__init__.py +5 -3
  2. ccxt/abstract/binance.py +1 -0
  3. ccxt/abstract/binancecoinm.py +1 -0
  4. ccxt/abstract/binanceus.py +1 -0
  5. ccxt/abstract/binanceusdm.py +1 -0
  6. ccxt/abstract/cryptomus.py +20 -0
  7. ccxt/abstract/derive.py +117 -0
  8. ccxt/abstract/tradeogre.py +1 -0
  9. ccxt/abstract/whitebit.py +16 -0
  10. ccxt/async_support/__init__.py +5 -3
  11. ccxt/async_support/base/exchange.py +6 -5
  12. ccxt/async_support/binance.py +8 -6
  13. ccxt/async_support/bitget.py +22 -12
  14. ccxt/async_support/bitrue.py +6 -3
  15. ccxt/async_support/bybit.py +1 -1
  16. ccxt/async_support/coinbase.py +73 -2
  17. ccxt/async_support/cryptocom.py +2 -0
  18. ccxt/async_support/cryptomus.py +1041 -0
  19. ccxt/async_support/derive.py +2530 -0
  20. ccxt/async_support/gate.py +5 -1
  21. ccxt/async_support/htx.py +19 -5
  22. ccxt/async_support/hyperliquid.py +108 -68
  23. ccxt/async_support/luno.py +113 -1
  24. ccxt/async_support/paradex.py +51 -12
  25. ccxt/async_support/tradeogre.py +132 -13
  26. ccxt/async_support/whitebit.py +276 -2
  27. ccxt/base/exchange.py +13 -4
  28. ccxt/binance.py +8 -6
  29. ccxt/bitget.py +22 -12
  30. ccxt/bitrue.py +6 -3
  31. ccxt/bybit.py +1 -1
  32. ccxt/coinbase.py +73 -2
  33. ccxt/cryptocom.py +2 -0
  34. ccxt/cryptomus.py +1041 -0
  35. ccxt/derive.py +2529 -0
  36. ccxt/gate.py +5 -1
  37. ccxt/htx.py +19 -5
  38. ccxt/hyperliquid.py +108 -68
  39. ccxt/luno.py +113 -1
  40. ccxt/paradex.py +51 -12
  41. ccxt/pro/__init__.py +3 -3
  42. ccxt/pro/bitopro.py +1 -1
  43. ccxt/pro/bybit.py +3 -2
  44. ccxt/pro/derive.py +704 -0
  45. ccxt/pro/gate.py +8 -1
  46. ccxt/pro/hyperliquid.py +3 -3
  47. ccxt/pro/vertex.py +5 -0
  48. ccxt/test/tests_async.py +36 -3
  49. ccxt/test/tests_sync.py +36 -3
  50. ccxt/tradeogre.py +132 -13
  51. ccxt/whitebit.py +276 -2
  52. {ccxt-4.4.63.dist-info → ccxt-4.4.68.dist-info}/METADATA +16 -12
  53. {ccxt-4.4.63.dist-info → ccxt-4.4.68.dist-info}/RECORD +56 -53
  54. ccxt/abstract/currencycom.py +0 -68
  55. ccxt/async_support/currencycom.py +0 -2070
  56. ccxt/currencycom.py +0 -2070
  57. ccxt/pro/currencycom.py +0 -536
  58. {ccxt-4.4.63.dist-info → ccxt-4.4.68.dist-info}/LICENSE.txt +0 -0
  59. {ccxt-4.4.63.dist-info → ccxt-4.4.68.dist-info}/WHEEL +0 -0
  60. {ccxt-4.4.63.dist-info → ccxt-4.4.68.dist-info}/top_level.txt +0 -0
@@ -1947,7 +1947,11 @@ class gate(Exchange, ImplicitAPI):
1947
1947
  """
1948
1948
  await self.load_markets()
1949
1949
  symbols = self.market_symbols(symbols)
1950
- request, query = self.prepare_request(None, 'swap', params)
1950
+ market = None
1951
+ if symbols is not None:
1952
+ firstSymbol = self.safe_string(symbols, 0)
1953
+ market = self.market(firstSymbol)
1954
+ request, query = self.prepare_request(market, 'swap', params)
1951
1955
  response = await self.publicFuturesGetSettleContracts(self.extend(request, query))
1952
1956
  #
1953
1957
  # [
ccxt/async_support/htx.py CHANGED
@@ -910,6 +910,7 @@ class htx(Exchange, ImplicitAPI):
910
910
  '1041': InvalidOrder, # {"status":"error","err_code":1041,"err_msg":"The order amount exceeds the limit(170000Cont), please modify and order again.","ts":1643802784940}
911
911
  '1047': InsufficientFunds, # {"status":"error","err_code":1047,"err_msg":"Insufficient margin available.","ts":1643802672652}
912
912
  '1048': InsufficientFunds, # {"status":"error","err_code":1048,"err_msg":"Insufficient close amount available.","ts":1652772408864}
913
+ '1061': OrderNotFound, # {"status":"ok","data":{"errors":[{"order_id":"1349442392365359104","err_code":1061,"err_msg":"The order does not exist."}],"successes":""},"ts":1741773744526}
913
914
  '1051': InvalidOrder, # {"status":"error","err_code":1051,"err_msg":"No orders to cancel.","ts":1652552125876}
914
915
  '1066': BadSymbol, # {"status":"error","err_code":1066,"err_msg":"The symbol field cannot be empty. Please re-enter.","ts":1640550819147}
915
916
  '1067': InvalidOrder, # {"status":"error","err_code":1067,"err_msg":"The client_order_id field is invalid. Please re-enter.","ts":1643802119413}
@@ -6757,14 +6758,17 @@ class htx(Exchange, ImplicitAPI):
6757
6758
  """
6758
6759
  await self.load_markets()
6759
6760
  symbols = self.market_symbols(symbols)
6760
- options = self.safe_value(self.options, 'fetchFundingRates', {})
6761
- defaultSubType = self.safe_string(self.options, 'defaultSubType', 'inverse')
6762
- subType = self.safe_string(options, 'subType', defaultSubType)
6763
- subType = self.safe_string(params, 'subType', subType)
6761
+ defaultSubType = self.safe_string(self.options, 'defaultSubType', 'linear')
6762
+ subType = None
6763
+ subType, params = self.handle_option_and_params(params, 'fetchFundingRates', 'subType', defaultSubType)
6764
+ if symbols is not None:
6765
+ firstSymbol = self.safe_string(symbols, 0)
6766
+ market = self.market(firstSymbol)
6767
+ isLinear = market['linear']
6768
+ subType = 'linear' if isLinear else 'inverse'
6764
6769
  request: dict = {
6765
6770
  # 'contract_code': market['id'],
6766
6771
  }
6767
- params = self.omit(params, 'subType')
6768
6772
  response = None
6769
6773
  if subType == 'linear':
6770
6774
  response = await self.contractPublicGetLinearSwapApiV1SwapBatchFundingRate(self.extend(request, params))
@@ -7032,6 +7036,7 @@ class htx(Exchange, ImplicitAPI):
7032
7036
  if 'status' in response:
7033
7037
  #
7034
7038
  # {"status":"error","err-code":"order-limitorder-amount-min-error","err-msg":"limit order amount error, min: `0.001`","data":null}
7039
+ # {"status":"ok","data":{"errors":[{"order_id":"1349442392365359104","err_code":1061,"err_msg":"The order does not exist."}],"successes":""},"ts":1741773744526}
7035
7040
  #
7036
7041
  status = self.safe_string(response, 'status')
7037
7042
  if status == 'error':
@@ -7047,6 +7052,15 @@ class htx(Exchange, ImplicitAPI):
7047
7052
  feedback = self.id + ' ' + body
7048
7053
  code = self.safe_string(response, 'code')
7049
7054
  self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
7055
+ data = self.safe_dict(response, 'data')
7056
+ errorsList = self.safe_list(data, 'errors')
7057
+ if errorsList is not None:
7058
+ first = self.safe_dict(errorsList, 0)
7059
+ errcode = self.safe_string(first, 'err_code')
7060
+ errmessage = self.safe_string(first, 'err_msg')
7061
+ feedBack = self.id + ' ' + body
7062
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errcode, feedBack)
7063
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errmessage, feedBack)
7050
7064
  return None
7051
7065
 
7052
7066
  async def fetch_funding_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
@@ -61,6 +61,7 @@ class hyperliquid(Exchange, ImplicitAPI):
61
61
  'createStopOrder': True,
62
62
  'createTriggerOrder': True,
63
63
  'editOrder': True,
64
+ 'editOrders': True,
64
65
  'fetchAccounts': False,
65
66
  'fetchBalance': True,
66
67
  'fetchBorrowInterest': False,
@@ -1356,7 +1357,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1356
1357
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1357
1358
  """
1358
1359
  await self.load_markets()
1359
- order, globalParams = self.parse_create_order_args(symbol, type, side, amount, price, params)
1360
+ order, globalParams = self.parse_create_edit_order_args(None, symbol, type, side, amount, price, params)
1360
1361
  orders = await self.create_orders([order], globalParams)
1361
1362
  return orders[0]
1362
1363
 
@@ -1710,74 +1711,97 @@ class hyperliquid(Exchange, ImplicitAPI):
1710
1711
  #
1711
1712
  return response
1712
1713
 
1713
- def edit_order_request(self, id: str, symbol: str, type: str, side: str, amount: Num = None, price: Num = None, params={}):
1714
+ def edit_orders_request(self, orders, params={}):
1714
1715
  self.check_required_credentials()
1715
- if id is None:
1716
- raise ArgumentsRequired(self.id + ' editOrder() requires an id argument')
1717
- market = self.market(symbol)
1718
- type = type.upper()
1719
- isMarket = (type == 'MARKET')
1720
- side = side.upper()
1721
- isBuy = (side == 'BUY')
1722
- defaultSlippage = self.safe_string(self.options, 'defaultSlippage')
1723
- slippage = self.safe_string(params, 'slippage', defaultSlippage)
1724
- defaultTimeInForce = 'ioc' if (isMarket) else 'gtc'
1725
- postOnly = self.safe_bool(params, 'postOnly', False)
1726
- if postOnly:
1727
- defaultTimeInForce = 'alo'
1728
- timeInForce = self.safe_string_lower(params, 'timeInForce', defaultTimeInForce)
1729
- timeInForce = self.capitalize(timeInForce)
1730
- clientOrderId = self.safe_string_2(params, 'clientOrderId', 'client_id')
1731
- triggerPrice = self.safe_string_2(params, 'triggerPrice', 'stopPrice')
1732
- stopLossPrice = self.safe_string(params, 'stopLossPrice', triggerPrice)
1733
- takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
1734
- isTrigger = (stopLossPrice or takeProfitPrice)
1735
- params = self.omit(params, ['slippage', 'timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'clientOrderId', 'client_id'])
1736
- px = str(price)
1737
- if isMarket:
1738
- px = str(Precise.string_mul(price), Precise.string_add('1', slippage)) if (isBuy) else str(Precise.string_mul(price), Precise.string_sub('1', slippage))
1739
- else:
1740
- px = self.price_to_precision(symbol, str(price))
1741
- sz = self.amount_to_precision(symbol, amount)
1742
- reduceOnly = self.safe_bool(params, 'reduceOnly', False)
1743
- orderType: dict = {}
1744
- if isTrigger:
1745
- isTp = False
1746
- if takeProfitPrice is not None:
1747
- triggerPrice = self.price_to_precision(symbol, takeProfitPrice)
1748
- isTp = True
1716
+ hasClientOrderId = False
1717
+ for i in range(0, len(orders)):
1718
+ rawOrder = orders[i]
1719
+ orderParams = self.safe_dict(rawOrder, 'params', {})
1720
+ clientOrderId = self.safe_string_2(orderParams, 'clientOrderId', 'client_id')
1721
+ if clientOrderId is not None:
1722
+ hasClientOrderId = True
1723
+ if hasClientOrderId:
1724
+ for i in range(0, len(orders)):
1725
+ rawOrder = orders[i]
1726
+ orderParams = self.safe_dict(rawOrder, 'params', {})
1727
+ clientOrderId = self.safe_string_2(orderParams, 'clientOrderId', 'client_id')
1728
+ if clientOrderId is None:
1729
+ raise ArgumentsRequired(self.id + ' editOrders() all orders must have clientOrderId if at least one has a clientOrderId')
1730
+ params = self.omit(params, ['slippage', 'clientOrderId', 'client_id', 'slippage', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'timeInForce'])
1731
+ modifies = []
1732
+ for i in range(0, len(orders)):
1733
+ rawOrder = orders[i]
1734
+ id = self.safe_string(rawOrder, 'id')
1735
+ marketId = self.safe_string(rawOrder, 'symbol')
1736
+ market = self.market(marketId)
1737
+ symbol = market['symbol']
1738
+ type = self.safe_string_upper(rawOrder, 'type')
1739
+ isMarket = (type == 'MARKET')
1740
+ side = self.safe_string_upper(rawOrder, 'side')
1741
+ isBuy = (side == 'BUY')
1742
+ amount = self.safe_string(rawOrder, 'amount')
1743
+ price = self.safe_string(rawOrder, 'price')
1744
+ orderParams = self.safe_dict(rawOrder, 'params', {})
1745
+ defaultSlippage = self.safe_string(self.options, 'defaultSlippage')
1746
+ slippage = self.safe_string(orderParams, 'slippage', defaultSlippage)
1747
+ defaultTimeInForce = 'ioc' if (isMarket) else 'gtc'
1748
+ postOnly = self.safe_bool(orderParams, 'postOnly', False)
1749
+ if postOnly:
1750
+ defaultTimeInForce = 'alo'
1751
+ timeInForce = self.safe_string_lower(orderParams, 'timeInForce', defaultTimeInForce)
1752
+ timeInForce = self.capitalize(timeInForce)
1753
+ clientOrderId = self.safe_string_2(orderParams, 'clientOrderId', 'client_id')
1754
+ triggerPrice = self.safe_string_2(orderParams, 'triggerPrice', 'stopPrice')
1755
+ stopLossPrice = self.safe_string(orderParams, 'stopLossPrice', triggerPrice)
1756
+ takeProfitPrice = self.safe_string(orderParams, 'takeProfitPrice')
1757
+ isTrigger = (stopLossPrice or takeProfitPrice)
1758
+ reduceOnly = self.safe_bool(orderParams, 'reduceOnly', False)
1759
+ orderParams = self.omit(orderParams, ['slippage', 'timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'clientOrderId', 'client_id', 'postOnly', 'reduceOnly'])
1760
+ px = str(price)
1761
+ if isMarket:
1762
+ px = str(Precise.string_mul(price), Precise.string_add('1', slippage)) if (isBuy) else str(Precise.string_mul(price), Precise.string_sub('1', slippage))
1749
1763
  else:
1750
- triggerPrice = self.price_to_precision(symbol, stopLossPrice)
1751
- orderType['trigger'] = {
1752
- 'isMarket': isMarket,
1753
- 'triggerPx': triggerPrice,
1754
- 'tpsl': 'tp' if (isTp) else 'sl',
1764
+ px = self.price_to_precision(symbol, str(price))
1765
+ sz = self.amount_to_precision(symbol, amount)
1766
+ orderType: dict = {}
1767
+ if isTrigger:
1768
+ isTp = False
1769
+ if takeProfitPrice is not None:
1770
+ triggerPrice = self.price_to_precision(symbol, takeProfitPrice)
1771
+ isTp = True
1772
+ else:
1773
+ triggerPrice = self.price_to_precision(symbol, stopLossPrice)
1774
+ orderType['trigger'] = {
1775
+ 'isMarket': isMarket,
1776
+ 'triggerPx': triggerPrice,
1777
+ 'tpsl': 'tp' if (isTp) else 'sl',
1778
+ }
1779
+ else:
1780
+ orderType['limit'] = {
1781
+ 'tif': timeInForce,
1782
+ }
1783
+ if triggerPrice is None:
1784
+ triggerPrice = '0'
1785
+ orderReq: dict = {
1786
+ 'a': self.parse_to_int(market['baseId']),
1787
+ 'b': isBuy,
1788
+ 'p': px,
1789
+ 's': sz,
1790
+ 'r': reduceOnly,
1791
+ 't': orderType,
1792
+ # 'c': clientOrderId,
1755
1793
  }
1756
- else:
1757
- orderType['limit'] = {
1758
- 'tif': timeInForce,
1794
+ if clientOrderId is not None:
1795
+ orderReq['c'] = clientOrderId
1796
+ modifyReq: dict = {
1797
+ 'oid': self.parse_to_int(id),
1798
+ 'order': orderReq,
1759
1799
  }
1760
- if triggerPrice is None:
1761
- triggerPrice = '0'
1800
+ modifies.append(modifyReq)
1762
1801
  nonce = self.milliseconds()
1763
- orderReq: dict = {
1764
- 'a': self.parse_to_int(market['baseId']),
1765
- 'b': isBuy,
1766
- 'p': px,
1767
- 's': sz,
1768
- 'r': reduceOnly,
1769
- 't': orderType,
1770
- # 'c': clientOrderId,
1771
- }
1772
- if clientOrderId is not None:
1773
- orderReq['c'] = clientOrderId
1774
- modifyReq: dict = {
1775
- 'oid': self.parse_to_int(id),
1776
- 'order': orderReq,
1777
- }
1778
1802
  modifyAction: dict = {
1779
1803
  'type': 'batchModify',
1780
- 'modifies': [modifyReq],
1804
+ 'modifies': modifies,
1781
1805
  }
1782
1806
  vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
1783
1807
  signature = self.sign_l1_action(modifyAction, nonce, vaultAddress)
@@ -1796,7 +1820,6 @@ class hyperliquid(Exchange, ImplicitAPI):
1796
1820
  """
1797
1821
  edit a trade order
1798
1822
 
1799
- https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-an-order
1800
1823
  https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-multiple-orders
1801
1824
 
1802
1825
  :param str id: cancel order id
@@ -1815,8 +1838,24 @@ class hyperliquid(Exchange, ImplicitAPI):
1815
1838
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1816
1839
  """
1817
1840
  await self.load_markets()
1818
- market = self.market(symbol)
1819
- request = self.edit_order_request(id, symbol, type, side, amount, price, params)
1841
+ if id is None:
1842
+ raise ArgumentsRequired(self.id + ' editOrder() requires an id argument')
1843
+ order, globalParams = self.parse_create_edit_order_args(id, symbol, type, side, amount, price, params)
1844
+ orders = await self.edit_orders([order], globalParams)
1845
+ return orders[0]
1846
+
1847
+ async def edit_orders(self, orders: List[OrderRequest], params={}):
1848
+ """
1849
+ edit a list of trade orders
1850
+
1851
+ https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-multiple-orders
1852
+
1853
+ :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
1854
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1855
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1856
+ """
1857
+ await self.load_markets()
1858
+ request = self.edit_orders_request(orders, params)
1820
1859
  response = await self.privatePostExchange(request)
1821
1860
  #
1822
1861
  # {
@@ -1856,8 +1895,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1856
1895
  responseObject = self.safe_dict(response, 'response', {})
1857
1896
  dataObject = self.safe_dict(responseObject, 'data', {})
1858
1897
  statuses = self.safe_list(dataObject, 'statuses', [])
1859
- first = self.safe_dict(statuses, 0, {})
1860
- return self.parse_order(first, market)
1898
+ return self.parse_orders(statuses)
1861
1899
 
1862
1900
  async def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1863
1901
  """
@@ -3387,7 +3425,7 @@ class hyperliquid(Exchange, ImplicitAPI):
3387
3425
  return byType[type]
3388
3426
  return self.safe_value(config, 'cost', 1)
3389
3427
 
3390
- def parse_create_order_args(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
3428
+ def parse_create_edit_order_args(self, id: Str, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
3391
3429
  market = self.market(symbol)
3392
3430
  vaultAddress = self.safe_string(params, 'vaultAddress')
3393
3431
  params = self.omit(params, 'vaultAddress')
@@ -3403,4 +3441,6 @@ class hyperliquid(Exchange, ImplicitAPI):
3403
3441
  globalParams = {}
3404
3442
  if vaultAddress is not None:
3405
3443
  globalParams['vaultAddress'] = vaultAddress
3444
+ if id is not None:
3445
+ order['id'] = id
3406
3446
  return [order, globalParams]
@@ -5,7 +5,7 @@
5
5
 
6
6
  from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.luno import ImplicitAPI
8
- from ccxt.base.types import Account, Any, Balances, Currency, Int, LedgerEntry, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface
8
+ from ccxt.base.types import Account, Any, Balances, Currency, DepositAddress, Int, LedgerEntry, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface
9
9
  from typing import List
10
10
  from ccxt.base.errors import ExchangeError
11
11
  from ccxt.base.errors import ArgumentsRequired
@@ -35,6 +35,7 @@ class luno(Exchange, ImplicitAPI):
35
35
  'cancelOrder': True,
36
36
  'closeAllPositions': False,
37
37
  'closePosition': False,
38
+ 'createDepositAddress': True,
38
39
  'createOrder': True,
39
40
  'createReduceOnlyOrder': False,
40
41
  'fetchAccounts': True,
@@ -43,6 +44,7 @@ class luno(Exchange, ImplicitAPI):
43
44
  'fetchClosedOrders': True,
44
45
  'fetchCrossBorrowRate': False,
45
46
  'fetchCrossBorrowRates': False,
47
+ 'fetchDepositAddress': True,
46
48
  'fetchFundingHistory': False,
47
49
  'fetchFundingRate': False,
48
50
  'fetchFundingRateHistory': False,
@@ -1158,6 +1160,116 @@ class luno(Exchange, ImplicitAPI):
1158
1160
  'fee': None,
1159
1161
  }, currency)
1160
1162
 
1163
+ async def create_deposit_address(self, code: str, params={}) -> DepositAddress:
1164
+ """
1165
+ create a currency deposit address
1166
+
1167
+ https://www.luno.com/en/developers/api#tag/Receive/operation/createFundingAddress
1168
+
1169
+ :param str code: unified currency code of the currency for the deposit address
1170
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1171
+ :param str [params.name]: an optional name for the new address
1172
+ :param int [params.account_id]: an optional account id for the new address
1173
+ :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
1174
+ """
1175
+ await self.load_markets()
1176
+ currency = self.currency(code)
1177
+ request: dict = {
1178
+ 'asset': currency['id'],
1179
+ }
1180
+ response = await self.privatePostFundingAddress(self.extend(request, params))
1181
+ #
1182
+ # {
1183
+ # "account_id": "string",
1184
+ # "address": "string",
1185
+ # "address_meta": [
1186
+ # {
1187
+ # "label": "string",
1188
+ # "value": "string"
1189
+ # }
1190
+ # ],
1191
+ # "asset": "string",
1192
+ # "assigned_at": 0,
1193
+ # "name": "string",
1194
+ # "network": 0,
1195
+ # "qr_code_uri": "string",
1196
+ # "receive_fee": "string",
1197
+ # "total_received": "string",
1198
+ # "total_unconfirmed": "string"
1199
+ # }
1200
+ #
1201
+ return self.parse_deposit_address(response, currency)
1202
+
1203
+ async def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
1204
+ """
1205
+ fetch the deposit address for a currency associated with self account
1206
+
1207
+ https://www.luno.com/en/developers/api#tag/Receive/operation/getFundingAddress
1208
+
1209
+ :param str code: unified currency code
1210
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1211
+ :param str [params.address]: a specific cryptocurrency address to retrieve
1212
+ :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
1213
+ """
1214
+ await self.load_markets()
1215
+ currency = self.currency(code)
1216
+ request: dict = {
1217
+ 'asset': currency['id'],
1218
+ }
1219
+ response = await self.privateGetFundingAddress(self.extend(request, params))
1220
+ #
1221
+ # {
1222
+ # "account_id": "string",
1223
+ # "address": "string",
1224
+ # "address_meta": [
1225
+ # {
1226
+ # "label": "string",
1227
+ # "value": "string"
1228
+ # }
1229
+ # ],
1230
+ # "asset": "string",
1231
+ # "assigned_at": 0,
1232
+ # "name": "string",
1233
+ # "network": 0,
1234
+ # "qr_code_uri": "string",
1235
+ # "receive_fee": "string",
1236
+ # "total_received": "string",
1237
+ # "total_unconfirmed": "string"
1238
+ # }
1239
+ #
1240
+ return self.parse_deposit_address(response, currency)
1241
+
1242
+ def parse_deposit_address(self, depositAddress, currency: Currency = None) -> DepositAddress:
1243
+ #
1244
+ # {
1245
+ # "account_id": "string",
1246
+ # "address": "string",
1247
+ # "address_meta": [
1248
+ # {
1249
+ # "label": "string",
1250
+ # "value": "string"
1251
+ # }
1252
+ # ],
1253
+ # "asset": "string",
1254
+ # "assigned_at": 0,
1255
+ # "name": "string",
1256
+ # "network": 0,
1257
+ # "qr_code_uri": "string",
1258
+ # "receive_fee": "string",
1259
+ # "total_received": "string",
1260
+ # "total_unconfirmed": "string"
1261
+ # }
1262
+ #
1263
+ currencyId = self.safe_string_upper(depositAddress, 'currency')
1264
+ code = self.safe_currency_code(currencyId, currency)
1265
+ return {
1266
+ 'info': depositAddress,
1267
+ 'currency': code,
1268
+ 'network': None,
1269
+ 'address': self.safe_string(depositAddress, 'address'),
1270
+ 'tag': self.safe_string(depositAddress, 'name'),
1271
+ }
1272
+
1161
1273
  def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
1162
1274
  url = self.urls['api'][api] + '/' + self.version + '/' + self.implode_params(path, params)
1163
1275
  query = self.omit(params, self.extract_params(path))
@@ -1170,6 +1170,10 @@ class paradex(Exchange, ImplicitAPI):
1170
1170
  average = self.omit_zero(self.safe_string(order, 'avg_fill_price'))
1171
1171
  remaining = self.omit_zero(self.safe_string(order, 'remaining_size'))
1172
1172
  lastUpdateTimestamp = self.safe_integer(order, 'last_updated_at')
1173
+ flags = self.safe_list(order, 'flags', [])
1174
+ reduceOnly = None
1175
+ if 'REDUCE_ONLY' in flags:
1176
+ reduceOnly = True
1173
1177
  return self.safe_order({
1174
1178
  'id': orderId,
1175
1179
  'clientOrderId': clientOrderId,
@@ -1182,7 +1186,7 @@ class paradex(Exchange, ImplicitAPI):
1182
1186
  'type': self.parse_order_type(orderType),
1183
1187
  'timeInForce': self.parse_time_in_force(self.safe_string(order, 'instrunction')),
1184
1188
  'postOnly': None,
1185
- 'reduceOnly': None,
1189
+ 'reduceOnly': reduceOnly,
1186
1190
  'side': side,
1187
1191
  'price': price,
1188
1192
  'triggerPrice': self.safe_string(order, 'trigger_price'),
@@ -1250,6 +1254,8 @@ class paradex(Exchange, ImplicitAPI):
1250
1254
  :param dict [params]: extra parameters specific to the exchange API endpoint
1251
1255
  :param float [params.stopPrice]: alias for triggerPrice
1252
1256
  :param float [params.triggerPrice]: The price a trigger order is triggered at
1257
+ :param float [params.stopLossPrice]: the price that a stop loss order is triggered at
1258
+ :param float [params.takeProfitPrice]: the price that a take profit order is triggered at
1253
1259
  :param str [params.timeInForce]: "GTC", "IOC", or "POST_ONLY"
1254
1260
  :param bool [params.postOnly]: True or False
1255
1261
  :param bool [params.reduceOnly]: Ensures that the executed order does not flip the opened position.
@@ -1265,11 +1271,15 @@ class paradex(Exchange, ImplicitAPI):
1265
1271
  request: dict = {
1266
1272
  'market': market['id'],
1267
1273
  'side': orderSide,
1268
- 'type': orderType, # LIMIT/MARKET/STOP_LIMIT/STOP_MARKET
1269
- 'size': self.amount_to_precision(symbol, amount),
1274
+ 'type': orderType, # LIMIT/MARKET/STOP_LIMIT/STOP_MARKET,STOP_LOSS_MARKET,STOP_LOSS_LIMIT,TAKE_PROFIT_MARKET,TAKE_PROFIT_LIMIT
1270
1275
  }
1271
1276
  triggerPrice = self.safe_string_2(params, 'triggerPrice', 'stopPrice')
1277
+ stopLossPrice = self.safe_string(params, 'stopLossPrice')
1278
+ takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
1272
1279
  isMarket = orderType == 'MARKET'
1280
+ isTakeProfitOrder = (takeProfitPrice is not None)
1281
+ isStopLossOrder = (stopLossPrice is not None)
1282
+ isStopOrder = (triggerPrice is not None) or isTakeProfitOrder or isStopLossOrder
1273
1283
  timeInForce = self.safe_string_upper(params, 'timeInForce')
1274
1284
  postOnly = self.is_post_only(isMarket, None, params)
1275
1285
  if not isMarket:
@@ -1277,22 +1287,51 @@ class paradex(Exchange, ImplicitAPI):
1277
1287
  request['instruction'] = 'POST_ONLY'
1278
1288
  elif timeInForce == 'ioc':
1279
1289
  request['instruction'] = 'IOC'
1280
- if reduceOnly:
1281
- request['flags'] = [
1282
- 'REDUCE_ONLY',
1283
- ]
1284
1290
  if price is not None:
1285
1291
  request['price'] = self.price_to_precision(symbol, price)
1286
1292
  clientOrderId = self.safe_string_n(params, ['clOrdID', 'clientOrderId', 'client_order_id'])
1287
1293
  if clientOrderId is not None:
1288
1294
  request['client_id'] = clientOrderId
1289
- if triggerPrice is not None:
1295
+ sizeString = '0'
1296
+ stopPrice = None
1297
+ if isStopOrder:
1298
+ # flags: Reduce_Only must be provided for TPSL orders.
1290
1299
  if isMarket:
1291
- request['type'] = 'STOP_MARKET'
1300
+ if isStopLossOrder:
1301
+ stopPrice = self.price_to_precision(symbol, stopLossPrice)
1302
+ reduceOnly = True
1303
+ request['type'] = 'STOP_LOSS_MARKET'
1304
+ elif isTakeProfitOrder:
1305
+ stopPrice = self.price_to_precision(symbol, takeProfitPrice)
1306
+ reduceOnly = True
1307
+ request['type'] = 'TAKE_PROFIT_MARKET'
1308
+ else:
1309
+ stopPrice = self.price_to_precision(symbol, triggerPrice)
1310
+ sizeString = self.amount_to_precision(symbol, amount)
1311
+ request['type'] = 'STOP_MARKET'
1292
1312
  else:
1293
- request['type'] = 'STOP_LIMIT'
1294
- request['trigger_price'] = self.price_to_precision(symbol, triggerPrice)
1295
- params = self.omit(params, ['reduceOnly', 'reduce_only', 'clOrdID', 'clientOrderId', 'client_order_id', 'postOnly', 'timeInForce', 'stopPrice', 'triggerPrice'])
1313
+ if isStopLossOrder:
1314
+ stopPrice = self.price_to_precision(symbol, stopLossPrice)
1315
+ reduceOnly = True
1316
+ request['type'] = 'STOP_LOSS_LIMIT'
1317
+ elif isTakeProfitOrder:
1318
+ stopPrice = self.price_to_precision(symbol, takeProfitPrice)
1319
+ reduceOnly = True
1320
+ request['type'] = 'TAKE_PROFIT_LIMIT'
1321
+ else:
1322
+ stopPrice = self.price_to_precision(symbol, triggerPrice)
1323
+ sizeString = self.amount_to_precision(symbol, amount)
1324
+ request['type'] = 'STOP_LIMIT'
1325
+ else:
1326
+ sizeString = self.amount_to_precision(symbol, amount)
1327
+ if stopPrice is not None:
1328
+ request['trigger_price'] = stopPrice
1329
+ request['size'] = sizeString
1330
+ if reduceOnly:
1331
+ request['flags'] = [
1332
+ 'REDUCE_ONLY',
1333
+ ]
1334
+ params = self.omit(params, ['reduceOnly', 'reduce_only', 'clOrdID', 'clientOrderId', 'client_order_id', 'postOnly', 'timeInForce', 'stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice'])
1296
1335
  account = await self.retrieve_account()
1297
1336
  now = self.nonce()
1298
1337
  orderReq = {