ccxt 4.4.91__py2.py3-none-any.whl → 4.4.93__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 (57) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/lbank.py +2 -1
  3. ccxt/ascendex.py +9 -8
  4. ccxt/async_support/__init__.py +1 -1
  5. ccxt/async_support/ascendex.py +9 -8
  6. ccxt/async_support/base/exchange.py +4 -1
  7. ccxt/async_support/base/ws/client.py +4 -1
  8. ccxt/async_support/binance.py +42 -1
  9. ccxt/async_support/bitmart.py +7 -0
  10. ccxt/async_support/bitmex.py +3 -3
  11. ccxt/async_support/bitvavo.py +7 -1
  12. ccxt/async_support/bybit.py +81 -8
  13. ccxt/async_support/coinbaseexchange.py +53 -0
  14. ccxt/async_support/coincheck.py +45 -4
  15. ccxt/async_support/coinex.py +16 -12
  16. ccxt/async_support/cryptomus.py +30 -52
  17. ccxt/async_support/deribit.py +6 -6
  18. ccxt/async_support/exmo.py +70 -50
  19. ccxt/async_support/htx.py +1 -1
  20. ccxt/async_support/hyperliquid.py +2 -1
  21. ccxt/async_support/krakenfutures.py +1 -1
  22. ccxt/async_support/kucoin.py +12 -14
  23. ccxt/async_support/latoken.py +19 -71
  24. ccxt/async_support/lbank.py +115 -35
  25. ccxt/async_support/okx.py +151 -2
  26. ccxt/async_support/paradex.py +54 -0
  27. ccxt/async_support/phemex.py +3 -3
  28. ccxt/base/exchange.py +69 -30
  29. ccxt/base/types.py +1 -0
  30. ccxt/binance.py +42 -1
  31. ccxt/bitmart.py +7 -0
  32. ccxt/bitmex.py +3 -3
  33. ccxt/bitvavo.py +7 -1
  34. ccxt/bybit.py +81 -8
  35. ccxt/coinbaseexchange.py +53 -0
  36. ccxt/coincheck.py +45 -4
  37. ccxt/coinex.py +16 -12
  38. ccxt/cryptomus.py +30 -52
  39. ccxt/deribit.py +6 -6
  40. ccxt/exmo.py +70 -50
  41. ccxt/htx.py +1 -1
  42. ccxt/hyperliquid.py +2 -1
  43. ccxt/krakenfutures.py +1 -1
  44. ccxt/kucoin.py +12 -14
  45. ccxt/latoken.py +19 -71
  46. ccxt/lbank.py +115 -35
  47. ccxt/okx.py +151 -2
  48. ccxt/paradex.py +54 -0
  49. ccxt/phemex.py +3 -3
  50. ccxt/pro/__init__.py +1 -1
  51. ccxt/pro/bitstamp.py +48 -16
  52. ccxt/pro/bybit.py +5 -5
  53. {ccxt-4.4.91.dist-info → ccxt-4.4.93.dist-info}/METADATA +4 -4
  54. {ccxt-4.4.91.dist-info → ccxt-4.4.93.dist-info}/RECORD +57 -57
  55. {ccxt-4.4.91.dist-info → ccxt-4.4.93.dist-info}/LICENSE.txt +0 -0
  56. {ccxt-4.4.91.dist-info → ccxt-4.4.93.dist-info}/WHEEL +0 -0
  57. {ccxt-4.4.91.dist-info → ccxt-4.4.93.dist-info}/top_level.txt +0 -0
@@ -2659,14 +2659,14 @@ class phemex(Exchange, ImplicitAPI):
2659
2659
  triggerDirection = None
2660
2660
  triggerDirection, params = self.handle_param_string(params, 'triggerDirection')
2661
2661
  if triggerDirection is None:
2662
- raise ArgumentsRequired(self.id + " createOrder() also requires a 'triggerDirection' parameter with either 'up' or 'down' value")
2662
+ raise ArgumentsRequired(self.id + " createOrder() also requires a 'triggerDirection' parameter with either 'ascending' or 'descending' value")
2663
2663
  # the flow defined per https://phemex-docs.github.io/#more-order-type-examples
2664
- if triggerDirection == 'up':
2664
+ if triggerDirection == 'ascending' or triggerDirection == 'up':
2665
2665
  if side == 'sell':
2666
2666
  request['ordType'] = 'MarketIfTouched' if (type == 'Market') else 'LimitIfTouched'
2667
2667
  elif side == 'buy':
2668
2668
  request['ordType'] = 'Stop' if (type == 'Market') else 'StopLimit'
2669
- elif triggerDirection == 'down':
2669
+ elif triggerDirection == 'descending' or triggerDirection == 'down':
2670
2670
  if side == 'sell':
2671
2671
  request['ordType'] = 'Stop' if (type == 'Market') else 'StopLimit'
2672
2672
  elif side == 'buy':
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.91'
7
+ __version__ = '4.4.93'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -1515,6 +1515,12 @@ class Exchange(object):
1515
1515
  parts = re.sub(r'0+$', '', str).split('.')
1516
1516
  return len(parts[1]) if len(parts) > 1 else 0
1517
1517
 
1518
+ def map_to_safe_map(self, dictionary):
1519
+ return dictionary # wrapper for go
1520
+
1521
+ def safe_map_to_map(self, dictionary):
1522
+ return dictionary # wrapper for go
1523
+
1518
1524
  def load_markets(self, reload=False, params={}):
1519
1525
  """
1520
1526
  Loads and prepares the markets for trading.
@@ -3222,14 +3228,14 @@ class Exchange(object):
3222
3228
  else:
3223
3229
  market['subType'] = None
3224
3230
  values.append(market)
3225
- self.markets = self.index_by(values, 'symbol')
3231
+ self.markets = self.map_to_safe_map(self.index_by(values, 'symbol'))
3226
3232
  marketsSortedBySymbol = self.keysort(self.markets)
3227
3233
  marketsSortedById = self.keysort(self.markets_by_id)
3228
3234
  self.symbols = list(marketsSortedBySymbol.keys())
3229
3235
  self.ids = list(marketsSortedById.keys())
3230
3236
  if currencies is not None:
3231
3237
  # currencies is always None when called in constructor but not when called from loadMarkets
3232
- self.currencies = self.deep_extend(self.currencies, currencies)
3238
+ self.currencies = self.map_to_safe_map(self.deep_extend(self.currencies, currencies))
3233
3239
  else:
3234
3240
  baseCurrencies = []
3235
3241
  quoteCurrencies = []
@@ -3255,8 +3261,8 @@ class Exchange(object):
3255
3261
  quoteCurrencies.append(currency)
3256
3262
  baseCurrencies = self.sort_by(baseCurrencies, 'code', False, '')
3257
3263
  quoteCurrencies = self.sort_by(quoteCurrencies, 'code', False, '')
3258
- self.baseCurrencies = self.index_by(baseCurrencies, 'code')
3259
- self.quoteCurrencies = self.index_by(quoteCurrencies, 'code')
3264
+ self.baseCurrencies = self.map_to_safe_map(self.index_by(baseCurrencies, 'code'))
3265
+ self.quoteCurrencies = self.map_to_safe_map(self.index_by(quoteCurrencies, 'code'))
3260
3266
  allCurrencies = self.array_concat(baseCurrencies, quoteCurrencies)
3261
3267
  groupedCurrencies = self.group_by(allCurrencies, 'code')
3262
3268
  codes = list(groupedCurrencies.keys())
@@ -3273,7 +3279,7 @@ class Exchange(object):
3273
3279
  highestPrecisionCurrency = currentCurrency if (currentCurrency['precision'] > highestPrecisionCurrency['precision']) else highestPrecisionCurrency
3274
3280
  resultingCurrencies.append(highestPrecisionCurrency)
3275
3281
  sortedCurrencies = self.sort_by(resultingCurrencies, 'code')
3276
- self.currencies = self.deep_extend(self.currencies, self.index_by(sortedCurrencies, 'code'))
3282
+ self.currencies = self.map_to_safe_map(self.deep_extend(self.currencies, self.index_by(sortedCurrencies, 'code')))
3277
3283
  self.currencies_by_id = self.index_by_safe(self.currencies, 'id')
3278
3284
  currenciesSortedByCode = self.keysort(self.currencies)
3279
3285
  self.codes = list(currenciesSortedByCode.keys())
@@ -4223,7 +4229,7 @@ class Exchange(object):
4223
4229
  return self.filter_by_since_limit(sorted, since, limit, 0, tail)
4224
4230
 
4225
4231
  def parse_leverage_tiers(self, response: Any, symbols: List[str] = None, marketIdKey=None):
4226
- # marketIdKey should only be None when response is a dictionary
4232
+ # marketIdKey should only be None when response is a dictionary.
4227
4233
  symbols = self.market_symbols(symbols)
4228
4234
  tiers = {}
4229
4235
  symbolsLength = 0
@@ -5444,6 +5450,9 @@ class Exchange(object):
5444
5450
  def fetch_greeks(self, symbol: str, params={}):
5445
5451
  raise NotSupported(self.id + ' fetchGreeks() is not supported yet')
5446
5452
 
5453
+ def fetch_all_greeks(self, symbols: Strings = None, params={}):
5454
+ raise NotSupported(self.id + ' fetchAllGreeks() is not supported yet')
5455
+
5447
5456
  def fetch_option_chain(self, code: str, params={}):
5448
5457
  raise NotSupported(self.id + ' fetchOptionChain() is not supported yet')
5449
5458
 
@@ -5697,10 +5706,16 @@ class Exchange(object):
5697
5706
  precisionNumber = int(precision)
5698
5707
  if precisionNumber == 0:
5699
5708
  return '1'
5700
- parsedPrecision = '0.'
5701
- for i in range(0, precisionNumber - 1):
5702
- parsedPrecision = parsedPrecision + '0'
5703
- return parsedPrecision + '1'
5709
+ if precisionNumber > 0:
5710
+ parsedPrecision = '0.'
5711
+ for i in range(0, precisionNumber - 1):
5712
+ parsedPrecision = parsedPrecision + '0'
5713
+ return parsedPrecision + '1'
5714
+ else:
5715
+ parsedPrecision = '1'
5716
+ for i in range(0, precisionNumber * -1 - 1):
5717
+ parsedPrecision = parsedPrecision + '0'
5718
+ return parsedPrecision + '0'
5704
5719
 
5705
5720
  def integer_precision_to_amount(self, precision: Str):
5706
5721
  """
@@ -6676,6 +6691,27 @@ class Exchange(object):
6676
6691
  def parse_greeks(self, greeks: dict, market: Market = None):
6677
6692
  raise NotSupported(self.id + ' parseGreeks() is not supported yet')
6678
6693
 
6694
+ def parse_all_greeks(self, greeks, symbols: Strings = None, params={}):
6695
+ #
6696
+ # the value of greeks is either a dict or a list
6697
+ #
6698
+ results = []
6699
+ if isinstance(greeks, list):
6700
+ for i in range(0, len(greeks)):
6701
+ parsedTicker = self.parse_greeks(greeks[i])
6702
+ greek = self.extend(parsedTicker, params)
6703
+ results.append(greek)
6704
+ else:
6705
+ marketIds = list(greeks.keys())
6706
+ for i in range(0, len(marketIds)):
6707
+ marketId = marketIds[i]
6708
+ market = self.safe_market(marketId)
6709
+ parsed = self.parse_greeks(greeks[marketId], market)
6710
+ greek = self.extend(parsed, params)
6711
+ results.append(greek)
6712
+ symbols = self.market_symbols(symbols)
6713
+ return self.filter_by_array(results, 'symbol', symbols)
6714
+
6679
6715
  def parse_option(self, chain: dict, currency: Currency = None, market: Market = None):
6680
6716
  raise NotSupported(self.id + ' parseOption() is not supported yet')
6681
6717
 
@@ -6792,7 +6828,7 @@ class Exchange(object):
6792
6828
  return reconstructedDate
6793
6829
 
6794
6830
  def convert_market_id_expire_date(self, date: str):
6795
- # parse 03JAN24 to 240103
6831
+ # parse 03JAN24 to 240103.
6796
6832
  monthMappping = {
6797
6833
  'JAN': '01',
6798
6834
  'FEB': '02',
@@ -6877,14 +6913,27 @@ class Exchange(object):
6877
6913
  """
6878
6914
  raise NotSupported(self.id + ' fetchTransfers() is not supported yet')
6879
6915
 
6880
- def clean_unsubscription(self, client, subHash: str, unsubHash: str):
6916
+ def clean_unsubscription(self, client, subHash: str, unsubHash: str, subHashIsPrefix=False):
6881
6917
  if unsubHash in client.subscriptions:
6882
6918
  del client.subscriptions[unsubHash]
6883
- if subHash in client.subscriptions:
6884
- del client.subscriptions[subHash]
6885
- if subHash in client.futures:
6886
- error = UnsubscribeError(self.id + ' ' + subHash)
6887
- client.reject(error, subHash)
6919
+ if not subHashIsPrefix:
6920
+ if subHash in client.subscriptions:
6921
+ del client.subscriptions[subHash]
6922
+ if subHash in client.futures:
6923
+ error = UnsubscribeError(self.id + ' ' + subHash)
6924
+ client.reject(error, subHash)
6925
+ else:
6926
+ clientSubscriptions = list(client.subscriptions.keys())
6927
+ for i in range(0, len(clientSubscriptions)):
6928
+ sub = clientSubscriptions[i]
6929
+ if sub.startswith(subHash):
6930
+ del client.subscriptions[sub]
6931
+ clientFutures = list(client.futures.keys())
6932
+ for i in range(0, len(clientFutures)):
6933
+ future = clientFutures[i]
6934
+ if future.startswith(subHash):
6935
+ error = UnsubscribeError(self.id + ' ' + future)
6936
+ client.reject(error, future)
6888
6937
  client.resolve(True, unsubHash)
6889
6938
 
6890
6939
  def clean_cache(self, subscription: dict):
@@ -6914,19 +6963,9 @@ class Exchange(object):
6914
6963
  del self.tickers[symbol]
6915
6964
  else:
6916
6965
  if topic == 'myTrades' and (self.myTrades is not None):
6917
- # don't reset self.myTrades directly here
6918
- # because in c# we need to use a different object(thread-safe dict)
6919
- keys = list(self.myTrades.keys())
6920
- for i in range(0, len(keys)):
6921
- key = keys[i]
6922
- if key in self.myTrades:
6923
- del self.myTrades[key]
6966
+ self.myTrades = None
6924
6967
  elif topic == 'orders' and (self.orders is not None):
6925
- orderSymbols = list(self.orders.keys())
6926
- for i in range(0, len(orderSymbols)):
6927
- orderSymbol = orderSymbols[i]
6928
- if orderSymbol in self.orders:
6929
- del self.orders[orderSymbol]
6968
+ self.orders = None
6930
6969
  elif topic == 'ticker' and (self.tickers is not None):
6931
6970
  tickerSymbols = list(self.tickers.keys())
6932
6971
  for i in range(0, len(tickerSymbols)):
ccxt/base/types.py CHANGED
@@ -606,3 +606,4 @@ class ConstructorArgs(TypedDict, total=False):
606
606
  hostname: str
607
607
  urls: Dict[str, Any]
608
608
  headers: Dict[str, Any]
609
+ session: Any
ccxt/binance.py CHANGED
@@ -87,6 +87,7 @@ class binance(Exchange, ImplicitAPI):
87
87
  'editOrder': True,
88
88
  'editOrders': True,
89
89
  'fetchAccounts': None,
90
+ 'fetchAllGreeks': True,
90
91
  'fetchBalance': True,
91
92
  'fetchBidsAsks': True,
92
93
  'fetchBorrowInterest': True,
@@ -10777,6 +10778,7 @@ class binance(Exchange, ImplicitAPI):
10777
10778
  request: dict = {}
10778
10779
  if symbol is not None:
10779
10780
  request['symbol'] = market['id']
10781
+ symbol = market['symbol']
10780
10782
  if since is not None:
10781
10783
  request['startTime'] = since
10782
10784
  if limit is not None:
@@ -10804,7 +10806,7 @@ class binance(Exchange, ImplicitAPI):
10804
10806
  #
10805
10807
  settlements = self.parse_settlements(response, market)
10806
10808
  sorted = self.sort_by(settlements, 'timestamp')
10807
- return self.filter_by_symbol_since_limit(sorted, market['symbol'], since, limit)
10809
+ return self.filter_by_symbol_since_limit(sorted, symbol, since, limit)
10808
10810
 
10809
10811
  def parse_settlement(self, settlement, market):
10810
10812
  #
@@ -12422,6 +12424,45 @@ class binance(Exchange, ImplicitAPI):
12422
12424
  #
12423
12425
  return self.parse_greeks(response[0], market)
12424
12426
 
12427
+ def fetch_all_greeks(self, symbols: Strings = None, params={}) -> List[Greeks]:
12428
+ """
12429
+ fetches all option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract
12430
+
12431
+ https://developers.binance.com/docs/derivatives/option/market-data/Option-Mark-Price
12432
+
12433
+ :param str[] [symbols]: unified symbols of the markets to fetch greeks for, all markets are returned if not assigned
12434
+ :param dict [params]: extra parameters specific to the exchange API endpoint
12435
+ :returns dict: a `greeks structure <https://docs.ccxt.com/#/?id=greeks-structure>`
12436
+ """
12437
+ self.load_markets()
12438
+ symbols = self.market_symbols(symbols, None, True, True, True)
12439
+ request: dict = {}
12440
+ market = None
12441
+ if symbols is not None:
12442
+ symbolsLength = len(symbols)
12443
+ if symbolsLength == 1:
12444
+ market = self.market(symbols[0])
12445
+ request['symbol'] = market['id']
12446
+ response = self.eapiPublicGetMark(self.extend(request, params))
12447
+ #
12448
+ # [
12449
+ # {
12450
+ # "symbol": "BTC-231229-40000-C",
12451
+ # "markPrice": "2012",
12452
+ # "bidIV": "0.60236275",
12453
+ # "askIV": "0.62267244",
12454
+ # "markIV": "0.6125176",
12455
+ # "delta": "0.39111646",
12456
+ # "theta": "-32.13948531",
12457
+ # "gamma": "0.00004656",
12458
+ # "vega": "51.70062218",
12459
+ # "highPriceLimit": "6474",
12460
+ # "lowPriceLimit": "5"
12461
+ # }
12462
+ # ]
12463
+ #
12464
+ return self.parse_all_greeks(response, symbols)
12465
+
12425
12466
  def parse_greeks(self, greeks: dict, market: Market = None) -> Greeks:
12426
12467
  #
12427
12468
  # {
ccxt/bitmart.py CHANGED
@@ -2160,6 +2160,7 @@ class bitmart(Exchange, ImplicitAPI):
2160
2160
  :param dict [params]: extra parameters specific to the exchange API endpoint
2161
2161
  :param int [params.until]: the latest time in ms to fetch trades for
2162
2162
  :param boolean [params.marginMode]: *spot* whether to fetch trades for margin orders or spot orders, defaults to spot orders(only isolated margin orders are supported)
2163
+ :param str [params.stpMode]: self-trade prevention only for spot, defaults to none, ['none', 'cancel_maker', 'cancel_taker', 'cancel_both']
2163
2164
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
2164
2165
  """
2165
2166
  self.load_markets()
@@ -2264,6 +2265,7 @@ class bitmart(Exchange, ImplicitAPI):
2264
2265
  :param int [since]: the earliest time in ms to fetch trades for
2265
2266
  :param int [limit]: the maximum number of trades to retrieve
2266
2267
  :param dict [params]: extra parameters specific to the exchange API endpoint
2268
+ :param str [params.stpMode]: self-trade prevention only for spot, defaults to none, ['none', 'cancel_maker', 'cancel_taker', 'cancel_both']
2267
2269
  :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
2268
2270
  """
2269
2271
  self.load_markets()
@@ -2706,6 +2708,7 @@ class bitmart(Exchange, ImplicitAPI):
2706
2708
  :param str [params.stopLossPrice]: *swap only* the price to trigger a stop-loss order
2707
2709
  :param str [params.takeProfitPrice]: *swap only* the price to trigger a take-profit order
2708
2710
  :param int [params.plan_category]: *swap tp/sl only* 1: tp/sl, 2: position tp/sl, default is 1
2711
+ :param str [params.stpMode]: self-trade prevention only for spot, defaults to none, ['none', 'cancel_maker', 'cancel_taker', 'cancel_both']
2709
2712
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2710
2713
  """
2711
2714
  self.load_markets()
@@ -2768,6 +2771,7 @@ class bitmart(Exchange, ImplicitAPI):
2768
2771
 
2769
2772
  :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
2770
2773
  :param dict [params]: extra parameters specific to the exchange API endpoint
2774
+ :param str [params.stpMode]: self-trade prevention only for spot, defaults to none, ['none', 'cancel_maker', 'cancel_taker', 'cancel_both']
2771
2775
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2772
2776
  """
2773
2777
  self.load_markets()
@@ -3270,6 +3274,7 @@ class bitmart(Exchange, ImplicitAPI):
3270
3274
  :param str [params.orderType]: *swap only* 'limit', 'market', or 'trailing'
3271
3275
  :param boolean [params.trailing]: *swap only* set to True if you want to fetch trailing orders
3272
3276
  :param boolean [params.trigger]: *swap only* set to True if you want to fetch trigger orders
3277
+ :param str [params.stpMode]: self-trade prevention only for spot, defaults to none, ['none', 'cancel_maker', 'cancel_taker', 'cancel_both']
3273
3278
  :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
3274
3279
  """
3275
3280
  self.load_markets()
@@ -3383,6 +3388,7 @@ class bitmart(Exchange, ImplicitAPI):
3383
3388
  :param dict [params]: extra parameters specific to the exchange API endpoint
3384
3389
  :param int [params.until]: timestamp in ms of the latest entry
3385
3390
  :param str [params.marginMode]: *spot only* 'cross' or 'isolated', for margin trading
3391
+ :param str [params.stpMode]: self-trade prevention only for spot, defaults to none, ['none', 'cancel_maker', 'cancel_taker', 'cancel_both']
3386
3392
  :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
3387
3393
  """
3388
3394
  self.load_markets()
@@ -3441,6 +3447,7 @@ class bitmart(Exchange, ImplicitAPI):
3441
3447
  :param str [params.clientOrderId]: *spot* fetch the order by client order id instead of order id
3442
3448
  :param str [params.orderType]: *swap only* 'limit', 'market', 'liquidate', 'bankruptcy', 'adl' or 'trailing'
3443
3449
  :param boolean [params.trailing]: *swap only* set to True if you want to fetch a trailing order
3450
+ :param str [params.stpMode]: self-trade prevention only for spot, defaults to none, ['none', 'cancel_maker', 'cancel_taker', 'cancel_both']
3444
3451
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
3445
3452
  """
3446
3453
  self.load_markets()
ccxt/bitmex.py CHANGED
@@ -1924,7 +1924,7 @@ class bitmex(Exchange, ImplicitAPI):
1924
1924
  :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1925
1925
  :param dict [params]: extra parameters specific to the exchange API endpoint
1926
1926
  :param dict [params.triggerPrice]: the price at which a trigger order is triggered at
1927
- :param dict [params.triggerDirection]: the direction whenever the trigger happens with relation to price - 'above' or 'below'
1927
+ :param dict [params.triggerDirection]: the direction whenever the trigger happens with relation to price - 'ascending' or 'descending'
1928
1928
  :param float [params.trailingAmount]: the quote amount to trail away from the current market price
1929
1929
  :returns dict: an `order structure <https://github.com/ccxt/ccxt/wiki/Manual#order-structure>`
1930
1930
  """
@@ -1951,7 +1951,7 @@ class bitmex(Exchange, ImplicitAPI):
1951
1951
  isTrailingAmountOrder = trailingAmount is not None
1952
1952
  if isTriggerOrder or isTrailingAmountOrder:
1953
1953
  triggerDirection = self.safe_string(params, 'triggerDirection')
1954
- triggerAbove = (triggerDirection == 'above')
1954
+ triggerAbove = ((triggerDirection == 'ascending') or (triggerDirection == 'above'))
1955
1955
  if (type == 'limit') or (type == 'market'):
1956
1956
  self.check_required_argument('createOrder', triggerDirection, 'triggerDirection', ['above', 'below'])
1957
1957
  if type == 'limit':
@@ -1994,7 +1994,7 @@ class bitmex(Exchange, ImplicitAPI):
1994
1994
  isTrailingAmountOrder = trailingAmount is not None
1995
1995
  if isTrailingAmountOrder:
1996
1996
  triggerDirection = self.safe_string(params, 'triggerDirection')
1997
- triggerAbove = (triggerDirection == 'above')
1997
+ triggerAbove = ((triggerDirection == 'ascending') or (triggerDirection == 'above'))
1998
1998
  if (type == 'limit') or (type == 'market'):
1999
1999
  self.check_required_argument('createOrder', triggerDirection, 'triggerDirection', ['above', 'below'])
2000
2000
  orderType = None
ccxt/bitvavo.py CHANGED
@@ -666,7 +666,7 @@ class bitvavo(Exchange, ImplicitAPI):
666
666
  },
667
667
  })
668
668
  # set currencies here to avoid calling publicGetAssets twice
669
- self.currencies = self.deep_extend(self.currencies, result)
669
+ self.currencies = self.map_to_safe_map(self.deep_extend(self.currencies, result))
670
670
  return result
671
671
 
672
672
  def fetch_ticker(self, symbol: str, params={}) -> Ticker:
@@ -1207,6 +1207,8 @@ class bitvavo(Exchange, ImplicitAPI):
1207
1207
  operatorId, params = self.handle_option_and_params(params, 'createOrder', 'operatorId')
1208
1208
  if operatorId is not None:
1209
1209
  request['operatorId'] = self.parse_to_int(operatorId)
1210
+ else:
1211
+ raise ArgumentsRequired(self.id + ' createOrder() requires an operatorId in params or options, eg: exchange.options[\'operatorId\'] = 1234567890')
1210
1212
  return self.extend(request, params)
1211
1213
 
1212
1214
  def create_order(self, symbol: Str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
@@ -1304,6 +1306,8 @@ class bitvavo(Exchange, ImplicitAPI):
1304
1306
  operatorId, params = self.handle_option_and_params(params, 'editOrder', 'operatorId')
1305
1307
  if operatorId is not None:
1306
1308
  request['operatorId'] = self.parse_to_int(operatorId)
1309
+ else:
1310
+ raise ArgumentsRequired(self.id + ' editOrder() requires an operatorId in params or options, eg: exchange.options[\'operatorId\'] = 1234567890')
1307
1311
  request['market'] = market['id']
1308
1312
  return request
1309
1313
 
@@ -1342,6 +1346,8 @@ class bitvavo(Exchange, ImplicitAPI):
1342
1346
  operatorId, params = self.handle_option_and_params(params, 'cancelOrder', 'operatorId')
1343
1347
  if operatorId is not None:
1344
1348
  request['operatorId'] = self.parse_to_int(operatorId)
1349
+ else:
1350
+ raise ArgumentsRequired(self.id + ' cancelOrder() requires an operatorId in params or options, eg: exchange.options[\'operatorId\'] = 1234567890')
1345
1351
  return self.extend(request, params)
1346
1352
 
1347
1353
  def cancel_order(self, id: str, symbol: Str = None, params={}):
ccxt/bybit.py CHANGED
@@ -74,6 +74,7 @@ class bybit(Exchange, ImplicitAPI):
74
74
  'createTriggerOrder': True,
75
75
  'editOrder': True,
76
76
  'editOrders': True,
77
+ 'fetchAllGreeks': True,
77
78
  'fetchBalance': True,
78
79
  'fetchBidsAsks': 'emulated',
79
80
  'fetchBorrowInterest': False, # temporarily disabled, doesn't work
@@ -1172,6 +1173,7 @@ class bybit(Exchange, ImplicitAPI):
1172
1173
  '4h': '4h',
1173
1174
  '1d': '1d',
1174
1175
  },
1176
+ 'useMarkPriceForPositionCollateral': False, # use mark price for position collateral
1175
1177
  },
1176
1178
  'features': {
1177
1179
  'default': {
@@ -3725,7 +3727,7 @@ class bybit(Exchange, ImplicitAPI):
3725
3727
  :param int [params.isLeverage]: *unified spot only* False then spot trading True then margin trading
3726
3728
  :param str [params.tpslMode]: *contract only* 'full' or 'partial'
3727
3729
  :param str [params.mmp]: *option only* market maker protection
3728
- :param str [params.triggerDirection]: *contract only* the direction for trigger orders, 'above' or 'below'
3730
+ :param str [params.triggerDirection]: *contract only* the direction for trigger orders, 'ascending' or 'descending'
3729
3731
  :param float [params.triggerPrice]: The price at which a trigger order is triggered at
3730
3732
  :param float [params.stopLossPrice]: The price at which a stop loss order is triggered at
3731
3733
  :param float [params.takeProfitPrice]: The price at which a take profit order is triggered at
@@ -3935,8 +3937,8 @@ class bybit(Exchange, ImplicitAPI):
3935
3937
  raise NotSupported(self.id + ' createOrder() : trigger order does not support triggerDirection for spot markets yet')
3936
3938
  else:
3937
3939
  if triggerDirection is None:
3938
- raise ArgumentsRequired(self.id + ' stop/trigger orders require a triggerDirection parameter, either "above" or "below" to determine the direction of the trigger.')
3939
- isAsending = ((triggerDirection == 'above') or (triggerDirection == '1'))
3940
+ raise ArgumentsRequired(self.id + ' stop/trigger orders require a triggerDirection parameter, either "ascending" or "descending" to determine the direction of the trigger.')
3941
+ isAsending = ((triggerDirection == 'ascending') or (triggerDirection == 'above') or (triggerDirection == '1'))
3940
3942
  request['triggerDirection'] = 1 if isAsending else 2
3941
3943
  request['triggerPrice'] = self.get_price(symbol, triggerPrice)
3942
3944
  elif (isStopLossTriggerOrder or isTakeProfitTriggerOrder) and not isAlternativeEndpoint:
@@ -6213,12 +6215,14 @@ classic accounts only/ spot not supported* fetches information on an order made
6213
6215
  marginMode = 'isolated' if (tradeMode == 1) else 'cross'
6214
6216
  collateralString = self.safe_string(position, 'positionBalance')
6215
6217
  entryPrice = self.omit_zero(self.safe_string_n(position, ['entryPrice', 'avgPrice', 'avgEntryPrice']))
6218
+ markPrice = self.safe_string(position, 'markPrice')
6216
6219
  liquidationPrice = self.omit_zero(self.safe_string(position, 'liqPrice'))
6217
6220
  leverage = self.safe_string(position, 'leverage')
6218
6221
  if liquidationPrice is not None:
6219
6222
  if market['settle'] == 'USDC':
6220
6223
  # (Entry price - Liq price) * Contracts + Maintenance Margin + (unrealised pnl) = Collateral
6221
- difference = Precise.string_abs(Precise.string_sub(entryPrice, liquidationPrice))
6224
+ price = markPrice if self.safe_bool(self.options, 'useMarkPriceForPositionCollateral', False) else entryPrice
6225
+ difference = Precise.string_abs(Precise.string_sub(price, liquidationPrice))
6222
6226
  collateralString = Precise.string_add(Precise.string_add(Precise.string_mul(difference, size), maintenanceMarginString), unrealisedPnl)
6223
6227
  else:
6224
6228
  bustPrice = self.safe_string(position, 'bustPrice')
@@ -6267,7 +6271,7 @@ classic accounts only/ spot not supported* fetches information on an order made
6267
6271
  'contractSize': self.safe_number(market, 'contractSize'),
6268
6272
  'marginRatio': self.parse_number(marginRatio),
6269
6273
  'liquidationPrice': self.parse_number(liquidationPrice),
6270
- 'markPrice': self.safe_number(position, 'markPrice'),
6274
+ 'markPrice': self.parse_number(markPrice),
6271
6275
  'lastPrice': self.safe_number(position, 'avgExitPrice'),
6272
6276
  'collateral': self.parse_number(collateralString),
6273
6277
  'marginMode': marginMode,
@@ -7624,6 +7628,75 @@ classic accounts only/ spot not supported* fetches information on an order made
7624
7628
  'datetime': self.iso8601(timestamp),
7625
7629
  })
7626
7630
 
7631
+ def fetch_all_greeks(self, symbols: Strings = None, params={}) -> List[Greeks]:
7632
+ """
7633
+ fetches all option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract
7634
+
7635
+ https://bybit-exchange.github.io/docs/api-explorer/v5/market/tickers
7636
+
7637
+ :param str[] [symbols]: unified symbols of the markets to fetch greeks for, all markets are returned if not assigned
7638
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7639
+ :param str [params.baseCoin]: the baseCoin of the symbol, default is BTC
7640
+ :returns dict: a `greeks structure <https://docs.ccxt.com/#/?id=greeks-structure>`
7641
+ """
7642
+ self.load_markets()
7643
+ symbols = self.market_symbols(symbols, None, True, True, True)
7644
+ baseCoin = self.safe_string(params, 'baseCoin', 'BTC')
7645
+ request: dict = {
7646
+ 'category': 'option',
7647
+ 'baseCoin': baseCoin,
7648
+ }
7649
+ market = None
7650
+ if symbols is not None:
7651
+ symbolsLength = len(symbols)
7652
+ if symbolsLength == 1:
7653
+ market = self.market(symbols[0])
7654
+ request['symbol'] = market['id']
7655
+ response = self.publicGetV5MarketTickers(self.extend(request, params))
7656
+ #
7657
+ # {
7658
+ # "retCode": 0,
7659
+ # "retMsg": "SUCCESS",
7660
+ # "result": {
7661
+ # "category": "option",
7662
+ # "list": [
7663
+ # {
7664
+ # "symbol": "BTC-26JAN24-39000-C",
7665
+ # "bid1Price": "3205",
7666
+ # "bid1Size": "7.1",
7667
+ # "bid1Iv": "0.5478",
7668
+ # "ask1Price": "3315",
7669
+ # "ask1Size": "1.98",
7670
+ # "ask1Iv": "0.5638",
7671
+ # "lastPrice": "3230",
7672
+ # "highPrice24h": "3255",
7673
+ # "lowPrice24h": "3200",
7674
+ # "markPrice": "3273.02263032",
7675
+ # "indexPrice": "36790.96",
7676
+ # "markIv": "0.5577",
7677
+ # "underlyingPrice": "37649.67254894",
7678
+ # "openInterest": "19.67",
7679
+ # "turnover24h": "170140.33875912",
7680
+ # "volume24h": "4.56",
7681
+ # "totalVolume": "22",
7682
+ # "totalTurnover": "789305",
7683
+ # "delta": "0.49640971",
7684
+ # "gamma": "0.00004131",
7685
+ # "vega": "69.08651675",
7686
+ # "theta": "-24.9443226",
7687
+ # "predictedDeliveryPrice": "0",
7688
+ # "change24h": "0.18532111"
7689
+ # }
7690
+ # ]
7691
+ # },
7692
+ # "retExtInfo": {},
7693
+ # "time": 1699584008326
7694
+ # }
7695
+ #
7696
+ result = self.safe_dict(response, 'result', {})
7697
+ data = self.safe_list(result, 'list', [])
7698
+ return self.parse_all_greeks(data, symbols)
7699
+
7627
7700
  def parse_greeks(self, greeks: dict, market: Market = None) -> Greeks:
7628
7701
  #
7629
7702
  # {
@@ -8730,7 +8803,7 @@ classic accounts only/ spot not supported* fetches information on an order made
8730
8803
  authFull = auth_base + body
8731
8804
  else:
8732
8805
  authFull = auth_base + queryEncoded
8733
- url += '?' + self.rawencode(query)
8806
+ url += '?' + queryEncoded
8734
8807
  signature = None
8735
8808
  if self.secret.find('PRIVATE KEY') > -1:
8736
8809
  signature = self.rsa(authFull, self.secret, 'sha256')
@@ -8744,7 +8817,7 @@ classic accounts only/ spot not supported* fetches information on an order made
8744
8817
  'timestamp': timestamp,
8745
8818
  })
8746
8819
  sortedQuery = self.keysort(query)
8747
- auth = self.rawencode(sortedQuery)
8820
+ auth = self.rawencode(sortedQuery, True)
8748
8821
  signature = None
8749
8822
  if self.secret.find('PRIVATE KEY') > -1:
8750
8823
  signature = self.rsa(auth, self.secret, 'sha256')
@@ -8766,7 +8839,7 @@ classic accounts only/ spot not supported* fetches information on an order made
8766
8839
  'Content-Type': 'application/json',
8767
8840
  }
8768
8841
  else:
8769
- url += '?' + self.rawencode(sortedQuery)
8842
+ url += '?' + self.rawencode(sortedQuery, True)
8770
8843
  url += '&sign=' + signature
8771
8844
  if method == 'POST':
8772
8845
  brokerId = self.safe_string(self.options, 'brokerId')