ccxt 4.4.92__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 (48) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/lbank.py +1 -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 +3 -0
  8. ccxt/async_support/binance.py +42 -1
  9. ccxt/async_support/bitmex.py +3 -3
  10. ccxt/async_support/bybit.py +81 -8
  11. ccxt/async_support/coinbaseexchange.py +53 -0
  12. ccxt/async_support/coincheck.py +45 -4
  13. ccxt/async_support/coinex.py +16 -12
  14. ccxt/async_support/cryptomus.py +30 -52
  15. ccxt/async_support/deribit.py +6 -6
  16. ccxt/async_support/exmo.py +64 -52
  17. ccxt/async_support/hyperliquid.py +2 -1
  18. ccxt/async_support/kucoin.py +12 -14
  19. ccxt/async_support/latoken.py +19 -71
  20. ccxt/async_support/lbank.py +2 -2
  21. ccxt/async_support/okx.py +149 -0
  22. ccxt/async_support/paradex.py +54 -0
  23. ccxt/async_support/phemex.py +3 -3
  24. ccxt/base/exchange.py +55 -12
  25. ccxt/binance.py +42 -1
  26. ccxt/bitmex.py +3 -3
  27. ccxt/bybit.py +81 -8
  28. ccxt/coinbaseexchange.py +53 -0
  29. ccxt/coincheck.py +45 -4
  30. ccxt/coinex.py +16 -12
  31. ccxt/cryptomus.py +30 -52
  32. ccxt/deribit.py +6 -6
  33. ccxt/exmo.py +64 -52
  34. ccxt/hyperliquid.py +2 -1
  35. ccxt/kucoin.py +12 -14
  36. ccxt/latoken.py +19 -71
  37. ccxt/lbank.py +2 -2
  38. ccxt/okx.py +149 -0
  39. ccxt/paradex.py +54 -0
  40. ccxt/phemex.py +3 -3
  41. ccxt/pro/__init__.py +1 -1
  42. ccxt/pro/bitstamp.py +48 -16
  43. ccxt/pro/bybit.py +2 -1
  44. {ccxt-4.4.92.dist-info → ccxt-4.4.93.dist-info}/METADATA +4 -4
  45. {ccxt-4.4.92.dist-info → ccxt-4.4.93.dist-info}/RECORD +48 -48
  46. {ccxt-4.4.92.dist-info → ccxt-4.4.93.dist-info}/LICENSE.txt +0 -0
  47. {ccxt-4.4.92.dist-info → ccxt-4.4.93.dist-info}/WHEEL +0 -0
  48. {ccxt-4.4.92.dist-info → ccxt-4.4.93.dist-info}/top_level.txt +0 -0
ccxt/async_support/okx.py CHANGED
@@ -81,6 +81,7 @@ class okx(Exchange, ImplicitAPI):
81
81
  'createTriggerOrder': True,
82
82
  'editOrder': True,
83
83
  'fetchAccounts': True,
84
+ 'fetchAllGreeks': True,
84
85
  'fetchBalance': True,
85
86
  'fetchBidsAsks': None,
86
87
  'fetchBorrowInterest': True,
@@ -3614,6 +3615,84 @@ class okx(Exchange, ImplicitAPI):
3614
3615
  # "uTime": "1621910749815"
3615
3616
  # }
3616
3617
  #
3618
+ # watchOrders & fetchClosedOrders
3619
+ #
3620
+ # {
3621
+ # "algoClOrdId": "",
3622
+ # "algoId": "",
3623
+ # "attachAlgoClOrdId": "",
3624
+ # "attachAlgoOrds": [],
3625
+ # "cancelSource": "",
3626
+ # "cancelSourceReason": "", # not present in WS, but present in fetchClosedOrders
3627
+ # "category": "normal",
3628
+ # "ccy": "", # empty in WS, but eg. `USDT` in fetchClosedOrders
3629
+ # "clOrdId": "",
3630
+ # "cTime": "1751705801423",
3631
+ # "feeCcy": "USDT",
3632
+ # "instId": "LINK-USDT-SWAP",
3633
+ # "instType": "SWAP",
3634
+ # "isTpLimit": "false",
3635
+ # "lever": "3",
3636
+ # "linkedAlgoOrd": {"algoId": ""},
3637
+ # "ordId": "2657625147249614848",
3638
+ # "ordType": "limit",
3639
+ # "posSide": "net",
3640
+ # "px": "13.142",
3641
+ # "pxType": "",
3642
+ # "pxUsd": "",
3643
+ # "pxVol": "",
3644
+ # "quickMgnType": "",
3645
+ # "rebate": "0",
3646
+ # "rebateCcy": "USDT",
3647
+ # "reduceOnly": "true",
3648
+ # "side": "sell",
3649
+ # "slOrdPx": "",
3650
+ # "slTriggerPx": "",
3651
+ # "slTriggerPxType": "",
3652
+ # "source": "",
3653
+ # "stpId": "",
3654
+ # "stpMode": "cancel_maker",
3655
+ # "sz": "0.1",
3656
+ # "tag": "",
3657
+ # "tdMode": "isolated",
3658
+ # "tgtCcy": "",
3659
+ # "tpOrdPx": "",
3660
+ # "tpTriggerPx": "",
3661
+ # "tpTriggerPxType": "",
3662
+ # "uTime": "1751705807467",
3663
+ # "reqId": "", # field present only in WS
3664
+ # "msg": "", # field present only in WS
3665
+ # "amendResult": "", # field present only in WS
3666
+ # "amendSource": "", # field present only in WS
3667
+ # "code": "0", # field present only in WS
3668
+ # "fillFwdPx": "", # field present only in WS
3669
+ # "fillMarkVol": "", # field present only in WS
3670
+ # "fillPxUsd": "", # field present only in WS
3671
+ # "fillPxVol": "", # field present only in WS
3672
+ # "lastPx": "13.142", # field present only in WS
3673
+ # "notionalUsd": "1.314515408", # field present only in WS
3674
+ #
3675
+ # #### these below fields are empty on first omit from websocket, because of "creation" event. however, if order is executed, it also immediately sends another update with these fields filled ###
3676
+ #
3677
+ # "pnl": "-0.0001",
3678
+ # "accFillSz": "0.1",
3679
+ # "avgPx": "13.142",
3680
+ # "state": "filled",
3681
+ # "fee": "-0.00026284",
3682
+ # "fillPx": "13.142",
3683
+ # "tradeId": "293429690",
3684
+ # "fillSz": "0.1",
3685
+ # "fillTime": "1751705807467",
3686
+ # "fillNotionalUsd": "1.314515408", # field present only in WS
3687
+ # "fillPnl": "-0.0001", # field present only in WS
3688
+ # "fillFee": "-0.00026284", # field present only in WS
3689
+ # "fillFeeCcy": "USDT", # field present only in WS
3690
+ # "execType": "M", # field present only in WS
3691
+ # "fillMarkPx": "13.141", # field present only in WS
3692
+ # "fillIdxPx": "13.147" # field present only in WS
3693
+ # }
3694
+ #
3695
+ #
3617
3696
  # Algo Order fetchOpenOrders, fetchCanceledOrders, fetchClosedOrders
3618
3697
  #
3619
3698
  # {
@@ -7548,6 +7627,76 @@ class okx(Exchange, ImplicitAPI):
7548
7627
  return self.parse_greeks(entry, market)
7549
7628
  return None
7550
7629
 
7630
+ async def fetch_all_greeks(self, symbols: Strings = None, params={}) -> List[Greeks]:
7631
+ """
7632
+ fetches all option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract
7633
+
7634
+ https://www.okx.com/docs-v5/en/#public-data-rest-api-get-option-market-data
7635
+
7636
+ :param str[] [symbols]: unified symbols of the markets to fetch greeks for, all markets are returned if not assigned
7637
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7638
+ :param str params['uly']: Underlying, either uly or instFamily is required
7639
+ :param str params['instFamily']: Instrument family, either uly or instFamily is required
7640
+ :returns dict: a `greeks structure <https://docs.ccxt.com/#/?id=greeks-structure>`
7641
+ """
7642
+ await self.load_markets()
7643
+ request: dict = {}
7644
+ symbols = self.market_symbols(symbols, None, True, True, True)
7645
+ symbolsLength = None
7646
+ if symbols is not None:
7647
+ symbolsLength = len(symbols)
7648
+ if (symbols is None) or (symbolsLength != 1):
7649
+ uly = self.safe_string(params, 'uly')
7650
+ if uly is not None:
7651
+ request['uly'] = uly
7652
+ instFamily = self.safe_string(params, 'instFamily')
7653
+ if instFamily is not None:
7654
+ request['instFamily'] = instFamily
7655
+ if (uly is None) and (instFamily is None):
7656
+ raise BadRequest(self.id + ' fetchAllGreeks() requires either a uly or instFamily parameter')
7657
+ market = None
7658
+ if symbols is not None:
7659
+ if symbolsLength == 1:
7660
+ market = self.market(symbols[0])
7661
+ marketId = market['id']
7662
+ optionParts = marketId.split('-')
7663
+ request['uly'] = market['info']['uly']
7664
+ request['instFamily'] = market['info']['instFamily']
7665
+ request['expTime'] = self.safe_string(optionParts, 2)
7666
+ params = self.omit(params, ['uly', 'instFamily'])
7667
+ response = await self.publicGetPublicOptSummary(self.extend(request, params))
7668
+ #
7669
+ # {
7670
+ # "code": "0",
7671
+ # "data": [
7672
+ # {
7673
+ # "askVol": "0",
7674
+ # "bidVol": "0",
7675
+ # "delta": "0.5105464486882039",
7676
+ # "deltaBS": "0.7325502184143025",
7677
+ # "fwdPx": "37675.80158694987186",
7678
+ # "gamma": "-0.13183515090501083",
7679
+ # "gammaBS": "0.000024139685826358558",
7680
+ # "instId": "BTC-USD-240329-32000-C",
7681
+ # "instType": "OPTION",
7682
+ # "lever": "4.504428015946619",
7683
+ # "markVol": "0.5916253554539876",
7684
+ # "realVol": "0",
7685
+ # "theta": "-0.0004202992014012855",
7686
+ # "thetaBS": "-18.52354631567909",
7687
+ # "ts": "1699586421976",
7688
+ # "uly": "BTC-USD",
7689
+ # "vega": "0.0020207455080045846",
7690
+ # "vegaBS": "74.44022302387287",
7691
+ # "volLv": "0.5948549730405797"
7692
+ # },
7693
+ # ],
7694
+ # "msg": ""
7695
+ # }
7696
+ #
7697
+ data = self.safe_list(response, 'data', [])
7698
+ return self.parse_all_greeks(data, symbols)
7699
+
7551
7700
  def parse_greeks(self, greeks: dict, market: Market = None) -> Greeks:
7552
7701
  #
7553
7702
  # {
@@ -57,6 +57,7 @@ class paradex(Exchange, ImplicitAPI):
57
57
  'createTriggerOrder': True,
58
58
  'editOrder': False,
59
59
  'fetchAccounts': False,
60
+ 'fetchAllGreeks': True,
60
61
  'fetchBalance': True,
61
62
  'fetchBorrowInterest': False,
62
63
  'fetchBorrowRateHistories': False,
@@ -2346,6 +2347,59 @@ class paradex(Exchange, ImplicitAPI):
2346
2347
  greeks = self.safe_dict(data, 0, {})
2347
2348
  return self.parse_greeks(greeks, market)
2348
2349
 
2350
+ async def fetch_all_greeks(self, symbols: Strings = None, params={}) -> List[Greeks]:
2351
+ """
2352
+ fetches all option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract
2353
+
2354
+ https://docs.api.testnet.paradex.trade/#list-available-markets-summary
2355
+
2356
+ :param str[] [symbols]: unified symbols of the markets to fetch greeks for, all markets are returned if not assigned
2357
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2358
+ :returns dict: a `greeks structure <https://docs.ccxt.com/#/?id=greeks-structure>`
2359
+ """
2360
+ await self.load_markets()
2361
+ symbols = self.market_symbols(symbols, None, True, True, True)
2362
+ request: dict = {
2363
+ 'market': 'ALL',
2364
+ }
2365
+ response = await self.publicGetMarketsSummary(self.extend(request, params))
2366
+ #
2367
+ # {
2368
+ # "results": [
2369
+ # {
2370
+ # "symbol": "BTC-USD-114000-P",
2371
+ # "mark_price": "10835.66892602",
2372
+ # "mark_iv": "0.71781855",
2373
+ # "delta": "-0.98726024",
2374
+ # "greeks": {
2375
+ # "delta": "-0.9872602390817709",
2376
+ # "gamma": "0.000004560958862297231",
2377
+ # "vega": "227.11344863639806",
2378
+ # "rho": "-302.0617972461581",
2379
+ # "vanna": "0.06609830491614832",
2380
+ # "volga": "925.9501532805552"
2381
+ # },
2382
+ # "last_traded_price": "10551.5",
2383
+ # "bid": "10794.9",
2384
+ # "bid_iv": "0.05",
2385
+ # "ask": "10887.3",
2386
+ # "ask_iv": "0.8783283",
2387
+ # "last_iv": "0.05",
2388
+ # "volume_24h": "0",
2389
+ # "total_volume": "195240.72672261014",
2390
+ # "created_at": 1747644009995,
2391
+ # "underlying_price": "103164.79162649",
2392
+ # "open_interest": "0",
2393
+ # "funding_rate": "0.000004464241170536191",
2394
+ # "price_change_rate_24h": "0.074915",
2395
+ # "future_funding_rate": "0.0001"
2396
+ # }
2397
+ # ]
2398
+ # }
2399
+ #
2400
+ results = self.safe_list(response, 'results', [])
2401
+ return self.parse_all_greeks(results, symbols)
2402
+
2349
2403
  def parse_greeks(self, greeks: dict, market: Market = None) -> Greeks:
2350
2404
  #
2351
2405
  # {
@@ -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.92'
7
+ __version__ = '4.4.93'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -4229,7 +4229,7 @@ class Exchange(object):
4229
4229
  return self.filter_by_since_limit(sorted, since, limit, 0, tail)
4230
4230
 
4231
4231
  def parse_leverage_tiers(self, response: Any, symbols: List[str] = None, marketIdKey=None):
4232
- # marketIdKey should only be None when response is a dictionary
4232
+ # marketIdKey should only be None when response is a dictionary.
4233
4233
  symbols = self.market_symbols(symbols)
4234
4234
  tiers = {}
4235
4235
  symbolsLength = 0
@@ -5450,6 +5450,9 @@ class Exchange(object):
5450
5450
  def fetch_greeks(self, symbol: str, params={}):
5451
5451
  raise NotSupported(self.id + ' fetchGreeks() is not supported yet')
5452
5452
 
5453
+ def fetch_all_greeks(self, symbols: Strings = None, params={}):
5454
+ raise NotSupported(self.id + ' fetchAllGreeks() is not supported yet')
5455
+
5453
5456
  def fetch_option_chain(self, code: str, params={}):
5454
5457
  raise NotSupported(self.id + ' fetchOptionChain() is not supported yet')
5455
5458
 
@@ -5703,10 +5706,16 @@ class Exchange(object):
5703
5706
  precisionNumber = int(precision)
5704
5707
  if precisionNumber == 0:
5705
5708
  return '1'
5706
- parsedPrecision = '0.'
5707
- for i in range(0, precisionNumber - 1):
5708
- parsedPrecision = parsedPrecision + '0'
5709
- 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'
5710
5719
 
5711
5720
  def integer_precision_to_amount(self, precision: Str):
5712
5721
  """
@@ -6682,6 +6691,27 @@ class Exchange(object):
6682
6691
  def parse_greeks(self, greeks: dict, market: Market = None):
6683
6692
  raise NotSupported(self.id + ' parseGreeks() is not supported yet')
6684
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
+
6685
6715
  def parse_option(self, chain: dict, currency: Currency = None, market: Market = None):
6686
6716
  raise NotSupported(self.id + ' parseOption() is not supported yet')
6687
6717
 
@@ -6883,14 +6913,27 @@ class Exchange(object):
6883
6913
  """
6884
6914
  raise NotSupported(self.id + ' fetchTransfers() is not supported yet')
6885
6915
 
6886
- def clean_unsubscription(self, client, subHash: str, unsubHash: str):
6916
+ def clean_unsubscription(self, client, subHash: str, unsubHash: str, subHashIsPrefix=False):
6887
6917
  if unsubHash in client.subscriptions:
6888
6918
  del client.subscriptions[unsubHash]
6889
- if subHash in client.subscriptions:
6890
- del client.subscriptions[subHash]
6891
- if subHash in client.futures:
6892
- error = UnsubscribeError(self.id + ' ' + subHash)
6893
- 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)
6894
6937
  client.resolve(True, unsubHash)
6895
6938
 
6896
6939
  def clean_cache(self, subscription: dict):
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/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/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')