ccxt 4.4.26__py2.py3-none-any.whl → 4.4.28__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 (103) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/alpaca.py +2 -0
  3. ccxt/abstract/binance.py +7 -0
  4. ccxt/abstract/binancecoinm.py +7 -0
  5. ccxt/abstract/binanceus.py +7 -0
  6. ccxt/abstract/binanceusdm.py +7 -0
  7. ccxt/abstract/hyperliquid.py +1 -1
  8. ccxt/ace.py +1 -1
  9. ccxt/alpaca.py +186 -6
  10. ccxt/ascendex.py +1 -1
  11. ccxt/async_support/__init__.py +1 -1
  12. ccxt/async_support/ace.py +1 -1
  13. ccxt/async_support/alpaca.py +186 -6
  14. ccxt/async_support/ascendex.py +1 -1
  15. ccxt/async_support/base/exchange.py +19 -1
  16. ccxt/async_support/bequant.py +1 -1
  17. ccxt/async_support/bigone.py +1 -1
  18. ccxt/async_support/binance.py +8 -1
  19. ccxt/async_support/binancecoinm.py +1 -1
  20. ccxt/async_support/binanceus.py +1 -1
  21. ccxt/async_support/binanceusdm.py +1 -1
  22. ccxt/async_support/bingx.py +23 -28
  23. ccxt/async_support/bit2c.py +1 -1
  24. ccxt/async_support/bitbank.py +1 -1
  25. ccxt/async_support/bitbns.py +1 -1
  26. ccxt/async_support/bitfinex.py +1 -1
  27. ccxt/async_support/bitfinex2.py +1 -1
  28. ccxt/async_support/bitflyer.py +1 -1
  29. ccxt/async_support/bitget.py +1 -1
  30. ccxt/async_support/bithumb.py +1 -1
  31. ccxt/async_support/bitmart.py +1 -1
  32. ccxt/async_support/bitmex.py +1 -1
  33. ccxt/async_support/bitopro.py +1 -1
  34. ccxt/async_support/bitrue.py +1 -1
  35. ccxt/async_support/bitso.py +1 -1
  36. ccxt/async_support/bitstamp.py +1 -1
  37. ccxt/async_support/bitteam.py +1 -1
  38. ccxt/async_support/bitvavo.py +1 -1
  39. ccxt/async_support/bl3p.py +1 -1
  40. ccxt/async_support/blockchaincom.py +1 -1
  41. ccxt/async_support/blofin.py +1 -1
  42. ccxt/async_support/btcalpha.py +1 -1
  43. ccxt/async_support/btcbox.py +1 -1
  44. ccxt/async_support/btcmarkets.py +1 -1
  45. ccxt/async_support/btcturk.py +1 -1
  46. ccxt/async_support/bybit.py +4 -1
  47. ccxt/async_support/coinbase.py +89 -11
  48. ccxt/async_support/coinex.py +1 -1
  49. ccxt/async_support/gate.py +20 -16
  50. ccxt/async_support/hyperliquid.py +19 -1
  51. ccxt/async_support/kraken.py +43 -35
  52. ccxt/async_support/lbank.py +97 -2
  53. ccxt/async_support/wavesexchange.py +14 -2
  54. ccxt/base/exchange.py +19 -1
  55. ccxt/bequant.py +1 -1
  56. ccxt/bigone.py +1 -1
  57. ccxt/binance.py +8 -1
  58. ccxt/binancecoinm.py +1 -1
  59. ccxt/binanceus.py +1 -1
  60. ccxt/binanceusdm.py +1 -1
  61. ccxt/bingx.py +23 -28
  62. ccxt/bit2c.py +1 -1
  63. ccxt/bitbank.py +1 -1
  64. ccxt/bitbns.py +1 -1
  65. ccxt/bitfinex.py +1 -1
  66. ccxt/bitfinex2.py +1 -1
  67. ccxt/bitflyer.py +1 -1
  68. ccxt/bitget.py +1 -1
  69. ccxt/bithumb.py +1 -1
  70. ccxt/bitmart.py +1 -1
  71. ccxt/bitmex.py +1 -1
  72. ccxt/bitopro.py +1 -1
  73. ccxt/bitrue.py +1 -1
  74. ccxt/bitso.py +1 -1
  75. ccxt/bitstamp.py +1 -1
  76. ccxt/bitteam.py +1 -1
  77. ccxt/bitvavo.py +1 -1
  78. ccxt/bl3p.py +1 -1
  79. ccxt/blockchaincom.py +1 -1
  80. ccxt/blofin.py +1 -1
  81. ccxt/btcalpha.py +1 -1
  82. ccxt/btcbox.py +1 -1
  83. ccxt/btcmarkets.py +1 -1
  84. ccxt/btcturk.py +1 -1
  85. ccxt/bybit.py +4 -1
  86. ccxt/coinbase.py +89 -11
  87. ccxt/coinex.py +1 -1
  88. ccxt/gate.py +20 -16
  89. ccxt/hyperliquid.py +19 -1
  90. ccxt/kraken.py +43 -35
  91. ccxt/lbank.py +97 -2
  92. ccxt/pro/__init__.py +1 -1
  93. ccxt/pro/binance.py +6 -7
  94. ccxt/pro/bybit.py +1 -1
  95. ccxt/pro/lbank.py +7 -4
  96. ccxt/pro/okx.py +1 -1
  97. ccxt/wavesexchange.py +14 -2
  98. ccxt-4.4.28.dist-info/METADATA +637 -0
  99. {ccxt-4.4.26.dist-info → ccxt-4.4.28.dist-info}/RECORD +102 -102
  100. ccxt-4.4.26.dist-info/METADATA +0 -636
  101. {ccxt-4.4.26.dist-info → ccxt-4.4.28.dist-info}/LICENSE.txt +0 -0
  102. {ccxt-4.4.26.dist-info → ccxt-4.4.28.dist-info}/WHEEL +0 -0
  103. {ccxt-4.4.26.dist-info → ccxt-4.4.28.dist-info}/top_level.txt +0 -0
ccxt/blofin.py CHANGED
@@ -162,7 +162,7 @@ class blofin(Exchange, ImplicitAPI):
162
162
  },
163
163
  'hostname': 'www.blofin.com',
164
164
  'urls': {
165
- 'logo': 'https://github.com/ccxt/ccxt/assets/43336371/255a7b29-341f-4d20-8342-fbfae4932807',
165
+ 'logo': 'https://github.com/user-attachments/assets/518cdf80-f05d-4821-a3e3-d48ceb41d73b',
166
166
  'api': {
167
167
  'rest': 'https://openapi.blofin.com',
168
168
  },
ccxt/btcalpha.py CHANGED
@@ -103,7 +103,7 @@ class btcalpha(Exchange, ImplicitAPI):
103
103
  '1d': 'D',
104
104
  },
105
105
  'urls': {
106
- 'logo': 'https://user-images.githubusercontent.com/1294454/42625213-dabaa5da-85cf-11e8-8f99-aa8f8f7699f0.jpg',
106
+ 'logo': 'https://github.com/user-attachments/assets/dce49f3a-61e5-4ba0-a2fe-41d192fd0e5d',
107
107
  'api': {
108
108
  'rest': 'https://btc-alpha.com/api',
109
109
  },
ccxt/btcbox.py CHANGED
@@ -88,7 +88,7 @@ class btcbox(Exchange, ImplicitAPI):
88
88
  'ws': False,
89
89
  },
90
90
  'urls': {
91
- 'logo': 'https://user-images.githubusercontent.com/51840849/87327317-98c55400-c53c-11ea-9a11-81f7d951cc74.jpg',
91
+ 'logo': 'https://github.com/user-attachments/assets/1e2cb499-8d0f-4f8f-9464-3c015cfbc76b',
92
92
  'api': {
93
93
  'rest': 'https://www.btcbox.co.jp/api',
94
94
  },
ccxt/btcmarkets.py CHANGED
@@ -91,7 +91,7 @@ class btcmarkets(Exchange, ImplicitAPI):
91
91
  'withdraw': True,
92
92
  },
93
93
  'urls': {
94
- 'logo': 'https://user-images.githubusercontent.com/51840849/89731817-b3fb8480-da52-11ea-817f-783b08aaf32b.jpg',
94
+ 'logo': 'https://github.com/user-attachments/assets/8c8d6907-3873-4cc4-ad20-e22fba28247e',
95
95
  'api': {
96
96
  'public': 'https://api.btcmarkets.net',
97
97
  'private': 'https://api.btcmarkets.net',
ccxt/btcturk.py CHANGED
@@ -93,7 +93,7 @@ class btcturk(Exchange, ImplicitAPI):
93
93
  '1y': '1 y',
94
94
  },
95
95
  'urls': {
96
- 'logo': 'https://user-images.githubusercontent.com/51840849/87153926-efbef500-c2c0-11ea-9842-05b63612c4b9.jpg',
96
+ 'logo': 'https://github.com/user-attachments/assets/10e0a238-9f60-4b06-9dda-edfc7602f1d6',
97
97
  'api': {
98
98
  'public': 'https://api.btcturk.com/api/v2',
99
99
  'private': 'https://api.btcturk.com/api/v1',
ccxt/bybit.py CHANGED
@@ -173,7 +173,7 @@ class bybit(Exchange, ImplicitAPI):
173
173
  'public': 'https://api-testnet.{hostname}',
174
174
  'private': 'https://api-testnet.{hostname}',
175
175
  },
176
- 'logo': 'https://user-images.githubusercontent.com/51840849/76547799-daff5b80-649e-11ea-87fb-3be9bac08954.jpg',
176
+ 'logo': 'https://github.com/user-attachments/assets/97a5d0b3-de10-423d-90e1-6620960025ed',
177
177
  'api': {
178
178
  'spot': 'https://api.{hostname}',
179
179
  'futures': 'https://api.{hostname}',
@@ -2487,6 +2487,9 @@ class bybit(Exchange, ImplicitAPI):
2487
2487
  #
2488
2488
  data = self.safe_dict(response, 'result', {})
2489
2489
  tickerList = self.safe_list(data, 'list', [])
2490
+ timestamp = self.safe_integer(response, 'time')
2491
+ for i in range(0, len(tickerList)):
2492
+ tickerList[i]['timestamp'] = timestamp # will be removed inside the parser
2490
2493
  result = self.parse_funding_rates(tickerList)
2491
2494
  return self.filter_by_array(result, 'symbol', symbols)
2492
2495
 
ccxt/coinbase.py CHANGED
@@ -89,6 +89,7 @@ class coinbase(Exchange, ImplicitAPI):
89
89
  'fetchDepositAddresses': False,
90
90
  'fetchDepositAddressesByNetwork': True,
91
91
  'fetchDeposits': True,
92
+ 'fetchDepositsWithdrawals': True,
92
93
  'fetchFundingHistory': False,
93
94
  'fetchFundingRate': False,
94
95
  'fetchFundingRateHistory': False,
@@ -757,8 +758,14 @@ class coinbase(Exchange, ImplicitAPI):
757
758
  :param int [since]: the earliest time in ms to fetch withdrawals for
758
759
  :param int [limit]: the maximum number of withdrawals structures to retrieve
759
760
  :param dict [params]: extra parameters specific to the exchange API endpoint
761
+ :param str [params.currencyType]: "fiat" or "crypto"
760
762
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
761
763
  """
764
+ currencyType = None
765
+ currencyType, params = self.handle_option_and_params(params, 'fetchWithdrawals', 'currencyType')
766
+ if currencyType == 'crypto':
767
+ results = self.fetch_transactions_with_method('v2PrivateGetAccountsAccountIdTransactions', code, since, limit, params)
768
+ return self.filter_by_array(results, 'type', 'withdrawal', False)
762
769
  return self.fetch_transactions_with_method('v2PrivateGetAccountsAccountIdWithdrawals', code, since, limit, params)
763
770
 
764
771
  def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
@@ -769,10 +776,30 @@ class coinbase(Exchange, ImplicitAPI):
769
776
  :param int [since]: the earliest time in ms to fetch deposits for
770
777
  :param int [limit]: the maximum number of deposits structures to retrieve
771
778
  :param dict [params]: extra parameters specific to the exchange API endpoint
779
+ :param str [params.currencyType]: "fiat" or "crypto"
772
780
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
773
781
  """
782
+ currencyType = None
783
+ currencyType, params = self.handle_option_and_params(params, 'fetchWithdrawals', 'currencyType')
784
+ if currencyType == 'crypto':
785
+ results = self.fetch_transactions_with_method('v2PrivateGetAccountsAccountIdTransactions', code, since, limit, params)
786
+ return self.filter_by_array(results, 'type', 'deposit', False)
774
787
  return self.fetch_transactions_with_method('v2PrivateGetAccountsAccountIdDeposits', code, since, limit, params)
775
788
 
789
+ def fetch_deposits_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
790
+ """
791
+ fetch history of deposits and withdrawals
792
+ :see: https://docs.cdp.coinbase.com/coinbase-app/docs/api-transactions
793
+ :param str [code]: unified currency code for the currency of the deposit/withdrawals, default is None
794
+ :param int [since]: timestamp in ms of the earliest deposit/withdrawal, default is None
795
+ :param int [limit]: max number of deposit/withdrawals to return, default = 50, Min: 1, Max: 100
796
+ :param dict [params]: extra parameters specific to the exchange API endpoint
797
+ :returns dict: a list of `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
798
+ """
799
+ self.load_markets()
800
+ results = self.fetch_transactions_with_method('v2PrivateGetAccountsAccountIdTransactions', code, since, limit, params)
801
+ return self.filter_by_array(results, 'type', ['deposit', 'withdrawal'], False)
802
+
776
803
  def parse_transaction_status(self, status: Str):
777
804
  statuses: dict = {
778
805
  'created': 'pending',
@@ -896,16 +923,59 @@ class coinbase(Exchange, ImplicitAPI):
896
923
  # "hide_native_amount": False
897
924
  # }
898
925
  #
926
+ #
927
+ # crypto deposit & withdrawal(using `/transactions` endpoint)
928
+ # {
929
+ # "amount": {
930
+ # "amount": "0.00014200",(negative for withdrawal)
931
+ # "currency": "BTC"
932
+ # },
933
+ # "created_at": "2024-03-29T15:48:30Z",
934
+ # "id": "0031a605-241d-514d-a97b-d4b99f3225d3",
935
+ # "idem": "092a979b-017e-4403-940a-2ca57811f442", # field present only in case of withdrawal
936
+ # "native_amount": {
937
+ # "amount": "9.85",(negative for withdrawal)
938
+ # "currency": "USD"
939
+ # },
940
+ # "network": {
941
+ # "status": "pending", # if status is `off_blockchain` then no more other fields are hasattr(self, present) object
942
+ # "hash": "5jYuvrNsvX2DZoMnzGYzVpYxJLfYu4GSK3xetG1H5LHrSovsuFCFYdFMwNRoiht3s6fBk92MM8QLLnz65xuEFTrE",
943
+ # "network_name": "solana",
944
+ # "transaction_fee": {
945
+ # "amount": "0.000100000",
946
+ # "currency": "SOL"
947
+ # }
948
+ # },
949
+ # "resource": "transaction",
950
+ # "resource_path": "/v2/accounts/dc504b1c-248e-5b68-a3b0-b991f7fa84e6/transactions/0031a605-241d-514d-a97b-d4b99f3225d3",
951
+ # "status": "completed",
952
+ # "type": "send",
953
+ # "from": { # in some cases, field might be present for deposit
954
+ # "id": "7fd10cd7-b091-5cee-ba41-c29e49a7cccf",
955
+ # "name": "Coinbase",
956
+ # "resource": "user"
957
+ # },
958
+ # "to": { # field only present for withdrawal
959
+ # "address": "5HA12BNthAvBwNYARYf9y5MqqCpB4qhCNFCs1Qw48ACE",
960
+ # "resource": "address"
961
+ # },
962
+ # "description": "C3 - One Time BTC Credit . Reference Case # 123.", # in some cases, field might be present for deposit
963
+ # }
964
+ #
899
965
  transactionType = self.safe_string(transaction, 'type')
900
966
  amountAndCurrencyObject = None
901
967
  feeObject = None
968
+ network = self.safe_dict(transaction, 'network', {})
902
969
  if transactionType == 'send':
903
- network = self.safe_dict(transaction, 'network', {})
904
- amountAndCurrencyObject = self.safe_dict(network, 'transaction_amount', {})
970
+ amountAndCurrencyObject = self.safe_dict(network, 'transaction_amount')
905
971
  feeObject = self.safe_dict(network, 'transaction_fee', {})
906
972
  else:
907
- amountAndCurrencyObject = self.safe_dict(transaction, 'subtotal', {})
973
+ amountAndCurrencyObject = self.safe_dict(transaction, 'subtotal')
908
974
  feeObject = self.safe_dict(transaction, 'fee', {})
975
+ if amountAndCurrencyObject is None:
976
+ amountAndCurrencyObject = self.safe_dict(transaction, 'amount')
977
+ amountString = self.safe_string(amountAndCurrencyObject, 'amount')
978
+ amountStringAbs = Precise.string_abs(amountString)
909
979
  status = self.parse_transaction_status(self.safe_string(transaction, 'status'))
910
980
  if status is None:
911
981
  committed = self.safe_bool(transaction, 'committed')
@@ -914,23 +984,31 @@ class coinbase(Exchange, ImplicitAPI):
914
984
  currencyId = self.safe_string(amountAndCurrencyObject, 'currency')
915
985
  feeCurrencyId = self.safe_string(feeObject, 'currency')
916
986
  datetime = self.safe_string(transaction, 'created_at')
917
- toObject = self.safe_dict(transaction, 'to', {})
918
- toAddress = self.safe_string(toObject, 'address')
987
+ resource = self.safe_string(transaction, 'resource')
988
+ type = resource
989
+ if not self.in_array(type, ['deposit', 'withdrawal']):
990
+ if Precise.string_gt(amountString, '0'):
991
+ type = 'deposit'
992
+ elif Precise.string_lt(amountString, '0'):
993
+ type = 'withdrawal'
994
+ toObject = self.safe_dict(transaction, 'to')
995
+ addressTo = self.safe_string(toObject, 'address')
996
+ networkId = self.safe_string(network, 'network_name')
919
997
  return {
920
998
  'info': transaction,
921
999
  'id': id,
922
- 'txid': id,
1000
+ 'txid': self.safe_string(network, 'hash', id),
923
1001
  'timestamp': self.parse8601(datetime),
924
1002
  'datetime': datetime,
925
- 'network': None,
926
- 'address': toAddress,
927
- 'addressTo': toAddress,
1003
+ 'network': self.network_id_to_code(networkId),
1004
+ 'address': addressTo,
1005
+ 'addressTo': addressTo,
928
1006
  'addressFrom': None,
929
1007
  'tag': None,
930
1008
  'tagTo': None,
931
1009
  'tagFrom': None,
932
- 'type': self.safe_string(transaction, 'resource'),
933
- 'amount': self.safe_number(amountAndCurrencyObject, 'amount'),
1010
+ 'type': type,
1011
+ 'amount': self.parse_number(amountStringAbs),
934
1012
  'currency': self.safe_currency_code(currencyId, currency),
935
1013
  'status': status,
936
1014
  'updated': self.parse8601(self.safe_string(transaction, 'updated_at')),
ccxt/coinex.py CHANGED
@@ -4672,7 +4672,7 @@ class coinex(Exchange, ImplicitAPI):
4672
4672
  self.load_markets()
4673
4673
  currency = self.currency(code)
4674
4674
  amountToPrecision = self.currency_to_precision(code, amount)
4675
- accountsByType = self.safe_dict(self.options, 'accountsById', {})
4675
+ accountsByType = self.safe_dict(self.options, 'accountsByType', {})
4676
4676
  fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
4677
4677
  toId = self.safe_string(accountsByType, toAccount, toAccount)
4678
4678
  request: dict = {
ccxt/gate.py CHANGED
@@ -922,22 +922,26 @@ class gate(Exchange, ImplicitAPI):
922
922
  """
923
923
  unifiedAccount = self.safe_bool(self.options, 'unifiedAccount')
924
924
  if unifiedAccount is None:
925
- response = self.privateAccountGetDetail(params)
926
- #
927
- # {
928
- # "user_id": 10406147,
929
- # "ip_whitelist": [],
930
- # "currency_pairs": [],
931
- # "key": {
932
- # "mode": 1
933
- # },
934
- # "tier": 0,
935
- # "tier_expire_time": "0001-01-01T00:00:00Z",
936
- # "copy_trading_role": 0
937
- # }
938
- #
939
- result = self.safe_dict(response, 'key', {})
940
- self.options['unifiedAccount'] = self.safe_integer(result, 'mode') == 2
925
+ try:
926
+ #
927
+ # {
928
+ # "user_id": 10406147,
929
+ # "ip_whitelist": [],
930
+ # "currency_pairs": [],
931
+ # "key": {
932
+ # "mode": 1
933
+ # },
934
+ # "tier": 0,
935
+ # "tier_expire_time": "0001-01-01T00:00:00Z",
936
+ # "copy_trading_role": 0
937
+ # }
938
+ #
939
+ response = self.privateAccountGetDetail(params)
940
+ result = self.safe_dict(response, 'key', {})
941
+ self.options['unifiedAccount'] = self.safe_integer(result, 'mode') == 2
942
+ except Exception as e:
943
+ # if the request fails, the unifiedAccount is disabled
944
+ self.options['unifiedAccount'] = False
941
945
 
942
946
  def upgrade_unified_trade_account(self, params={}):
943
947
  return self.privateUnifiedPutUnifiedMode(params)
ccxt/hyperliquid.py CHANGED
@@ -156,7 +156,17 @@ class hyperliquid(Exchange, ImplicitAPI):
156
156
  'api': {
157
157
  'public': {
158
158
  'post': {
159
- 'info': 1,
159
+ 'info': {
160
+ 'cost': 20,
161
+ 'byType': {
162
+ 'l2Book': 2,
163
+ 'allMids': 2,
164
+ 'clearinghouseState': 2,
165
+ 'orderStatus': 2,
166
+ 'spotClearinghouseState': 2,
167
+ 'exchangeStatus': 2,
168
+ },
169
+ },
160
170
  },
161
171
  },
162
172
  'private': {
@@ -2851,6 +2861,14 @@ class hyperliquid(Exchange, ImplicitAPI):
2851
2861
  body = self.json(params)
2852
2862
  return {'url': url, 'method': method, 'body': body, 'headers': headers}
2853
2863
 
2864
+ def calculate_rate_limiter_cost(self, api, method, path, params, config={}):
2865
+ if ('byType' in config) and ('type' in params):
2866
+ type = params['type']
2867
+ byType = config['byType']
2868
+ if type in byType:
2869
+ return byType[type]
2870
+ return self.safe_value(config, 'cost', 1)
2871
+
2854
2872
  def parse_create_order_args(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
2855
2873
  market = self.market(symbol)
2856
2874
  vaultAddress = self.safe_string(params, 'vaultAddress')
ccxt/kraken.py CHANGED
@@ -1436,7 +1436,7 @@ class kraken(Exchange, ImplicitAPI):
1436
1436
  # {
1437
1437
  # "error": [],
1438
1438
  # "result": {
1439
- # "descr": {order: 'buy 0.02100000 ETHUSDT @ limit 330.00'},
1439
+ # "descr": {order: 'buy 0.02100000 ETHUSDT @ limit 330.00'}, # see more examples in "parseOrder"
1440
1440
  # "txid": ['OEKVV2-IH52O-TPL6GZ']
1441
1441
  # }
1442
1442
  # }
@@ -1496,9 +1496,10 @@ class kraken(Exchange, ImplicitAPI):
1496
1496
 
1497
1497
  def parse_order_type(self, status):
1498
1498
  statuses: dict = {
1499
+ # we dont add "space" delimited orders here(eg. stop loss) because they need separate parsing
1499
1500
  'take-profit': 'market',
1500
- 'stop-loss-limit': 'limit',
1501
1501
  'stop-loss': 'market',
1502
+ 'stop-loss-limit': 'limit',
1502
1503
  'take-profit-limit': 'limit',
1503
1504
  'trailing-stop-limit': 'limit',
1504
1505
  }
@@ -1506,30 +1507,19 @@ class kraken(Exchange, ImplicitAPI):
1506
1507
 
1507
1508
  def parse_order(self, order: dict, market: Market = None) -> Order:
1508
1509
  #
1509
- # createOrder for regular orders
1510
+ # createOrder
1510
1511
  #
1511
1512
  # {
1512
- # "descr": {order: 'buy 0.02100000 ETHUSDT @ limit 330.00'},
1513
+ # "descr": {
1514
+ # "order": "buy 0.02100000 ETHUSDT @ limit 330.00" # limit orders
1515
+ # "buy 0.12345678 ETHUSDT @ market" # market order
1516
+ # "sell 0.28002676 ETHUSDT @ stop loss 0.0123 -> limit 0.0.1222" # stop order
1517
+ # "sell 0.00100000 ETHUSDT @ stop loss 2677.00 -> limit 2577.00 with 5:1 leverage"
1518
+ # "buy 0.10000000 LTCUSDT @ take profit 75.00000 -> limit 74.00000"
1519
+ # "sell 10.00000000 XRPEUR @ trailing stop +50.0000%" # trailing stop
1520
+ # },
1513
1521
  # "txid": ['OEKVV2-IH52O-TPL6GZ']
1514
1522
  # }
1515
- # {
1516
- # "txid": ["TX_ID_HERE"],
1517
- # "descr": {"order":"buy 0.12345678 ETHEUR @ market"},
1518
- # }
1519
- #
1520
- #
1521
- # createOrder for stop orders
1522
- #
1523
- # {
1524
- # "txid":["OSILNC-VQI5Q-775ZDQ"],
1525
- # "descr":{"order":"sell 167.28002676 ADAXBT @ stop loss 0.00003280 -> limit 0.00003212"}
1526
- # }
1527
- #
1528
- #
1529
- # {
1530
- # "txid":["OVHMJV-BZW2V-6NZFWF"],
1531
- # "descr":{"order":"sell 0.00100000 ETHUSD @ stop loss 2677.00 -> limit 2577.00 with 5:1 leverage"}
1532
- # }
1533
1523
  #
1534
1524
  # editOrder
1535
1525
  #
@@ -1607,24 +1597,29 @@ class kraken(Exchange, ImplicitAPI):
1607
1597
  else:
1608
1598
  orderDescription = self.safe_string(order, 'descr')
1609
1599
  side = None
1610
- type = None
1600
+ rawType = None
1611
1601
  marketId = None
1612
1602
  price = None
1613
1603
  amount = None
1614
- stopPrice = None
1604
+ triggerPrice = None
1615
1605
  if orderDescription is not None:
1616
1606
  parts = orderDescription.split(' ')
1617
1607
  side = self.safe_string(parts, 0)
1618
1608
  amount = self.safe_string(parts, 1)
1619
1609
  marketId = self.safe_string(parts, 2)
1620
- type = self.safe_string(parts, 4)
1621
- if type == 'stop':
1622
- stopPrice = self.safe_string(parts, 6)
1610
+ part4 = self.safe_string(parts, 4)
1611
+ part5 = self.safe_string(parts, 5)
1612
+ if part4 == 'limit' or part4 == 'market':
1613
+ rawType = part4 # eg, limit, market
1614
+ else:
1615
+ rawType = part4 + ' ' + part5 # eg. stop loss, take profit, trailing stop
1616
+ if rawType == 'stop loss' or rawType == 'take profit':
1617
+ triggerPrice = self.safe_string(parts, 6)
1623
1618
  price = self.safe_string(parts, 9)
1624
- elif type == 'limit':
1619
+ elif rawType == 'limit':
1625
1620
  price = self.safe_string(parts, 5)
1626
1621
  side = self.safe_string(description, 'type', side)
1627
- type = self.safe_string(description, 'ordertype', type)
1622
+ rawType = self.safe_string(description, 'ordertype', rawType) # orderType has dash, e.g. trailing-stop
1628
1623
  marketId = self.safe_string(description, 'pair', marketId)
1629
1624
  foundMarket = self.find_market_by_altname_or_id(marketId)
1630
1625
  symbol = None
@@ -1676,15 +1671,28 @@ class kraken(Exchange, ImplicitAPI):
1676
1671
  trades.append(self.safe_trade({'id': rawTrade, 'orderId': id, 'symbol': symbol, 'info': {}}))
1677
1672
  else:
1678
1673
  trades.append(rawTrade)
1679
- stopPrice = self.omit_zero(self.safe_string(order, 'stopprice', stopPrice))
1674
+ # in #24192 PR, self field is not something consistent/actual
1675
+ # triggerPrice = self.omit_zero(self.safe_string(order, 'stopprice', triggerPrice))
1680
1676
  stopLossPrice = None
1681
1677
  takeProfitPrice = None
1682
- if type.startswith('take-profit'):
1678
+ # the dashed strings are not provided from fields(eg. fetch order)
1679
+ # while spaced strings from "order" sentence(when other fields not available)
1680
+ if rawType.startswith('take-profit'):
1683
1681
  takeProfitPrice = self.safe_string(description, 'price')
1684
1682
  price = self.omit_zero(self.safe_string(description, 'price2'))
1685
- elif type.startswith('stop-loss'):
1683
+ elif rawType.startswith('stop-loss'):
1686
1684
  stopLossPrice = self.safe_string(description, 'price')
1687
1685
  price = self.omit_zero(self.safe_string(description, 'price2'))
1686
+ elif rawType == 'take profit':
1687
+ takeProfitPrice = triggerPrice
1688
+ elif rawType == 'stop loss':
1689
+ stopLossPrice = triggerPrice
1690
+ finalType = self.parse_order_type(rawType)
1691
+ # unlike from endpoints which provide eg: "take-profit-limit"
1692
+ # for "space-delimited" orders we dont have market/limit suffixes, their format is
1693
+ # eg: `stop loss > limit 123`, so we need to parse them manually
1694
+ if self.in_array(finalType, ['stop loss', 'take profit']):
1695
+ finalType = 'market' if (price is None) else 'limit'
1688
1696
  return self.safe_order({
1689
1697
  'id': id,
1690
1698
  'clientOrderId': clientOrderId,
@@ -1694,13 +1702,13 @@ class kraken(Exchange, ImplicitAPI):
1694
1702
  'lastTradeTimestamp': None,
1695
1703
  'status': status,
1696
1704
  'symbol': symbol,
1697
- 'type': self.parse_order_type(type),
1705
+ 'type': finalType,
1698
1706
  'timeInForce': None,
1699
1707
  'postOnly': isPostOnly,
1700
1708
  'side': side,
1701
1709
  'price': price,
1702
- 'stopPrice': stopPrice,
1703
- 'triggerPrice': stopPrice,
1710
+ 'stopPrice': triggerPrice,
1711
+ 'triggerPrice': triggerPrice,
1704
1712
  'takeProfitPrice': takeProfitPrice,
1705
1713
  'stopLossPrice': stopLossPrice,
1706
1714
  'cost': None,
ccxt/lbank.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.lbank import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Currency, DepositAddress, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, TradingFees, Transaction
9
+ from ccxt.base.types import Balances, Currency, DepositAddress, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade, TradingFeeInterface, TradingFees, Transaction
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import AuthenticationError
@@ -69,7 +69,7 @@ class lbank(Exchange, ImplicitAPI):
69
69
  'fetchFundingHistory': False,
70
70
  'fetchFundingRate': False,
71
71
  'fetchFundingRateHistory': False,
72
- 'fetchFundingRates': False,
72
+ 'fetchFundingRates': True,
73
73
  'fetchIndexOHLCV': False,
74
74
  'fetchIsolatedBorrowRate': False,
75
75
  'fetchIsolatedBorrowRates': False,
@@ -1132,6 +1132,101 @@ class lbank(Exchange, ImplicitAPI):
1132
1132
  return self.safe_balance(result)
1133
1133
  return None
1134
1134
 
1135
+ def parse_funding_rate(self, ticker, market: Market = None) -> FundingRate:
1136
+ # {
1137
+ # "symbol": "BTCUSDT",
1138
+ # "highestPrice": "69495.5",
1139
+ # "underlyingPrice": "68455.904",
1140
+ # "lowestPrice": "68182.1",
1141
+ # "openPrice": "68762.4",
1142
+ # "positionFeeRate": "0.0001",
1143
+ # "volume": "33534.2858",
1144
+ # "markedPrice": "68434.1",
1145
+ # "turnover": "1200636218.210558",
1146
+ # "positionFeeTime": "28800",
1147
+ # "lastPrice": "68427.3",
1148
+ # "nextFeeTime": "1730736000000",
1149
+ # "fundingRate": "0.0001",
1150
+ # }
1151
+ marketId = self.safe_string(ticker, 'symbol')
1152
+ symbol = self.safe_symbol(marketId, market)
1153
+ markPrice = self.safe_number(ticker, 'markedPrice')
1154
+ indexPrice = self.safe_number(ticker, 'underlyingPrice')
1155
+ fundingRate = self.safe_number(ticker, 'fundingRate')
1156
+ fundingTime = self.safe_integer(ticker, 'nextFeeTime')
1157
+ return {
1158
+ 'info': ticker,
1159
+ 'symbol': symbol,
1160
+ 'markPrice': markPrice,
1161
+ 'indexPrice': indexPrice,
1162
+ 'fundingRate': fundingRate,
1163
+ 'fundingTimestamp': fundingTime,
1164
+ 'fundingDatetime': self.iso8601(fundingTime),
1165
+ 'timestamp': None,
1166
+ 'datetime': None,
1167
+ 'nextFundingRate': None,
1168
+ 'nextFundingTimestamp': None,
1169
+ 'nextFundingDatetime': None,
1170
+ 'previousFundingRate': None,
1171
+ 'previousFundingTimestamp': None,
1172
+ 'previousFundingDatetime': None,
1173
+ 'interval': None,
1174
+ }
1175
+
1176
+ def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
1177
+ """
1178
+ fetch the current funding rate
1179
+ :see: https://www.lbank.com/en-US/docs/contract.html#query-contract-market-list
1180
+ :param str symbol: unified market symbol
1181
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1182
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
1183
+ """
1184
+ self.load_markets()
1185
+ market = self.market(symbol)
1186
+ responseForSwap = self.fetch_funding_rates([market['symbol']], params)
1187
+ return self.safe_value(responseForSwap, market['symbol'])
1188
+
1189
+ def fetch_funding_rates(self, symbols: Strings = None, params={}) -> FundingRates:
1190
+ """
1191
+ fetch the funding rate for multiple markets
1192
+ :see: https://www.lbank.com/en-US/docs/contract.html#query-contract-market-list
1193
+ :param str[]|None symbols: list of unified market symbols
1194
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1195
+ :returns dict: a dictionary of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rates-structure>`, indexed by market symbols
1196
+ """
1197
+ self.load_markets()
1198
+ symbols = self.market_symbols(symbols)
1199
+ request: dict = {
1200
+ 'productGroup': 'SwapU',
1201
+ }
1202
+ response = self.contractPublicGetCfdOpenApiV1PubMarketData(self.extend(request, params))
1203
+ # {
1204
+ # "data": [
1205
+ # {
1206
+ # "symbol": "BTCUSDT",
1207
+ # "highestPrice": "69495.5",
1208
+ # "underlyingPrice": "68455.904",
1209
+ # "lowestPrice": "68182.1",
1210
+ # "openPrice": "68762.4",
1211
+ # "positionFeeRate": "0.0001",
1212
+ # "volume": "33534.2858",
1213
+ # "markedPrice": "68434.1",
1214
+ # "turnover": "1200636218.210558",
1215
+ # "positionFeeTime": "28800",
1216
+ # "lastPrice": "68427.3",
1217
+ # "nextFeeTime": "1730736000000",
1218
+ # "fundingRate": "0.0001",
1219
+ # }
1220
+ # ],
1221
+ # "error_code": "0",
1222
+ # "msg": "Success",
1223
+ # "result": "true",
1224
+ # "success": True,
1225
+ # }
1226
+ data = self.safe_list(response, 'data', [])
1227
+ result = self.parse_funding_rates(data)
1228
+ return self.filter_by_array(result, 'symbol', symbols)
1229
+
1135
1230
  def fetch_balance(self, params={}) -> Balances:
1136
1231
  """
1137
1232
  query for balance and get the amount of funds available for trading or funds locked in orders
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.26'
7
+ __version__ = '4.4.28'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
ccxt/pro/binance.py CHANGED
@@ -1359,7 +1359,7 @@ class binance(ccxt.async_support.binance):
1359
1359
  filtered = self.filter_by_since_limit(candles, since, limit, 0, True)
1360
1360
  return self.create_ohlcv_object(symbol, timeframe, filtered)
1361
1361
 
1362
- async def un_watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], params={}):
1362
+ async def un_watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], params={}) -> Any:
1363
1363
  """
1364
1364
  unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1365
1365
  :see: https://binance-docs.github.io/apidocs/spot/en/#kline-candlestick-data
@@ -1819,7 +1819,7 @@ class binance(ccxt.async_support.binance):
1819
1819
  symbolsDefined = (symbols is not None)
1820
1820
  if symbolsDefined:
1821
1821
  firstMarket = self.market(symbols[0])
1822
- defaultMarket = 'swap' if (isMarkPrice) else 'spot'
1822
+ defaultMarket = 'swap' if (isMarkPrice) else None
1823
1823
  marketType, params = self.handle_market_type_and_params(methodName, firstMarket, params, defaultMarket)
1824
1824
  subType = None
1825
1825
  subType, params = self.handle_sub_type_and_params(methodName, firstMarket, params)
@@ -3410,11 +3410,6 @@ class binance(ccxt.async_support.binance):
3410
3410
  if not self.is_empty(symbols):
3411
3411
  market = self.get_market_from_symbols(symbols)
3412
3412
  messageHash = '::' + ','.join(symbols)
3413
- marketTypeObject: dict = {}
3414
- if market is not None:
3415
- marketTypeObject['type'] = market['type']
3416
- marketTypeObject['subType'] = market['subType']
3417
- await self.authenticate(self.extend(marketTypeObject, params))
3418
3413
  type = None
3419
3414
  type, params = self.handle_market_type_and_params('watchPositions', market, params)
3420
3415
  if type == 'spot' or type == 'margin':
@@ -3425,6 +3420,10 @@ class binance(ccxt.async_support.binance):
3425
3420
  type = 'future'
3426
3421
  elif self.isInverse(type, subType):
3427
3422
  type = 'delivery'
3423
+ marketTypeObject: dict = {}
3424
+ marketTypeObject['type'] = type
3425
+ marketTypeObject['subType'] = subType
3426
+ await self.authenticate(self.extend(marketTypeObject, params))
3428
3427
  messageHash = type + ':positions' + messageHash
3429
3428
  isPortfolioMargin = None
3430
3429
  isPortfolioMargin, params = self.handle_option_and_params_2(params, 'watchPositions', 'papi', 'portfolioMargin', False)
ccxt/pro/bybit.py CHANGED
@@ -651,7 +651,7 @@ class bybit(ccxt.async_support.bybit):
651
651
  filtered = self.filter_by_since_limit(stored, since, limit, 0, True)
652
652
  return self.create_ohlcv_object(symbol, timeframe, filtered)
653
653
 
654
- async def un_watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], params={}):
654
+ async def un_watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], params={}) -> Any:
655
655
  """
656
656
  unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
657
657
  :see: https://bybit-exchange.github.io/docs/v5/websocket/public/kline