ccxt 4.0.100__py2.py3-none-any.whl → 4.0.102__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 (65) hide show
  1. ccxt/__init__.py +1 -3
  2. ccxt/abstract/binance.py +8 -0
  3. ccxt/abstract/binancecoinm.py +8 -0
  4. ccxt/abstract/binanceus.py +8 -0
  5. ccxt/abstract/binanceusdm.py +8 -0
  6. ccxt/abstract/bingx.py +16 -1
  7. ccxt/async_support/__init__.py +1 -3
  8. ccxt/async_support/base/exchange.py +1 -1
  9. ccxt/async_support/binance.py +36 -1
  10. ccxt/async_support/bingx.py +41 -4
  11. ccxt/async_support/bitbank.py +11 -0
  12. ccxt/async_support/bitfinex.py +12 -8
  13. ccxt/async_support/bitflyer.py +39 -10
  14. ccxt/async_support/bitforex.py +0 -8
  15. ccxt/async_support/bitget.py +15 -5
  16. ccxt/async_support/bitmart.py +66 -0
  17. ccxt/async_support/bitstamp1.py +22 -0
  18. ccxt/async_support/bl3p.py +32 -0
  19. ccxt/async_support/bybit.py +120 -48
  20. ccxt/async_support/coinbasepro.py +11 -0
  21. ccxt/async_support/currencycom.py +1 -1
  22. ccxt/async_support/gemini.py +1 -0
  23. ccxt/async_support/huobi.py +1 -1
  24. ccxt/async_support/huobijp.py +1 -1
  25. ccxt/async_support/idex.py +1 -1
  26. ccxt/async_support/kucoinfutures.py +46 -51
  27. ccxt/async_support/lbank.py +1 -1
  28. ccxt/async_support/lbank2.py +1 -1
  29. ccxt/base/exchange.py +1 -1
  30. ccxt/binance.py +36 -1
  31. ccxt/bingx.py +41 -4
  32. ccxt/bitbank.py +11 -0
  33. ccxt/bitfinex.py +12 -8
  34. ccxt/bitflyer.py +39 -10
  35. ccxt/bitforex.py +0 -8
  36. ccxt/bitget.py +15 -5
  37. ccxt/bitmart.py +66 -0
  38. ccxt/bitstamp1.py +22 -0
  39. ccxt/bl3p.py +32 -0
  40. ccxt/bybit.py +120 -48
  41. ccxt/coinbasepro.py +11 -0
  42. ccxt/currencycom.py +1 -1
  43. ccxt/gemini.py +1 -0
  44. ccxt/huobi.py +1 -1
  45. ccxt/huobijp.py +1 -1
  46. ccxt/idex.py +1 -1
  47. ccxt/kucoinfutures.py +46 -51
  48. ccxt/lbank.py +1 -1
  49. ccxt/lbank2.py +1 -1
  50. ccxt/pro/__init__.py +1 -1
  51. ccxt/pro/binance.py +7 -7
  52. ccxt/pro/bybit.py +16 -16
  53. ccxt/pro/coinbasepro.py +10 -10
  54. ccxt/pro/huobijp.py +1 -2
  55. ccxt/pro/krakenfutures.py +7 -7
  56. ccxt/pro/kucoin.py +42 -2
  57. ccxt/pro/kucoinfutures.py +3 -3
  58. ccxt/pro/phemex.py +2 -2
  59. ccxt/test/test_async.py +1 -1
  60. ccxt/test/test_sync.py +1 -1
  61. {ccxt-4.0.100.dist-info → ccxt-4.0.102.dist-info}/METADATA +6 -7
  62. {ccxt-4.0.100.dist-info → ccxt-4.0.102.dist-info}/RECORD +64 -65
  63. ccxt/abstract/bkex.py +0 -58
  64. {ccxt-4.0.100.dist-info → ccxt-4.0.102.dist-info}/WHEEL +0 -0
  65. {ccxt-4.0.100.dist-info → ccxt-4.0.102.dist-info}/top_level.txt +0 -0
@@ -76,6 +76,9 @@ class bitmart(Exchange, ImplicitAPI):
76
76
  'fetchDepositWithdrawFee': True,
77
77
  'fetchDepositWithdrawFees': False,
78
78
  'fetchFundingHistory': None,
79
+ 'fetchFundingRate': True,
80
+ 'fetchFundingRateHistory': False,
81
+ 'fetchFundingRates': False,
79
82
  'fetchMarginMode': False,
80
83
  'fetchMarkets': True,
81
84
  'fetchMyTrades': True,
@@ -3084,6 +3087,69 @@ class bitmart(Exchange, ImplicitAPI):
3084
3087
  }
3085
3088
  return await self.privatePostContractPrivateSubmitLeverage(self.extend(request, params))
3086
3089
 
3090
+ async def fetch_funding_rate(self, symbol: str, params={}):
3091
+ """
3092
+ fetch the current funding rate
3093
+ see https://developer-pro.bitmart.com/en/futures/#get-current-funding-rate
3094
+ :param str symbol: unified market symbol
3095
+ :param dict [params]: extra parameters specific to the bitmart api endpoint
3096
+ :returns dict: a `funding rate structure <https://github.com/ccxt/ccxt/wiki/Manual#funding-rate-structure>`
3097
+ """
3098
+ await self.load_markets()
3099
+ market = self.market(symbol)
3100
+ if not market['swap']:
3101
+ raise BadSymbol(self.id + ' fetchFundingRate() supports swap contracts only')
3102
+ request = {
3103
+ 'symbol': market['id'],
3104
+ }
3105
+ response = await self.publicGetContractPublicFundingRate(self.extend(request, params))
3106
+ #
3107
+ # {
3108
+ # "code": 1000,
3109
+ # "message": "Ok",
3110
+ # "data": {
3111
+ # "timestamp": 1695184410697,
3112
+ # "symbol": "BTCUSDT",
3113
+ # "rate_value": "-0.00002614",
3114
+ # "expected_rate": "-0.00002"
3115
+ # },
3116
+ # "trace": "4cad855074654097ac7ba5257c47305d.54.16951844206655589"
3117
+ # }
3118
+ #
3119
+ data = self.safe_value(response, 'data', {})
3120
+ return self.parse_funding_rate(data, market)
3121
+
3122
+ def parse_funding_rate(self, contract, market=None):
3123
+ #
3124
+ # {
3125
+ # "timestamp": 1695184410697,
3126
+ # "symbol": "BTCUSDT",
3127
+ # "rate_value": "-0.00002614",
3128
+ # "expected_rate": "-0.00002"
3129
+ # }
3130
+ #
3131
+ marketId = self.safe_string(contract, 'symbol')
3132
+ timestamp = self.safe_integer(contract, 'timestamp')
3133
+ return {
3134
+ 'info': contract,
3135
+ 'symbol': self.safe_symbol(marketId, market),
3136
+ 'markPrice': None,
3137
+ 'indexPrice': None,
3138
+ 'interestRate': None,
3139
+ 'estimatedSettlePrice': None,
3140
+ 'timestamp': timestamp,
3141
+ 'datetime': self.iso8601(timestamp),
3142
+ 'fundingRate': self.safe_number(contract, 'expected_rate'),
3143
+ 'fundingTimestamp': None,
3144
+ 'fundingDatetime': None,
3145
+ 'nextFundingRate': None,
3146
+ 'nextFundingTimestamp': None,
3147
+ 'nextFundingDatetime': None,
3148
+ 'previousFundingRate': self.safe_number(contract, 'rate_value'),
3149
+ 'previousFundingTimestamp': None,
3150
+ 'previousFundingDatetime': None,
3151
+ }
3152
+
3087
3153
  def nonce(self):
3088
3154
  return self.milliseconds()
3089
3155
 
@@ -213,6 +213,17 @@ class bitstamp1(Exchange, ImplicitAPI):
213
213
  return self.parse_ticker(ticker, market)
214
214
 
215
215
  def parse_trade(self, trade, market=None):
216
+ #
217
+ # public trade
218
+ #
219
+ # {
220
+ # "amount": "0.00114000",
221
+ # "date": "1694287856",
222
+ # "price": "25865",
223
+ # "tid": 298730788,
224
+ # "type": 0
225
+ # }
226
+ #
216
227
  timestamp = self.safe_timestamp_2(trade, 'date', 'datetime')
217
228
  side = 'buy' if (trade['type'] == 0) else 'sell'
218
229
  orderId = self.safe_string(trade, 'order_id')
@@ -254,6 +265,17 @@ class bitstamp1(Exchange, ImplicitAPI):
254
265
  'time': 'minute',
255
266
  }
256
267
  response = await self.publicGetTransactions(self.extend(request, params))
268
+ #
269
+ # [
270
+ # {
271
+ # "amount": "0.00114000",
272
+ # "date": "1694287856",
273
+ # "price": "25865",
274
+ # "tid": 298730788,
275
+ # "type": 0
276
+ # },
277
+ # ]
278
+ #
257
279
  return self.parse_trades(response, market, since, limit)
258
280
 
259
281
  def parse_balance(self, response):
@@ -35,6 +35,9 @@ class bl3p(Exchange, ImplicitAPI):
35
35
  'cancelOrder': True,
36
36
  'createOrder': True,
37
37
  'createReduceOnlyOrder': False,
38
+ 'createStopLimitOrder': False,
39
+ 'createStopMarketOrder': False,
40
+ 'createStopOrder': False,
38
41
  'fetchBalance': True,
39
42
  'fetchBorrowRate': False,
40
43
  'fetchBorrowRateHistories': False,
@@ -237,6 +240,16 @@ class bl3p(Exchange, ImplicitAPI):
237
240
  return self.parse_ticker(ticker, market)
238
241
 
239
242
  def parse_trade(self, trade, market=None):
243
+ #
244
+ # fetchTrades
245
+ #
246
+ # {
247
+ # "trade_id": "2518789",
248
+ # "date": "1694348697745",
249
+ # "amount_int": "2959153",
250
+ # "price_int": "2416231440"
251
+ # }
252
+ #
240
253
  id = self.safe_string(trade, 'trade_id')
241
254
  timestamp = self.safe_integer(trade, 'date')
242
255
  price = self.safe_string(trade, 'price_int')
@@ -271,6 +284,20 @@ class bl3p(Exchange, ImplicitAPI):
271
284
  response = await self.publicGetMarketTrades(self.extend({
272
285
  'market': market['id'],
273
286
  }, params))
287
+ #
288
+ # {
289
+ # "result": "success",
290
+ # "data": {
291
+ # "trades": [
292
+ # {
293
+ # "trade_id": "2518789",
294
+ # "date": "1694348697745",
295
+ # "amount_int": "2959153",
296
+ # "price_int": "2416231440"
297
+ # },
298
+ # ]
299
+ # }
300
+ # }
274
301
  result = self.parse_trades(response['data']['trades'], market, since, limit)
275
302
  return result
276
303
 
@@ -329,12 +356,17 @@ class bl3p(Exchange, ImplicitAPI):
329
356
  async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount, price=None, params={}):
330
357
  """
331
358
  create a trade order
359
+ see https://github.com/BitonicNL/bl3p-api/blob/master/examples/nodejs/example.md#21---create-an-order
332
360
  :param str symbol: unified symbol of the market to create an order in
333
361
  :param str type: 'market' or 'limit'
334
362
  :param str side: 'buy' or 'sell'
335
363
  :param float amount: how much of currency you want to trade in units of base currency
336
364
  :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
337
365
  :param dict [params]: extra parameters specific to the bl3p api endpoint
366
+ *
367
+ * EXCHANGE SPECIFIC PARAMETERS
368
+ :param int [params.amount_funds]: maximal EUR amount to spend(*1e5)
369
+ :param str [params.fee_currency]: 'EUR' or 'BTC'
338
370
  :returns dict: an `order structure <https://github.com/ccxt/ccxt/wiki/Manual#order-structure>`
339
371
  """
340
372
  market = self.market(symbol)
@@ -742,7 +742,7 @@ class bybit(Exchange, ImplicitAPI):
742
742
  '110023': InvalidOrder, # This contract only supports position reduction operation, please contact customer service for details
743
743
  '110024': InvalidOrder, # You have an existing position, so position mode cannot be switched
744
744
  '110025': InvalidOrder, # Position mode is not modified
745
- '110026': InvalidOrder, # Cross/isolated margin mode is not modified
745
+ '110026': BadRequest, # Cross/isolated margin mode is not modified
746
746
  '110027': InvalidOrder, # Margin is not modified
747
747
  '110028': InvalidOrder, # Open orders exist, so you cannot change position mode
748
748
  '110029': InvalidOrder, # Hedge mode is not available for self symbol
@@ -2338,26 +2338,27 @@ class bybit(Exchange, ImplicitAPI):
2338
2338
  if limit is not None:
2339
2339
  request['limit'] = limit # max 1000, default 1000
2340
2340
  request['interval'] = self.safe_string(self.timeframes, timeframe, timeframe)
2341
- method = None
2341
+ response = None
2342
2342
  if market['spot']:
2343
2343
  request['category'] = 'spot'
2344
- method = 'publicGetV5MarketKline'
2344
+ response = await self.publicGetV5MarketKline(self.extend(request, params))
2345
2345
  else:
2346
2346
  price = self.safe_string(params, 'price')
2347
2347
  params = self.omit(params, 'price')
2348
- methods = {
2349
- 'mark': 'publicGetV5MarketMarkPriceKline',
2350
- 'index': 'publicGetV5MarketIndexPriceKline',
2351
- 'premiumIndex': 'publicGetV5MarketPremiumIndexPriceKline',
2352
- }
2353
- method = self.safe_value(methods, price, 'publicGetV5MarketKline')
2354
2348
  if market['linear']:
2355
2349
  request['category'] = 'linear'
2356
2350
  elif market['inverse']:
2357
2351
  request['category'] = 'inverse'
2358
2352
  else:
2359
2353
  raise NotSupported(self.id + ' fetchOHLCV() is not supported for option markets')
2360
- response = await getattr(self, method)(self.extend(request, params))
2354
+ if price == 'mark':
2355
+ response = await self.publicGetV5MarketMarkPriceKline(self.extend(request, params))
2356
+ elif price == 'index':
2357
+ response = await self.publicGetV5MarketIndexPriceKline(self.extend(request, params))
2358
+ elif price == 'premiumIndex':
2359
+ response = await self.publicGetV5MarketPremiumIndexPriceKline(self.extend(request, params))
2360
+ else:
2361
+ response = await self.publicGetV5MarketKline(self.extend(request, params))
2361
2362
  #
2362
2363
  # {
2363
2364
  # "retCode": 0,
@@ -3459,6 +3460,7 @@ class bybit(Exchange, ImplicitAPI):
3459
3460
  :param boolean [params.isLeverage]: *unified spot only* False then spot trading True then margin trading
3460
3461
  :param str [params.tpslMode]: *contract only* 'full' or 'partial'
3461
3462
  :param str [params.mmp]: *option only* market maker protection
3463
+ :param int [params.triggerDirection]: *contract only* conditional orders, 1: triggered when market price rises to triggerPrice, 2: triggered when market price falls to triggerPrice
3462
3464
  :returns dict: an `order structure <https://github.com/ccxt/ccxt/wiki/Manual#order-structure>`
3463
3465
  """
3464
3466
  await self.load_markets()
@@ -3549,7 +3551,6 @@ class bybit(Exchange, ImplicitAPI):
3549
3551
  isBuy = side == 'buy'
3550
3552
  ascending = not isBuy if stopLossTriggerPrice else isBuy
3551
3553
  if triggerPrice is not None:
3552
- request['triggerDirection'] = 2 if ascending else 1
3553
3554
  request['triggerPrice'] = self.price_to_precision(symbol, triggerPrice)
3554
3555
  elif isStopLossTriggerOrder or isTakeProfitTriggerOrder:
3555
3556
  request['triggerDirection'] = 2 if ascending else 1
@@ -3558,11 +3559,11 @@ class bybit(Exchange, ImplicitAPI):
3558
3559
  request['reduceOnly'] = True
3559
3560
  elif isStopLoss or isTakeProfit:
3560
3561
  if isStopLoss:
3561
- stopLossTriggerPrice = self.safe_value_2(stopLoss, 'triggerPrice', 'stopPrice', stopLoss)
3562
- request['stopLoss'] = self.price_to_precision(symbol, stopLossTriggerPrice)
3562
+ slTriggerPrice = self.safe_value_2(stopLoss, 'triggerPrice', 'stopPrice', stopLoss)
3563
+ request['stopLoss'] = self.price_to_precision(symbol, slTriggerPrice)
3563
3564
  if isTakeProfit:
3564
- takeProfitTriggerPrice = self.safe_value_2(takeProfit, 'triggerPrice', 'stopPrice', takeProfit)
3565
- request['takeProfit'] = self.price_to_precision(symbol, takeProfitTriggerPrice)
3565
+ tpTriggerPrice = self.safe_value_2(takeProfit, 'triggerPrice', 'stopPrice', takeProfit)
3566
+ request['takeProfit'] = self.price_to_precision(symbol, tpTriggerPrice)
3566
3567
  if market['spot']:
3567
3568
  # only works for spot market
3568
3569
  if triggerPrice is not None:
@@ -3656,11 +3657,11 @@ class bybit(Exchange, ImplicitAPI):
3656
3657
  request['basePrice'] = Precise.string_sub(preciseStopPrice, delta) if isStopLossTriggerOrder else Precise.string_add(preciseStopPrice, delta)
3657
3658
  elif isStopLoss or isTakeProfit:
3658
3659
  if isStopLoss:
3659
- stopLossTriggerPrice = self.safe_value_2(stopLoss, 'triggerPrice', 'stopPrice', stopLoss)
3660
- request['stopLoss'] = self.price_to_precision(symbol, stopLossTriggerPrice)
3660
+ slTriggerPrice = self.safe_value_2(stopLoss, 'triggerPrice', 'stopPrice', stopLoss)
3661
+ request['stopLoss'] = self.price_to_precision(symbol, slTriggerPrice)
3661
3662
  if isTakeProfit:
3662
- takeProfitTriggerPrice = self.safe_value_2(takeProfit, 'triggerPrice', 'stopPrice', takeProfit)
3663
- request['takeProfit'] = self.price_to_precision(symbol, takeProfitTriggerPrice)
3663
+ tpTriggerPrice = self.safe_value_2(takeProfit, 'triggerPrice', 'stopPrice', takeProfit)
3664
+ request['takeProfit'] = self.price_to_precision(symbol, tpTriggerPrice)
3664
3665
  else:
3665
3666
  request['orderFilter'] = 'Order'
3666
3667
  clientOrderId = self.safe_string(params, 'clientOrderId')
@@ -3670,8 +3671,11 @@ class bybit(Exchange, ImplicitAPI):
3670
3671
  # mandatory field for options
3671
3672
  request['orderLinkId'] = self.uuid16()
3672
3673
  params = self.omit(params, ['stopPrice', 'timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'postOnly', 'clientOrderId'])
3673
- method = 'privatePostOptionUsdcOpenapiPrivateV1PlaceOrder' if market['option'] else 'privatePostPerpetualUsdcOpenapiPrivateV1PlaceOrder'
3674
- response = await getattr(self, method)(self.extend(request, params))
3674
+ response = None
3675
+ if market['option']:
3676
+ response = await self.privatePostOptionUsdcOpenapiPrivateV1PlaceOrder(self.extend(request, params))
3677
+ else:
3678
+ response = await self.privatePostPerpetualUsdcOpenapiPrivateV1PlaceOrder(self.extend(request, params))
3675
3679
  #
3676
3680
  # {
3677
3681
  # "retCode":0,
@@ -3711,11 +3715,10 @@ class bybit(Exchange, ImplicitAPI):
3711
3715
  request['orderQty'] = self.amount_to_precision(symbol, amount)
3712
3716
  if price is not None:
3713
3717
  request['orderPrice'] = self.price_to_precision(symbol, price)
3714
- method = None
3718
+ response = None
3715
3719
  if market['option']:
3716
- method = 'privatePostOptionUsdcOpenapiPrivateV1ReplaceOrder'
3720
+ response = await self.privatePostOptionUsdcOpenapiPrivateV1ReplaceOrder(self.extend(request, params))
3717
3721
  else:
3718
- method = 'privatePostPerpetualUsdcOpenapiPrivateV1ReplaceOrder'
3719
3722
  isStop = self.safe_value(params, 'stop', False)
3720
3723
  triggerPrice = self.safe_value_2(params, 'stopPrice', 'triggerPrice')
3721
3724
  stopLossPrice = self.safe_value(params, 'stopLossPrice')
@@ -3732,7 +3735,7 @@ class bybit(Exchange, ImplicitAPI):
3732
3735
  if takeProfitPrice is not None:
3733
3736
  request['takeProfit'] = self.price_to_precision(symbol, takeProfitPrice)
3734
3737
  params = self.omit(params, ['stop', 'stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice'])
3735
- response = await getattr(self, method)(self.extend(request, params))
3738
+ response = await self.privatePostPerpetualUsdcOpenapiPrivateV1ReplaceOrder(self.extend(request, params))
3736
3739
  #
3737
3740
  # {
3738
3741
  # "retCode": 0,
@@ -3812,11 +3815,11 @@ class bybit(Exchange, ImplicitAPI):
3812
3815
  request['triggerPrice'] = self.price_to_precision(symbol, triggerPrice)
3813
3816
  if isStopLoss or isTakeProfit:
3814
3817
  if isStopLoss:
3815
- stopLossTriggerPrice = self.safe_value_2(stopLoss, 'triggerPrice', 'stopPrice', stopLoss)
3816
- request['stopLoss'] = self.price_to_precision(symbol, stopLossTriggerPrice)
3818
+ slTriggerPrice = self.safe_value_2(stopLoss, 'triggerPrice', 'stopPrice', stopLoss)
3819
+ request['stopLoss'] = self.price_to_precision(symbol, slTriggerPrice)
3817
3820
  if isTakeProfit:
3818
- takeProfitTriggerPrice = self.safe_value_2(takeProfit, 'triggerPrice', 'stopPrice', takeProfit)
3819
- request['takeProfit'] = self.price_to_precision(symbol, takeProfitTriggerPrice)
3821
+ tpTriggerPrice = self.safe_value_2(takeProfit, 'triggerPrice', 'stopPrice', takeProfit)
3822
+ request['takeProfit'] = self.price_to_precision(symbol, tpTriggerPrice)
3820
3823
  clientOrderId = self.safe_string(params, 'clientOrderId')
3821
3824
  if clientOrderId is not None:
3822
3825
  request['orderLinkId'] = clientOrderId
@@ -3851,15 +3854,14 @@ class bybit(Exchange, ImplicitAPI):
3851
3854
  }
3852
3855
  isStop = self.safe_value(params, 'stop', False)
3853
3856
  params = self.omit(params, ['stop'])
3854
- method = None
3855
3857
  if id is not None: # The user can also use argument params["order_link_id"]
3856
3858
  request['orderId'] = id
3859
+ response = None
3857
3860
  if market['option']:
3858
- method = 'privatePostOptionUsdcOpenapiPrivateV1CancelOrder'
3861
+ response = await self.privatePostOptionUsdcOpenapiPrivateV1CancelOrder(self.extend(request, params))
3859
3862
  else:
3860
- method = 'privatePostPerpetualUsdcOpenapiPrivateV1CancelOrder'
3861
3863
  request['orderFilter'] = 'StopOrder' if isStop else 'Order'
3862
- response = await getattr(self, method)(self.extend(request, params))
3864
+ response = await self.privatePostPerpetualUsdcOpenapiPrivateV1CancelOrder(self.extend(request, params))
3863
3865
  #
3864
3866
  # {
3865
3867
  # "retCode": 0,
@@ -4937,13 +4939,16 @@ class bybit(Exchange, ImplicitAPI):
4937
4939
  else:
4938
4940
  if since is not None:
4939
4941
  request['start_date'] = self.yyyymmdd(since)
4940
- method = 'privateGetV5AccountTransactionLog' if (enableUnified[1]) else 'privateGetV2PrivateWalletFundRecords'
4941
4942
  if code is not None:
4942
4943
  currency = self.currency(code)
4943
4944
  request[currencyKey] = currency['id']
4944
4945
  if limit is not None:
4945
4946
  request['limit'] = limit
4946
- response = await getattr(self, method)(self.extend(request, params))
4947
+ response = None
4948
+ if enableUnified[1]:
4949
+ response = await self.privateGetV5AccountTransactionLog(self.extend(request, params))
4950
+ else:
4951
+ response = await self.privateGetV2PrivateWalletFundRecords(self.extend(request, params))
4947
4952
  #
4948
4953
  # {
4949
4954
  # "ret_code": 0,
@@ -5624,18 +5629,85 @@ class bybit(Exchange, ImplicitAPI):
5624
5629
  })
5625
5630
 
5626
5631
  async def set_margin_mode(self, marginMode, symbol: Optional[str] = None, params={}):
5632
+ """
5633
+ set margin mode(account) or trade mode(symbol)
5634
+ see https://bybit-exchange.github.io/docs/v5/account/set-margin-mode
5635
+ see https://bybit-exchange.github.io/docs/v5/position/cross-isolate
5636
+ :param str marginMode: account mode must be either [isolated, cross, portfolio], trade mode must be either [isolated, cross]
5637
+ :param str symbol: unified market symbol of the market the position is held in, default is None
5638
+ :param dict [params]: extra parameters specific to the bybit api endpoint
5639
+ :param str [params.leverage]: the rate of leverage, is required if setting trade mode(symbol)
5640
+ :returns dict: response from the exchange
5641
+ """
5627
5642
  await self.load_markets()
5628
5643
  enableUnifiedMargin, enableUnifiedAccount = await self.is_unified_enabled()
5629
5644
  isUnifiedAccount = (enableUnifiedMargin or enableUnifiedAccount)
5630
- if marginMode == 'ISOLATED_MARGIN':
5631
- if not isUnifiedAccount:
5632
- raise NotSupported(self.id + ' setMarginMode() Normal Account not support ISOLATED_MARGIN')
5633
- elif (marginMode != 'REGULAR_MARGIN') and (marginMode != 'PORTFOLIO_MARGIN'):
5634
- raise NotSupported(self.id + ' setMarginMode() marginMode must be either ISOLATED_MARGIN or REGULAR_MARGIN or PORTFOLIO_MARGIN')
5635
- request = {
5636
- 'setMarginMode': marginMode,
5637
- }
5638
- response = await self.privatePostV5AccountSetMarginMode(self.extend(request, params))
5645
+ market = None
5646
+ response = None
5647
+ if isUnifiedAccount:
5648
+ if marginMode == 'isolated':
5649
+ marginMode = 'ISOLATED_MARGIN'
5650
+ elif marginMode == 'cross':
5651
+ marginMode = 'REGULAR_MARGIN'
5652
+ elif marginMode == 'portfolio':
5653
+ marginMode = 'PORTFOLIO_MARGIN'
5654
+ else:
5655
+ raise NotSupported(self.id + ' setMarginMode() marginMode must be either [isolated, cross, portfolio]')
5656
+ request = {
5657
+ 'setMarginMode': marginMode,
5658
+ }
5659
+ response = await self.privatePostV5AccountSetMarginMode(self.extend(request, params))
5660
+ else:
5661
+ if symbol is None:
5662
+ raise ArgumentsRequired(self.id + ' setMarginMode() requires a symbol parameter for non unified account')
5663
+ market = self.market(symbol)
5664
+ isUsdcSettled = market['settle'] == 'USDC'
5665
+ if isUsdcSettled:
5666
+ if marginMode == 'cross':
5667
+ marginMode = 'REGULAR_MARGIN'
5668
+ elif marginMode == 'portfolio':
5669
+ marginMode = 'PORTFOLIO_MARGIN'
5670
+ else:
5671
+ raise NotSupported(self.id + ' setMarginMode() for usdc market marginMode must be either [cross, portfolio]')
5672
+ request = {
5673
+ 'setMarginMode': marginMode,
5674
+ }
5675
+ response = await self.privatePostV5AccountSetMarginMode(self.extend(request, params))
5676
+ else:
5677
+ type = None
5678
+ type, params = self.get_bybit_type('setPositionMode', market, params)
5679
+ tradeMode = None
5680
+ if marginMode == 'cross':
5681
+ tradeMode = 0
5682
+ elif marginMode == 'isolated':
5683
+ tradeMode = 1
5684
+ else:
5685
+ raise NotSupported(self.id + ' setMarginMode() with symbol marginMode must be either [isolated, cross]')
5686
+ sellLeverage = None
5687
+ buyLeverage = None
5688
+ leverage = self.safe_string(params, 'leverage')
5689
+ if leverage is None:
5690
+ sellLeverage = self.safe_string_2(params, 'sell_leverage', 'sellLeverage')
5691
+ buyLeverage = self.safe_string_2(params, 'buy_leverage', 'buyLeverage')
5692
+ if sellLeverage is None and buyLeverage is None:
5693
+ raise ArgumentsRequired(self.id + ' setMarginMode() requires a leverage parameter or sell_leverage and buy_leverage parameters')
5694
+ if buyLeverage is None:
5695
+ buyLeverage = sellLeverage
5696
+ if sellLeverage is None:
5697
+ sellLeverage = buyLeverage
5698
+ params = self.omit(params, ['buy_leverage', 'sell_leverage', 'sellLeverage', 'buyLeverage'])
5699
+ else:
5700
+ sellLeverage = leverage
5701
+ buyLeverage = leverage
5702
+ params = self.omit(params, 'leverage')
5703
+ request = {
5704
+ 'category': type,
5705
+ 'symbol': market['id'],
5706
+ 'tradeMode': tradeMode,
5707
+ 'buyLeverage': buyLeverage,
5708
+ 'sellLeverage': sellLeverage,
5709
+ }
5710
+ response = await self.privatePostV5PositionSwitchIsolated(self.extend(request, params))
5639
5711
  return response
5640
5712
 
5641
5713
  async def set_leverage(self, leverage, symbol: Optional[str] = None, params={}):
@@ -5665,21 +5737,21 @@ class bybit(Exchange, ImplicitAPI):
5665
5737
  'buyLeverage': leverage,
5666
5738
  'sellLeverage': leverage,
5667
5739
  }
5668
- method = None
5740
+ response = None
5669
5741
  if isUsdcSettled and not isUnifiedAccount:
5670
5742
  request['leverage'] = leverage
5671
- method = 'privatePostPerpetualUsdcOpenapiPrivateV1PositionLeverageSave'
5743
+ response = await self.privatePostPerpetualUsdcOpenapiPrivateV1PositionLeverageSave(self.extend(request, params))
5672
5744
  else:
5673
5745
  request['buyLeverage'] = leverage
5674
5746
  request['sellLeverage'] = leverage
5675
- method = 'privatePostV5PositionSetLeverage'
5676
5747
  if market['linear']:
5677
5748
  request['category'] = 'linear'
5678
5749
  elif market['inverse']:
5679
5750
  request['category'] = 'inverse'
5680
5751
  else:
5681
5752
  raise NotSupported(self.id + ' setLeverage() only support linear and inverse market')
5682
- return await getattr(self, method)(self.extend(request, params))
5753
+ response = await self.privatePostV5PositionSetLeverage(self.extend(request, params))
5754
+ return response
5683
5755
 
5684
5756
  async def set_position_mode(self, hedged, symbol: Optional[str] = None, params={}):
5685
5757
  """
@@ -799,6 +799,17 @@ class coinbasepro(Exchange, ImplicitAPI):
799
799
  if limit is not None:
800
800
  request['limit'] = limit # default 100
801
801
  response = await self.publicGetProductsIdTrades(self.extend(request, params))
802
+ #
803
+ # [
804
+ # {
805
+ # "trade_id": "15035219",
806
+ # "side": "sell",
807
+ # "size": "0.27426731",
808
+ # "price": "25820.42000000",
809
+ # "time": "2023-09-10T13:47:41.447577Z"
810
+ # },
811
+ # ]
812
+ #
802
813
  return self.parse_trades(response, market, since, limit)
803
814
 
804
815
  async def fetch_trading_fees(self, params={}):
@@ -1054,7 +1054,7 @@ class currencycom(Exchange, ImplicitAPI):
1054
1054
  # 'limit': 500, # default 500, max 1000
1055
1055
  }
1056
1056
  if limit is not None:
1057
- request['limit'] = limit # default 500, max 1000
1057
+ request['limit'] = min(limit, 1000) # default 500, max 1000
1058
1058
  if since is not None:
1059
1059
  request['startTime'] = since
1060
1060
  response = await self.publicGetV2AggTrades(self.extend(request, params))
@@ -238,6 +238,7 @@ class gemini(Exchange, ImplicitAPI):
238
238
  'InsufficientFunds': InsufficientFunds, # The order was rejected because of insufficient funds
239
239
  'InvalidJson': BadRequest, # The JSON provided is invalid
240
240
  'InvalidNonce': InvalidNonce, # The nonce was not greater than the previously used nonce, or was not present
241
+ 'InvalidApiKey': AuthenticationError, # Invalid API key
241
242
  'InvalidOrderType': InvalidOrder, # An unknown order type was provided
242
243
  'InvalidPrice': InvalidOrder, # For new orders, the price was invalid
243
244
  'InvalidQuantity': InvalidOrder, # A negative or otherwise invalid quantity was specified
@@ -2446,7 +2446,7 @@ class huobi(Exchange, ImplicitAPI):
2446
2446
  fieldName = 'contract_code'
2447
2447
  request[fieldName] = market['id']
2448
2448
  if limit is not None:
2449
- request['size'] = limit # max 2000
2449
+ request['size'] = min(limit, 2000) # max 2000
2450
2450
  response = await getattr(self, method)(self.extend(request, params))
2451
2451
  #
2452
2452
  # {
@@ -850,7 +850,7 @@ class huobijp(Exchange, ImplicitAPI):
850
850
  'symbol': market['id'],
851
851
  }
852
852
  if limit is not None:
853
- request['size'] = limit
853
+ request['size'] = min(limit, 2000)
854
854
  response = await self.marketGetHistoryTrade(self.extend(request, params))
855
855
  #
856
856
  # {
@@ -504,7 +504,7 @@ class idex(Exchange, ImplicitAPI):
504
504
  if since is not None:
505
505
  request['start'] = since
506
506
  if limit is not None:
507
- request['limit'] = limit
507
+ request['limit'] = min(limit, 1000)
508
508
  # [
509
509
  # {
510
510
  # fillId: 'b5467d00-b13e-3fa9-8216-dd66735550fc',