ccxt 4.4.10__py2.py3-none-any.whl → 4.4.12__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.
ccxt/bingx.py CHANGED
@@ -2457,6 +2457,7 @@ class bingx(Exchange, ImplicitAPI):
2457
2457
  :param dict [params.stopLoss]: *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered
2458
2458
  :param float [params.stopLoss.triggerPrice]: stop loss trigger price
2459
2459
  :param boolean [params.test]: *swap only* whether to use the test endpoint or not, default is False
2460
+ :param str [params.positionSide]: *contracts only* "BOTH" for one way mode, "LONG" for buy side of hedged mode, "SHORT" for sell side of hedged mode
2460
2461
  :param boolean [params.hedged]: *swap only* whether the order is in hedged mode or one way mode
2461
2462
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2462
2463
  """
@@ -4183,13 +4184,25 @@ class bingx(Exchange, ImplicitAPI):
4183
4184
  currencyId = self.safe_string(depositAddress, 'coin')
4184
4185
  currency = self.safe_currency(currencyId, currency)
4185
4186
  code = currency['code']
4186
- network = self.safe_string(depositAddress, 'network')
4187
+ # the exchange API returns deposit addresses without the leading '0x' prefix
4188
+ # however, the exchange API does require the 0x prefix to withdraw
4189
+ # so we append the prefix before returning the address to the user
4190
+ # that is only if the underlying contract address has the 0x prefix
4191
+ networkCode = self.safe_string(depositAddress, 'network')
4192
+ if networkCode is not None:
4193
+ if networkCode in currency['networks']:
4194
+ network = currency['networks'][networkCode]
4195
+ contractAddress = self.safe_string(network['info'], 'contractAddress')
4196
+ if contractAddress is not None:
4197
+ if contractAddress[0] == '0' and contractAddress[1] == 'x':
4198
+ if address[0] != '0' or address[1] != 'x':
4199
+ address = '0x' + address
4187
4200
  self.check_address(address)
4188
4201
  return {
4189
4202
  'currency': code,
4190
4203
  'address': address,
4191
4204
  'tag': tag,
4192
- 'network': network,
4205
+ 'network': networkCode,
4193
4206
  'info': depositAddress,
4194
4207
  }
4195
4208
 
ccxt/bitget.py CHANGED
@@ -1434,7 +1434,7 @@ class bitget(Exchange, ImplicitAPI):
1434
1434
  },
1435
1435
  'sandboxMode': False,
1436
1436
  'networks': {
1437
- 'TRX': 'TRC20',
1437
+ 'TRC20': 'TRC20',
1438
1438
  'ERC20': 'ERC20',
1439
1439
  'BEP20': 'BSC',
1440
1440
  'ARB': 'ArbitrumOne',
@@ -3947,6 +3947,7 @@ class bitget(Exchange, ImplicitAPI):
3947
3947
  :param str [params.trailingTriggerPrice]: *swap and future only* the price to trigger a trailing stop order, default uses the price argument
3948
3948
  :param str [params.triggerType]: *swap and future only* 'fill_price', 'mark_price' or 'index_price'
3949
3949
  :param boolean [params.oneWayMode]: *swap and future only* required to set self to True in one_way_mode and you can leave self in hedge_mode, can adjust the mode using the setPositionMode() method
3950
+ :param bool [params.hedged]: *swap and future only* True for hedged mode, False for one way mode, default is False
3950
3951
  :param bool [params.reduceOnly]: True or False whether the order is reduce-only
3951
3952
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
3952
3953
  """
ccxt/bybit.py CHANGED
@@ -3430,7 +3430,8 @@ class bybit(Exchange, ImplicitAPI):
3430
3430
  :param str [params.timeInForce]: "GTC", "IOC", "FOK"
3431
3431
  :param bool [params.postOnly]: True or False whether the order is post-only
3432
3432
  :param bool [params.reduceOnly]: True or False whether the order is reduce-only
3433
- :param str [params.positionIdx]: *contracts only* 0 for one-way mode, 1 buy side of hedged mode, 2 sell side of hedged mode
3433
+ :param str [params.positionIdx]: *contracts only* 0 for one-way mode, 1 buy side of hedged mode, 2 sell side of hedged mode
3434
+ :param bool [params.hedged]: *contracts only* True for hedged mode, False for one way mode, default is False
3434
3435
  :param boolean [params.isLeverage]: *unified spot only* False then spot trading True then margin trading
3435
3436
  :param str [params.tpslMode]: *contract only* 'full' or 'partial'
3436
3437
  :param str [params.mmp]: *option only* market maker protection
ccxt/htx.py CHANGED
@@ -1236,6 +1236,7 @@ class htx(Exchange, ImplicitAPI):
1236
1236
  # https://github.com/ccxt/ccxt/issues/6081
1237
1237
  # https://github.com/ccxt/ccxt/issues/3365
1238
1238
  # https://github.com/ccxt/ccxt/issues/2873
1239
+ 'NGL': 'GFNGL',
1239
1240
  'GET': 'THEMIS', # conflict with GET(Guaranteed Entrance Token, GET Protocol)
1240
1241
  'GTC': 'GAMECOM', # conflict with Gitcoin and Gastrocoin
1241
1242
  'HIT': 'HITCHAIN',
@@ -1247,6 +1248,7 @@ class htx(Exchange, ImplicitAPI):
1247
1248
  'SBTC': 'SUPERBITCOIN',
1248
1249
  'SOUL': 'SOULSAVER',
1249
1250
  'BIFI': 'BITCOINFILE', # conflict with Beefy.Finance https://github.com/ccxt/ccxt/issues/8706
1251
+ 'FUD': 'FTX Users\' Debt',
1250
1252
  },
1251
1253
  })
1252
1254
 
@@ -3479,6 +3481,12 @@ class htx(Exchange, ImplicitAPI):
3479
3481
  def fetch_order(self, id: str, symbol: Str = None, params={}):
3480
3482
  """
3481
3483
  fetches information on an order made by the user
3484
+ :see: https://huobiapi.github.io/docs/spot/v1/en/#get-the-order-detail-of-an-order-based-on-client-order-id
3485
+ :see: https://huobiapi.github.io/docs/spot/v1/en/#get-the-order-detail-of-an-order
3486
+ :see: https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-get-information-of-an-order
3487
+ :see: https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-get-information-of-order
3488
+ :see: https://huobiapi.github.io/docs/dm/v1/en/#get-information-of-an-order
3489
+ :see: https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-information-of-an-order
3482
3490
  :param str symbol: unified symbol of the market the order was made in
3483
3491
  :param dict [params]: extra parameters specific to the exchange API endpoint
3484
3492
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
@@ -6853,6 +6861,10 @@ class htx(Exchange, ImplicitAPI):
6853
6861
  def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
6854
6862
  """
6855
6863
  set the level of leverage for a market
6864
+ :see: https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-switch-leverage
6865
+ :see: https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-switch-leverage
6866
+ :see: https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#switch-leverage
6867
+ :see: https://huobiapi.github.io/docs/dm/v1/en/#switch-leverage # Coin-m futures
6856
6868
  :param float leverage: the rate of leverage
6857
6869
  :param str symbol: unified market symbol
6858
6870
  :param dict [params]: extra parameters specific to the exchange API endpoint
ccxt/kraken.py CHANGED
@@ -66,6 +66,7 @@ class kraken(Exchange, ImplicitAPI):
66
66
  'createStopMarketOrder': True,
67
67
  'createStopOrder': True,
68
68
  'createTrailingAmountOrder': True,
69
+ 'createTrailingPercentOrder': True,
69
70
  'editOrder': True,
70
71
  'fetchBalance': True,
71
72
  'fetchBorrowInterest': False,
@@ -456,7 +457,9 @@ class kraken(Exchange, ImplicitAPI):
456
457
  'EGeneral:Internal error': ExchangeNotAvailable,
457
458
  'EGeneral:Temporary lockout': DDoSProtection,
458
459
  'EGeneral:Permission denied': PermissionDenied,
460
+ 'EGeneral:Invalid arguments:price': InvalidOrder,
459
461
  'EOrder:Unknown order': InvalidOrder,
462
+ 'EOrder:Invalid price:Invalid price argument': InvalidOrder,
460
463
  'EOrder:Order minimum not met': InvalidOrder,
461
464
  'EGeneral:Invalid arguments': BadRequest,
462
465
  'ESession:Invalid session': AuthenticationError,
@@ -1397,8 +1400,8 @@ class kraken(Exchange, ImplicitAPI):
1397
1400
 
1398
1401
  def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1399
1402
  """
1400
- :see: https://docs.kraken.com/rest/#tag/Spot-Trading/operation/addOrder
1401
1403
  create a trade order
1404
+ :see: https://docs.kraken.com/api/docs/rest-api/add-order
1402
1405
  :param str symbol: unified symbol of the market to create an order in
1403
1406
  :param str type: 'market' or 'limit'
1404
1407
  :param str side: 'buy' or 'sell'
@@ -1410,7 +1413,9 @@ class kraken(Exchange, ImplicitAPI):
1410
1413
  :param float [params.stopLossPrice]: *margin only* the price that a stop loss order is triggered at
1411
1414
  :param float [params.takeProfitPrice]: *margin only* the price that a take profit order is triggered at
1412
1415
  :param str [params.trailingAmount]: *margin only* the quote amount to trail away from the current market price
1416
+ :param str [params.trailingPercent]: *margin only* the percent to trail away from the current market price
1413
1417
  :param str [params.trailingLimitAmount]: *margin only* the quote amount away from the trailingAmount
1418
+ :param str [params.trailingLimitPercent]: *margin only* the percent away from the trailingAmount
1414
1419
  :param str [params.offset]: *margin only* '+' or '-' whether you want the trailingLimitAmount value to be positive or negative, default is negative '-'
1415
1420
  :param str [params.trigger]: *margin only* the activation price type, 'last' or 'index', default is 'last'
1416
1421
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
@@ -1717,8 +1722,11 @@ class kraken(Exchange, ImplicitAPI):
1717
1722
  isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
1718
1723
  isStopLossOrTakeProfitTrigger = isStopLossTriggerOrder or isTakeProfitTriggerOrder
1719
1724
  trailingAmount = self.safe_string(params, 'trailingAmount')
1725
+ trailingPercent = self.safe_string(params, 'trailingPercent')
1720
1726
  trailingLimitAmount = self.safe_string(params, 'trailingLimitAmount')
1727
+ trailingLimitPercent = self.safe_string(params, 'trailingLimitPercent')
1721
1728
  isTrailingAmountOrder = trailingAmount is not None
1729
+ isTrailingPercentOrder = trailingPercent is not None
1722
1730
  isLimitOrder = type.endswith('limit') # supporting limit, stop-loss-limit, take-profit-limit, etc
1723
1731
  isMarketOrder = type == 'market'
1724
1732
  cost = self.safe_string(params, 'cost')
@@ -1732,7 +1740,7 @@ class kraken(Exchange, ImplicitAPI):
1732
1740
  request['volume'] = self.cost_to_precision(symbol, cost)
1733
1741
  extendedOflags = flags + ',viqc' if (flags is not None) else 'viqc'
1734
1742
  request['oflags'] = extendedOflags
1735
- elif isLimitOrder and not isTrailingAmountOrder:
1743
+ elif isLimitOrder and not isTrailingAmountOrder and not isTrailingPercentOrder:
1736
1744
  request['price'] = self.price_to_precision(symbol, price)
1737
1745
  reduceOnly = self.safe_bool_2(params, 'reduceOnly', 'reduce_only')
1738
1746
  if isStopLossOrTakeProfitTrigger:
@@ -1750,19 +1758,30 @@ class kraken(Exchange, ImplicitAPI):
1750
1758
  request['ordertype'] = 'take-profit'
1751
1759
  if isLimitOrder:
1752
1760
  request['price2'] = self.price_to_precision(symbol, price)
1753
- elif isTrailingAmountOrder:
1761
+ elif isTrailingAmountOrder or isTrailingPercentOrder:
1762
+ trailingPercentString = None
1763
+ if trailingPercent is not None:
1764
+ trailingPercentString = ('+' + trailingPercent) if (trailingPercent.endswith('%')) else ('+' + trailingPercent + '%')
1765
+ trailingAmountString = '+' + trailingAmount if (trailingAmount is not None) else None # must use + for self
1766
+ offset = self.safe_string(params, 'offset', '-') # can use + or - for self
1767
+ trailingLimitAmountString = offset + self.number_to_string(trailingLimitAmount) if (trailingLimitAmount is not None) else None
1754
1768
  trailingActivationPriceType = self.safe_string(params, 'trigger', 'last')
1755
- trailingAmountString = '+' + trailingAmount
1756
1769
  request['trigger'] = trailingActivationPriceType
1757
- if isLimitOrder or (trailingLimitAmount is not None):
1758
- offset = self.safe_string(params, 'offset', '-')
1759
- trailingLimitAmountString = offset + self.number_to_string(trailingLimitAmount)
1760
- request['price'] = trailingAmountString
1761
- request['price2'] = trailingLimitAmountString
1770
+ if isLimitOrder or (trailingLimitAmount is not None) or (trailingLimitPercent is not None):
1762
1771
  request['ordertype'] = 'trailing-stop-limit'
1772
+ if trailingLimitPercent is not None:
1773
+ trailingLimitPercentString = (offset + trailingLimitPercent) if (trailingLimitPercent.endswith('%')) else (offset + trailingLimitPercent + '%')
1774
+ request['price'] = trailingPercentString
1775
+ request['price2'] = trailingLimitPercentString
1776
+ elif trailingLimitAmount is not None:
1777
+ request['price'] = trailingAmountString
1778
+ request['price2'] = trailingLimitAmountString
1763
1779
  else:
1764
- request['price'] = trailingAmountString
1765
1780
  request['ordertype'] = 'trailing-stop'
1781
+ if trailingPercent is not None:
1782
+ request['price'] = trailingPercentString
1783
+ else:
1784
+ request['price'] = trailingAmountString
1766
1785
  if reduceOnly:
1767
1786
  if method == 'createOrderWs':
1768
1787
  request['reduce_only'] = True # ws request can't have stringified bool
@@ -1789,7 +1808,7 @@ class kraken(Exchange, ImplicitAPI):
1789
1808
  request['oflags'] = extendedPostFlags
1790
1809
  if (flags is not None) and not ('oflags' in request):
1791
1810
  request['oflags'] = flags
1792
- params = self.omit(params, ['timeInForce', 'reduceOnly', 'stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingLimitAmount', 'offset'])
1811
+ params = self.omit(params, ['timeInForce', 'reduceOnly', 'stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingLimitAmount', 'trailingLimitPercent', 'offset'])
1793
1812
  return [request, params]
1794
1813
 
1795
1814
  def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
@@ -2916,11 +2935,15 @@ class kraken(Exchange, ImplicitAPI):
2916
2935
  # urlencodeNested is used to address https://github.com/ccxt/ccxt/issues/12872
2917
2936
  url += '?' + self.urlencode_nested(params)
2918
2937
  elif api == 'private':
2938
+ price = self.safe_string(params, 'price')
2939
+ isTriggerPercent = False
2940
+ if price is not None:
2941
+ isTriggerPercent = True if (price.endswith('%')) else False
2919
2942
  isCancelOrderBatch = (path == 'CancelOrderBatch')
2920
2943
  self.check_required_credentials()
2921
2944
  nonce = str(self.nonce())
2922
2945
  # urlencodeNested is used to address https://github.com/ccxt/ccxt/issues/12872
2923
- if isCancelOrderBatch:
2946
+ if isCancelOrderBatch or isTriggerPercent:
2924
2947
  body = self.json(self.extend({'nonce': nonce}, params))
2925
2948
  else:
2926
2949
  body = self.urlencode_nested(self.extend({'nonce': nonce}, params))
@@ -2933,9 +2956,8 @@ class kraken(Exchange, ImplicitAPI):
2933
2956
  headers = {
2934
2957
  'API-Key': self.apiKey,
2935
2958
  'API-Sign': signature,
2936
- # 'Content-Type': 'application/x-www-form-urlencoded',
2937
2959
  }
2938
- if isCancelOrderBatch:
2960
+ if isCancelOrderBatch or isTriggerPercent:
2939
2961
  headers['Content-Type'] = 'application/json'
2940
2962
  else:
2941
2963
  headers['Content-Type'] = 'application/x-www-form-urlencoded'
ccxt/mexc.py CHANGED
@@ -2054,6 +2054,7 @@ class mexc(Exchange, ImplicitAPI):
2054
2054
  :param float [params.triggerPrice]: The price at which a trigger order is triggered at
2055
2055
  :param bool [params.postOnly]: if True, the order will only be posted if it will be a maker order
2056
2056
  :param bool [params.reduceOnly]: *contract only* indicates if self order is to reduce the size of a position
2057
+ :param bool [params.hedged]: *swap only* True for hedged mode, False for one way mode, default is False
2057
2058
  *
2058
2059
  * EXCHANGE SPECIFIC PARAMETERS
2059
2060
  :param int [params.leverage]: *contract only* leverage is necessary on isolated margin
@@ -2179,6 +2180,7 @@ class mexc(Exchange, ImplicitAPI):
2179
2180
  :param float [params.triggerPrice]: The price at which a trigger order is triggered at
2180
2181
  :param bool [params.postOnly]: if True, the order will only be posted if it will be a maker order
2181
2182
  :param bool [params.reduceOnly]: indicates if self order is to reduce the size of a position
2183
+ :param bool [params.hedged]: *swap only* True for hedged mode, False for one way mode, default is False
2182
2184
  *
2183
2185
  * EXCHANGE SPECIFIC PARAMETERS
2184
2186
  :param int [params.leverage]: leverage is necessary on isolated margin
@@ -2246,15 +2248,25 @@ class mexc(Exchange, ImplicitAPI):
2246
2248
  if leverage is None:
2247
2249
  raise ArgumentsRequired(self.id + ' createSwapOrder() requires a leverage parameter for isolated margin orders')
2248
2250
  reduceOnly = self.safe_bool(params, 'reduceOnly', False)
2249
- if reduceOnly:
2250
- request['side'] = 2 if (side == 'buy') else 4
2251
+ hedged = self.safe_bool(params, 'hedged', False)
2252
+ sideInteger = None
2253
+ if hedged:
2254
+ if reduceOnly:
2255
+ params = self.omit(params, 'reduceOnly') # hedged mode does not accept self parameter
2256
+ side = 'sell' if (side == 'buy') else 'buy'
2257
+ sideInteger = 1 if (side == 'buy') else 3
2258
+ request['positionMode'] = 1
2251
2259
  else:
2252
- request['side'] = 1 if (side == 'buy') else 3
2260
+ if reduceOnly:
2261
+ sideInteger = 2 if (side == 'buy') else 4
2262
+ else:
2263
+ sideInteger = 1 if (side == 'buy') else 3
2264
+ request['side'] = sideInteger
2253
2265
  clientOrderId = self.safe_string_2(params, 'clientOrderId', 'externalOid')
2254
2266
  if clientOrderId is not None:
2255
2267
  request['externalOid'] = clientOrderId
2256
2268
  stopPrice = self.safe_number_2(params, 'triggerPrice', 'stopPrice')
2257
- params = self.omit(params, ['clientOrderId', 'externalOid', 'postOnly', 'stopPrice', 'triggerPrice'])
2269
+ params = self.omit(params, ['clientOrderId', 'externalOid', 'postOnly', 'stopPrice', 'triggerPrice', 'hedged'])
2258
2270
  response = None
2259
2271
  if stopPrice:
2260
2272
  request['triggerPrice'] = self.price_to_precision(symbol, stopPrice)
@@ -3615,23 +3627,29 @@ class mexc(Exchange, ImplicitAPI):
3615
3627
  :param int [since]: the earliest time in ms to fetch trades for
3616
3628
  :param int [limit]: the maximum number of trades structures to retrieve
3617
3629
  :param dict [params]: extra parameters specific to the exchange API endpoint
3630
+ :param int [params.until]: the latest time in ms to fetch trades for
3618
3631
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
3619
3632
  """
3620
3633
  if symbol is None:
3621
3634
  raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument')
3622
3635
  self.load_markets()
3623
3636
  market = self.market(symbol)
3624
- marketType, query = self.handle_market_type_and_params('fetchMyTrades', market, params)
3637
+ marketType: Str = None
3638
+ marketType, params = self.handle_market_type_and_params('fetchMyTrades', market, params)
3625
3639
  request: dict = {
3626
3640
  'symbol': market['id'],
3627
3641
  }
3628
3642
  trades = None
3629
3643
  if marketType == 'spot':
3630
3644
  if since is not None:
3631
- request['start_time'] = since
3645
+ request['startTime'] = since
3632
3646
  if limit is not None:
3633
3647
  request['limit'] = limit
3634
- trades = self.spotPrivateGetMyTrades(self.extend(request, query))
3648
+ until = self.safe_integer(params, 'until')
3649
+ if until is not None:
3650
+ params = self.omit(params, 'until')
3651
+ request['endTime'] = until
3652
+ trades = self.spotPrivateGetMyTrades(self.extend(request, params))
3635
3653
  #
3636
3654
  # spot
3637
3655
  #
@@ -3661,7 +3679,7 @@ class mexc(Exchange, ImplicitAPI):
3661
3679
  request['end_time'] = self.sum(since, self.options['maxTimeTillEnd'])
3662
3680
  if limit is not None:
3663
3681
  request['page_size'] = limit
3664
- response = self.contractPrivateGetOrderListOrderDeals(self.extend(request, query))
3682
+ response = self.contractPrivateGetOrderListOrderDeals(self.extend(request, params))
3665
3683
  #
3666
3684
  # {
3667
3685
  # "success": True,
ccxt/okx.py CHANGED
@@ -17,6 +17,7 @@ from ccxt.base.errors import AccountSuspended
17
17
  from ccxt.base.errors import ArgumentsRequired
18
18
  from ccxt.base.errors import BadRequest
19
19
  from ccxt.base.errors import BadSymbol
20
+ from ccxt.base.errors import ManualInteractionNeeded
20
21
  from ccxt.base.errors import InsufficientFunds
21
22
  from ccxt.base.errors import InvalidAddress
22
23
  from ccxt.base.errors import InvalidOrder
@@ -599,6 +600,7 @@ class okx(Exchange, ImplicitAPI):
599
600
  # General Class
600
601
  '1': ExchangeError, # Operation failed
601
602
  '2': ExchangeError, # Bulk operation partially succeeded
603
+ '4088': ManualInteractionNeeded, # {"code":"4088","data":[],"msg":"You can’t trade or deposit until you’ve verified your identity again. Head to Identity Verification to complete it."}
602
604
  '50000': BadRequest, # Body can not be empty
603
605
  '50001': OnMaintenance, # Matching engine upgrading. Please try again later
604
606
  '50002': BadRequest, # Json data format error
@@ -2792,7 +2794,7 @@ class okx(Exchange, ImplicitAPI):
2792
2794
  :param str [params.positionSide]: if position mode is one-way: set to 'net', if position mode is hedge-mode: set to 'long' or 'short'
2793
2795
  :param str [params.trailingPercent]: the percent to trail away from the current market price
2794
2796
  :param str [params.tpOrdKind]: 'condition' or 'limit', the default is 'condition'
2795
- :param str [params.hedged]: True/false, to automatically set exchange-specific params needed when trading in hedge mode
2797
+ :param bool [params.hedged]: *swap and future only* True for hedged mode, False for one way mode
2796
2798
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2797
2799
  """
2798
2800
  self.load_markets()
@@ -4525,32 +4527,27 @@ class okx(Exchange, ImplicitAPI):
4525
4527
  :see: https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-deposit-address
4526
4528
  :param str code: unified currency code
4527
4529
  :param dict [params]: extra parameters specific to the exchange API endpoint
4530
+ :param str [params.network]: the network name for the deposit address
4528
4531
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
4529
4532
  """
4533
+ self.load_markets()
4530
4534
  rawNetwork = self.safe_string_upper(params, 'network')
4531
- networks = self.safe_value(self.options, 'networks', {})
4532
- network = self.safe_string(networks, rawNetwork, rawNetwork)
4533
4535
  params = self.omit(params, 'network')
4536
+ code = self.safe_currency_code(code)
4537
+ network = self.network_id_to_code(rawNetwork, code)
4534
4538
  response = self.fetch_deposit_addresses_by_network(code, params)
4535
- result = None
4536
- if network is None:
4537
- result = self.safe_value(response, code)
4539
+ if network is not None:
4540
+ result = self.safe_dict(response, network)
4538
4541
  if result is None:
4539
- alias = self.safe_string(networks, code, code)
4540
- result = self.safe_value(response, alias)
4541
- if result is None:
4542
- defaultNetwork = self.safe_string(self.options, 'defaultNetwork', 'ERC20')
4543
- result = self.safe_value(response, defaultNetwork)
4544
- if result is None:
4545
- values = list(response.values())
4546
- result = self.safe_value(values, 0)
4547
- if result is None:
4548
- raise InvalidAddress(self.id + ' fetchDepositAddress() cannot find deposit address for ' + code)
4542
+ raise InvalidAddress(self.id + ' fetchDepositAddress() cannot find ' + network + ' deposit address for ' + code)
4549
4543
  return result
4550
- result = self.safe_value(response, network)
4551
- if result is None:
4552
- raise InvalidAddress(self.id + ' fetchDepositAddress() cannot find ' + network + ' deposit address for ' + code)
4553
- return result
4544
+ codeNetwork = self.network_id_to_code(code, code)
4545
+ if codeNetwork in response:
4546
+ return response[codeNetwork]
4547
+ # if the network is not specified, return the first address
4548
+ keys = list(response.keys())
4549
+ first = self.safe_string(keys, 0)
4550
+ return self.safe_dict(response, first)
4554
4551
 
4555
4552
  def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
4556
4553
  """
ccxt/phemex.py CHANGED
@@ -2402,6 +2402,8 @@ class phemex(Exchange, ImplicitAPI):
2402
2402
  :param float [params.takeProfit.triggerPrice]: take profit trigger price
2403
2403
  :param dict [params.stopLoss]: *swap only* *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered(perpetual swap markets only)
2404
2404
  :param float [params.stopLoss.triggerPrice]: stop loss trigger price
2405
+ :param str [params.posSide]: *swap only* "Merged" for one way mode, "Long" for buy side of hedged mode, "Short" for sell side of hedged mode
2406
+ :param bool [params.hedged]: *swap only* True for hedged mode, False for one way mode, default is False
2405
2407
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2406
2408
  """
2407
2409
  self.load_markets()
@@ -2486,13 +2488,18 @@ class phemex(Exchange, ImplicitAPI):
2486
2488
  amountString = self.number_to_string(amount)
2487
2489
  request['baseQtyEv'] = self.to_ev(amountString, market)
2488
2490
  elif market['swap']:
2491
+ hedged = self.safe_bool(params, 'hedged', False)
2492
+ params = self.omit(params, 'hedged')
2489
2493
  posSide = self.safe_string_lower(params, 'posSide')
2490
2494
  if posSide is None:
2491
- posSide = 'Merged'
2495
+ if hedged:
2496
+ if reduceOnly:
2497
+ side = 'sell' if (side == 'buy') else 'buy'
2498
+ posSide = 'Long' if (side == 'buy') else 'Short'
2499
+ else:
2500
+ posSide = 'Merged'
2492
2501
  posSide = self.capitalize(posSide)
2493
2502
  request['posSide'] = posSide
2494
- if reduceOnly is not None:
2495
- request['reduceOnly'] = reduceOnly
2496
2503
  if market['settle'] == 'USDT':
2497
2504
  request['orderQtyRq'] = amount
2498
2505
  else:
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.10'
7
+ __version__ = '4.4.12'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
ccxt/pro/deribit.py CHANGED
@@ -23,6 +23,7 @@ class deribit(ccxt.async_support.deribit):
23
23
  'watchBalance': True,
24
24
  'watchTicker': True,
25
25
  'watchTickers': True,
26
+ 'watchBidsAsks': True,
26
27
  'watchTrades': True,
27
28
  'watchTradesForSymbols': True,
28
29
  'watchMyTrades': True,
@@ -265,6 +266,79 @@ class deribit(ccxt.async_support.deribit):
265
266
  self.tickers[symbol] = ticker
266
267
  client.resolve(ticker, messageHash)
267
268
 
269
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
270
+ """
271
+ :see: https://docs.deribit.com/#quote-instrument_name
272
+ watches best bid & ask for symbols
273
+ :param str[] [symbols]: unified symbol of the market to fetch the ticker for
274
+ :param dict [params]: extra parameters specific to the exchange API endpoint
275
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
276
+ """
277
+ await self.load_markets()
278
+ symbols = self.market_symbols(symbols, None, False)
279
+ url = self.urls['api']['ws']
280
+ channels = []
281
+ for i in range(0, len(symbols)):
282
+ market = self.market(symbols[i])
283
+ channels.append('quote.' + market['id'])
284
+ message: dict = {
285
+ 'jsonrpc': '2.0',
286
+ 'method': 'public/subscribe',
287
+ 'params': {
288
+ 'channels': channels,
289
+ },
290
+ 'id': self.request_id(),
291
+ }
292
+ request = self.deep_extend(message, params)
293
+ newTickers = await self.watch_multiple(url, channels, request, channels, request)
294
+ if self.newUpdates:
295
+ tickers: dict = {}
296
+ tickers[newTickers['symbol']] = newTickers
297
+ return tickers
298
+ return self.filter_by_array(self.bidsasks, 'symbol', symbols)
299
+
300
+ def handle_bid_ask(self, client: Client, message):
301
+ #
302
+ # {
303
+ # "jsonrpc": "2.0",
304
+ # "method": "subscription",
305
+ # "params": {
306
+ # "channel": "quote.BTC_USDT",
307
+ # "data": {
308
+ # "best_bid_amount": 0.026,
309
+ # "best_ask_amount": 0.026,
310
+ # "best_bid_price": 63908,
311
+ # "best_ask_price": 63940,
312
+ # "instrument_name": "BTC_USDT",
313
+ # "timestamp": 1727765131750
314
+ # }
315
+ # }
316
+ # }
317
+ #
318
+ params = self.safe_dict(message, 'params', {})
319
+ data = self.safe_dict(params, 'data', {})
320
+ ticker = self.parse_ws_bid_ask(data)
321
+ symbol = ticker['symbol']
322
+ self.bidsasks[symbol] = ticker
323
+ messageHash = self.safe_string(params, 'channel')
324
+ client.resolve(ticker, messageHash)
325
+
326
+ def parse_ws_bid_ask(self, ticker, market=None):
327
+ marketId = self.safe_string(ticker, 'instrument_name')
328
+ market = self.safe_market(marketId, market)
329
+ symbol = self.safe_string(market, 'symbol')
330
+ timestamp = self.safe_integer(ticker, 'timestamp')
331
+ return self.safe_ticker({
332
+ 'symbol': symbol,
333
+ 'timestamp': timestamp,
334
+ 'datetime': self.iso8601(timestamp),
335
+ 'ask': self.safe_string(ticker, 'best_ask_price'),
336
+ 'askVolume': self.safe_string(ticker, 'best_ask_amount'),
337
+ 'bid': self.safe_string(ticker, 'best_bid_price'),
338
+ 'bidVolume': self.safe_string(ticker, 'best_bid_amount'),
339
+ 'info': ticker,
340
+ }, market)
341
+
268
342
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
269
343
  """
270
344
  get the list of most recent trades for a particular symbol
@@ -862,6 +936,7 @@ class deribit(ccxt.async_support.deribit):
862
936
  }
863
937
  handlers: dict = {
864
938
  'ticker': self.handle_ticker,
939
+ 'quote': self.handle_bid_ask,
865
940
  'book': self.handle_order_book,
866
941
  'trades': self.handle_trades,
867
942
  'chart': self.handle_ohlcv,
ccxt/pro/exmo.py CHANGED
@@ -6,7 +6,7 @@
6
6
  import ccxt.async_support
7
7
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById
8
8
  import hashlib
9
- from ccxt.base.types import Balances, Int, OrderBook, Str, Ticker, Trade
9
+ from ccxt.base.types import Balances, Int, OrderBook, Str, Strings, Ticker, Tickers, Trade
10
10
  from ccxt.async_support.base.ws.client import Client
11
11
  from typing import List
12
12
  from ccxt.base.errors import NotSupported
@@ -20,7 +20,7 @@ class exmo(ccxt.async_support.exmo):
20
20
  'ws': True,
21
21
  'watchBalance': True,
22
22
  'watchTicker': True,
23
- 'watchTickers': False,
23
+ 'watchTickers': True,
24
24
  'watchTrades': True,
25
25
  'watchMyTrades': True,
26
26
  'watchOrders': False, # TODO
@@ -199,6 +199,7 @@ class exmo(ccxt.async_support.exmo):
199
199
  async def watch_ticker(self, symbol: str, params={}) -> Ticker:
200
200
  """
201
201
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
202
+ :see: https://documenter.getpostman.com/view/10287440/SzYXWKPi#fd8f47bc-8517-43c0-bb60-1d61a86d4471
202
203
  :param str symbol: unified symbol of the market to fetch the ticker for
203
204
  :param dict [params]: extra parameters specific to the exchange API endpoint
204
205
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -218,6 +219,32 @@ class exmo(ccxt.async_support.exmo):
218
219
  request = self.deep_extend(message, params)
219
220
  return await self.watch(url, messageHash, request, messageHash, request)
220
221
 
222
+ async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
223
+ """
224
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
225
+ :see: https://documenter.getpostman.com/view/10287440/SzYXWKPi#fd8f47bc-8517-43c0-bb60-1d61a86d4471
226
+ :param str[] [symbols]: unified symbol of the market to fetch the ticker for
227
+ :param dict [params]: extra parameters specific to the exchange API endpoint
228
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
229
+ """
230
+ await self.load_markets()
231
+ symbols = self.market_symbols(symbols, None, False)
232
+ messageHashes = []
233
+ args = []
234
+ for i in range(0, len(symbols)):
235
+ market = self.market(symbols[i])
236
+ messageHashes.append('ticker:' + market['symbol'])
237
+ args.append('spot/ticker:' + market['id'])
238
+ url = self.urls['api']['ws']['public']
239
+ message: dict = {
240
+ 'method': 'subscribe',
241
+ 'topics': args,
242
+ 'id': self.request_id(),
243
+ }
244
+ request = self.deep_extend(message, params)
245
+ await self.watch_multiple(url, messageHashes, request, messageHashes, request)
246
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
247
+
221
248
  def handle_ticker(self, client: Client, message):
222
249
  #
223
250
  # spot
ccxt/pro/okx.py CHANGED
@@ -1813,7 +1813,7 @@ class okx(ccxt.async_support.okx):
1813
1813
  tradeSymbols = list(symbols.keys())
1814
1814
  for i in range(0, len(tradeSymbols)):
1815
1815
  symbolMessageHash = messageHash + '::' + tradeSymbols[i]
1816
- client.resolve(self.orders, symbolMessageHash)
1816
+ client.resolve(self.myTrades, symbolMessageHash)
1817
1817
 
1818
1818
  def request_id(self):
1819
1819
  ts = str(self.milliseconds())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ccxt
3
- Version: 4.4.10
3
+ Version: 4.4.12
4
4
  Summary: A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges
5
5
  Home-page: https://ccxt.com
6
6
  Author: Igor Kroitor
@@ -272,13 +272,13 @@ console.log(version, Object.keys(exchanges));
272
272
 
273
273
  All-in-one browser bundle (dependencies included), served from a CDN of your choice:
274
274
 
275
- * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.4.10/dist/ccxt.browser.min.js
276
- * unpkg: https://unpkg.com/ccxt@4.4.10/dist/ccxt.browser.min.js
275
+ * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.4.12/dist/ccxt.browser.min.js
276
+ * unpkg: https://unpkg.com/ccxt@4.4.12/dist/ccxt.browser.min.js
277
277
 
278
278
  CDNs are not updated in real-time and may have delays. Defaulting to the most recent version without specifying the version number is not recommended. Please, keep in mind that we are not responsible for the correct operation of those CDN servers.
279
279
 
280
280
  ```HTML
281
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.4.10/dist/ccxt.browser.min.js"></script>
281
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.4.12/dist/ccxt.browser.min.js"></script>
282
282
  ```
283
283
 
284
284
  Creates a global `ccxt` object: