ccxt 4.4.92__py2.py3-none-any.whl → 4.4.94__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 (58) 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 +83 -10
  11. ccxt/async_support/coinbase.py +4 -1
  12. ccxt/async_support/coinbaseexchange.py +53 -0
  13. ccxt/async_support/coincheck.py +45 -4
  14. ccxt/async_support/coinex.py +16 -12
  15. ccxt/async_support/coinmetro.py +15 -3
  16. ccxt/async_support/cryptomus.py +30 -52
  17. ccxt/async_support/deribit.py +6 -6
  18. ccxt/async_support/exmo.py +64 -52
  19. ccxt/async_support/htx.py +5 -1
  20. ccxt/async_support/hyperliquid.py +126 -33
  21. ccxt/async_support/kucoin.py +12 -14
  22. ccxt/async_support/latoken.py +19 -71
  23. ccxt/async_support/lbank.py +2 -2
  24. ccxt/async_support/okx.py +159 -3
  25. ccxt/async_support/paradex.py +54 -0
  26. ccxt/async_support/phemex.py +3 -3
  27. ccxt/async_support/wavesexchange.py +12 -2
  28. ccxt/base/exchange.py +96 -31
  29. ccxt/binance.py +42 -1
  30. ccxt/bitmex.py +3 -3
  31. ccxt/bybit.py +83 -10
  32. ccxt/coinbase.py +4 -1
  33. ccxt/coinbaseexchange.py +53 -0
  34. ccxt/coincheck.py +45 -4
  35. ccxt/coinex.py +16 -12
  36. ccxt/coinmetro.py +14 -3
  37. ccxt/cryptomus.py +30 -52
  38. ccxt/deribit.py +6 -6
  39. ccxt/exmo.py +64 -52
  40. ccxt/htx.py +5 -1
  41. ccxt/hyperliquid.py +126 -33
  42. ccxt/kucoin.py +12 -14
  43. ccxt/latoken.py +19 -71
  44. ccxt/lbank.py +2 -2
  45. ccxt/okx.py +159 -3
  46. ccxt/paradex.py +54 -0
  47. ccxt/phemex.py +3 -3
  48. ccxt/pro/__init__.py +1 -1
  49. ccxt/pro/bitstamp.py +48 -16
  50. ccxt/pro/bybit.py +2 -1
  51. ccxt/test/tests_async.py +17 -15
  52. ccxt/test/tests_sync.py +17 -15
  53. ccxt/wavesexchange.py +12 -2
  54. {ccxt-4.4.92.dist-info → ccxt-4.4.94.dist-info}/METADATA +4 -4
  55. {ccxt-4.4.92.dist-info → ccxt-4.4.94.dist-info}/RECORD +58 -58
  56. {ccxt-4.4.92.dist-info → ccxt-4.4.94.dist-info}/LICENSE.txt +0 -0
  57. {ccxt-4.4.92.dist-info → ccxt-4.4.94.dist-info}/WHEEL +0 -0
  58. {ccxt-4.4.92.dist-info → ccxt-4.4.94.dist-info}/top_level.txt +0 -0
ccxt/kucoin.py CHANGED
@@ -1396,35 +1396,31 @@ class kucoin(Exchange, ImplicitAPI):
1396
1396
  # }
1397
1397
  #
1398
1398
  currenciesData = self.safe_list(response, 'data', [])
1399
+ brokenCurrencies = self.safe_list(self.options, 'brokenCurrencies', ['00', 'OPEN_ERROR', 'HUF', 'BDT'])
1400
+ otherFiats = self.safe_list(self.options, 'fiats', ['KWD', 'IRR', 'PKR'])
1399
1401
  result: dict = {}
1400
1402
  for i in range(0, len(currenciesData)):
1401
1403
  entry = currenciesData[i]
1402
1404
  id = self.safe_string(entry, 'currency')
1403
- name = self.safe_string(entry, 'fullName')
1405
+ if self.in_array(id, brokenCurrencies):
1406
+ continue # skip buggy entries: https://t.me/KuCoin_API/217798
1404
1407
  code = self.safe_currency_code(id)
1405
1408
  networks: dict = {}
1406
1409
  chains = self.safe_list(entry, 'chains', [])
1407
- rawPrecision = self.safe_string(entry, 'precision')
1408
- precision = self.parse_number(self.parse_precision(rawPrecision))
1409
1410
  chainsLength = len(chains)
1410
- if not chainsLength:
1411
- # one buggy coin, which doesn't contain info https://t.me/KuCoin_API/173118
1412
- continue
1413
1411
  for j in range(0, chainsLength):
1414
1412
  chain = chains[j]
1415
1413
  chainId = self.safe_string(chain, 'chainId')
1416
1414
  networkCode = self.network_id_to_code(chainId, code)
1417
- chainWithdrawEnabled = self.safe_bool(chain, 'isWithdrawEnabled', False)
1418
- chainDepositEnabled = self.safe_bool(chain, 'isDepositEnabled', False)
1419
1415
  networks[networkCode] = {
1420
1416
  'info': chain,
1421
1417
  'id': chainId,
1422
1418
  'name': self.safe_string(chain, 'chainName'),
1423
1419
  'code': networkCode,
1424
- 'active': chainWithdrawEnabled and chainDepositEnabled,
1420
+ 'active': None,
1425
1421
  'fee': self.safe_number(chain, 'withdrawalMinFee'),
1426
- 'deposit': chainDepositEnabled,
1427
- 'withdraw': chainWithdrawEnabled,
1422
+ 'deposit': self.safe_bool(chain, 'isDepositEnabled'),
1423
+ 'withdraw': self.safe_bool(chain, 'isWithdrawEnabled'),
1428
1424
  'precision': self.parse_number(self.parse_precision(self.safe_string(chain, 'withdrawPrecision'))),
1429
1425
  'limits': {
1430
1426
  'withdraw': {
@@ -1438,10 +1434,12 @@ class kucoin(Exchange, ImplicitAPI):
1438
1434
  },
1439
1435
  }
1440
1436
  # kucoin has determined 'fiat' currencies with below logic
1441
- isFiat = (rawPrecision == '2') and (chainsLength == 0)
1437
+ rawPrecision = self.safe_string(entry, 'precision')
1438
+ precision = self.parse_number(self.parse_precision(rawPrecision))
1439
+ isFiat = self.in_array(id, otherFiats) or ((rawPrecision == '2') and (chainsLength == 0))
1442
1440
  result[code] = self.safe_currency_structure({
1443
1441
  'id': id,
1444
- 'name': name,
1442
+ 'name': self.safe_string(entry, 'fullName'),
1445
1443
  'code': code,
1446
1444
  'type': 'fiat' if isFiat else 'crypto',
1447
1445
  'precision': precision,
@@ -2627,7 +2625,7 @@ class kucoin(Exchange, ImplicitAPI):
2627
2625
  """
2628
2626
  self.load_markets()
2629
2627
  request: dict = {}
2630
- trigger = self.safe_bool(params, 'stop', False)
2628
+ trigger = self.safe_bool_2(params, 'trigger', 'stop', False)
2631
2629
  hf = None
2632
2630
  hf, params = self.handle_hf_and_params(params)
2633
2631
  params = self.omit(params, 'stop')
ccxt/latoken.py CHANGED
@@ -247,6 +247,8 @@ class latoken(Exchange, ImplicitAPI):
247
247
  'fetchTradingFee': {
248
248
  'method': 'fetchPrivateTradingFee', # or 'fetchPublicTradingFee'
249
249
  },
250
+ 'timeDifference': 0, # the difference between system clock and exchange clock
251
+ 'adjustForTimeDifference': True, # controls the adjustment logic upon instantiation
250
252
  },
251
253
  'features': {
252
254
  'spot': {
@@ -347,39 +349,6 @@ class latoken(Exchange, ImplicitAPI):
347
349
  :param dict [params]: extra parameters specific to the exchange API endpoint
348
350
  :returns dict[]: an array of objects representing market data
349
351
  """
350
- currencies = self.fetch_currencies_from_cache(params)
351
- #
352
- # [
353
- # {
354
- # "id":"1a075819-9e0b-48fc-8784-4dab1d186d6d",
355
- # "status":"CURRENCY_STATUS_ACTIVE",
356
- # "type":"CURRENCY_TYPE_ALTERNATIVE", # CURRENCY_TYPE_CRYPTO, CURRENCY_TYPE_IEO
357
- # "name":"MyCryptoBank",
358
- # "tag":"MCB",
359
- # "description":"",
360
- # "logo":"",
361
- # "decimals":18,
362
- # "created":1572912000000,
363
- # "tier":1,
364
- # "assetClass":"ASSET_CLASS_UNKNOWN",
365
- # "minTransferAmount":0
366
- # },
367
- # {
368
- # "id":"db02758e-2507-46a5-a805-7bc60355b3eb",
369
- # "status":"CURRENCY_STATUS_ACTIVE",
370
- # "type":"CURRENCY_TYPE_FUTURES_CONTRACT",
371
- # "name":"BTC USDT Futures Contract",
372
- # "tag":"BTCUSDT",
373
- # "description":"",
374
- # "logo":"",
375
- # "decimals":8,
376
- # "created":1589459984395,
377
- # "tier":1,
378
- # "assetClass":"ASSET_CLASS_UNKNOWN",
379
- # "minTransferAmount":0
380
- # },
381
- # ]
382
- #
383
352
  response = self.publicGetPair(params)
384
353
  #
385
354
  # [
@@ -401,8 +370,9 @@ class latoken(Exchange, ImplicitAPI):
401
370
  # }
402
371
  # ]
403
372
  #
404
- if self.safe_value(self.options, 'adjustForTimeDifference', True):
373
+ if self.safe_bool(self.options, 'adjustForTimeDifference', False):
405
374
  self.load_time_difference()
375
+ currencies = self.safe_dict(self.options, 'cachedCurrencies', {})
406
376
  currenciesById = self.index_by(currencies, 'id')
407
377
  result = []
408
378
  for i in range(0, len(response)):
@@ -411,11 +381,13 @@ class latoken(Exchange, ImplicitAPI):
411
381
  # the exchange shows them inverted
412
382
  baseId = self.safe_string(market, 'baseCurrency')
413
383
  quoteId = self.safe_string(market, 'quoteCurrency')
414
- baseCurrency = self.safe_value(currenciesById, baseId)
415
- quoteCurrency = self.safe_value(currenciesById, quoteId)
416
- if baseCurrency is not None and quoteCurrency is not None:
417
- base = self.safe_currency_code(self.safe_string(baseCurrency, 'tag'))
418
- quote = self.safe_currency_code(self.safe_string(quoteCurrency, 'tag'))
384
+ baseCurrency = self.safe_dict(currenciesById, baseId)
385
+ quoteCurrency = self.safe_dict(currenciesById, quoteId)
386
+ baseCurrencyInfo = self.safe_dict(baseCurrency, 'info')
387
+ quoteCurrencyInfo = self.safe_dict(quoteCurrency, 'info')
388
+ if baseCurrencyInfo is not None and quoteCurrencyInfo is not None:
389
+ base = self.safe_currency_code(self.safe_string(baseCurrencyInfo, 'tag'))
390
+ quote = self.safe_currency_code(self.safe_string(quoteCurrencyInfo, 'tag'))
419
391
  lowercaseQuote = quote.lower()
420
392
  capitalizedQuote = self.capitalize(lowercaseQuote)
421
393
  status = self.safe_string(market, 'status')
@@ -470,28 +442,13 @@ class latoken(Exchange, ImplicitAPI):
470
442
  })
471
443
  return result
472
444
 
473
- def fetch_currencies_from_cache(self, params={}):
474
- # self method is now redundant
475
- # currencies are now fetched before markets
476
- options = self.safe_value(self.options, 'fetchCurrencies', {})
477
- timestamp = self.safe_integer(options, 'timestamp')
478
- expires = self.safe_integer(options, 'expires', 1000)
479
- now = self.milliseconds()
480
- if (timestamp is None) or ((now - timestamp) > expires):
481
- response = self.publicGetCurrency(params)
482
- self.options['fetchCurrencies'] = self.extend(options, {
483
- 'response': response,
484
- 'timestamp': now,
485
- })
486
- return self.safe_value(self.options['fetchCurrencies'], 'response')
487
-
488
445
  def fetch_currencies(self, params={}) -> Currencies:
489
446
  """
490
447
  fetches all available currencies on an exchange
491
448
  :param dict [params]: extra parameters specific to the exchange API endpoint
492
449
  :returns dict: an associative dictionary of currencies
493
450
  """
494
- response = self.fetch_currencies_from_cache(params)
451
+ response = self.publicGetCurrency(params)
495
452
  #
496
453
  # [
497
454
  # {
@@ -530,27 +487,18 @@ class latoken(Exchange, ImplicitAPI):
530
487
  id = self.safe_string(currency, 'id')
531
488
  tag = self.safe_string(currency, 'tag')
532
489
  code = self.safe_currency_code(tag)
533
- fee = self.safe_number(currency, 'fee')
534
490
  currencyType = self.safe_string(currency, 'type')
535
- type = None
536
- if currencyType == 'CURRENCY_TYPE_ALTERNATIVE':
537
- type = 'other'
538
- else:
539
- # CURRENCY_TYPE_CRYPTO and CURRENCY_TYPE_IEO are all cryptos
540
- type = 'crypto'
541
- status = self.safe_string(currency, 'status')
542
- active = (status == 'CURRENCY_STATUS_ACTIVE')
543
- name = self.safe_string(currency, 'name')
544
- result[code] = {
491
+ isCrypto = (currencyType == 'CURRENCY_TYPE_CRYPTO' or currencyType == 'CURRENCY_TYPE_IEO')
492
+ result[code] = self.safe_currency_structure({
545
493
  'id': id,
546
494
  'code': code,
547
495
  'info': currency,
548
- 'name': name,
549
- 'type': type,
550
- 'active': active,
496
+ 'name': self.safe_string(currency, 'name'),
497
+ 'type': 'crypto' if isCrypto else 'other',
498
+ 'active': self.safe_string(currency, 'status') == 'CURRENCY_STATUS_ACTIVE',
551
499
  'deposit': None,
552
500
  'withdraw': None,
553
- 'fee': fee,
501
+ 'fee': self.safe_number(currency, 'fee'),
554
502
  'precision': self.parse_number(self.parse_precision(self.safe_string(currency, 'decimals'))),
555
503
  'limits': {
556
504
  'amount': {
@@ -563,7 +511,7 @@ class latoken(Exchange, ImplicitAPI):
563
511
  },
564
512
  },
565
513
  'networks': {},
566
- }
514
+ })
567
515
  return result
568
516
 
569
517
  def fetch_balance(self, params={}) -> Balances:
ccxt/lbank.py CHANGED
@@ -137,7 +137,7 @@ class lbank(Exchange, ImplicitAPI):
137
137
  'accuracy': 2.5,
138
138
  'usdToCny': 2.5,
139
139
  'assetConfigs': 2.5,
140
- 'withdrawConfigs': 2.5,
140
+ 'withdrawConfigs': 2.5 * 1.5, # frequently rate-limits, so increase self endpoint RL
141
141
  'timestamp': 2.5,
142
142
  'ticker/24hr': 2.5,
143
143
  'ticker': 2.5,
@@ -674,7 +674,7 @@ class lbank(Exchange, ImplicitAPI):
674
674
  'active': True,
675
675
  'contract': True,
676
676
  'linear': True,
677
- 'inverse': None,
677
+ 'inverse': False,
678
678
  'contractSize': self.safe_number(market, 'volumeMultiple'),
679
679
  'expiry': None,
680
680
  'expiryDatetime': None,
ccxt/okx.py CHANGED
@@ -80,6 +80,7 @@ class okx(Exchange, ImplicitAPI):
80
80
  'createTriggerOrder': True,
81
81
  'editOrder': True,
82
82
  'fetchAccounts': True,
83
+ 'fetchAllGreeks': True,
83
84
  'fetchBalance': True,
84
85
  'fetchBidsAsks': None,
85
86
  'fetchBorrowInterest': True,
@@ -2555,11 +2556,11 @@ class okx(Exchange, ImplicitAPI):
2555
2556
  # it may be incorrect to use total, free and used for swap accounts
2556
2557
  eq = self.safe_string(balance, 'eq')
2557
2558
  availEq = self.safe_string(balance, 'availEq')
2558
- if (eq is None) or (availEq is None):
2559
+ account['total'] = eq
2560
+ if availEq is None:
2559
2561
  account['free'] = self.safe_string(balance, 'availBal')
2560
2562
  account['used'] = self.safe_string(balance, 'frozenBal')
2561
2563
  else:
2562
- account['total'] = eq
2563
2564
  account['free'] = availEq
2564
2565
  result[code] = account
2565
2566
  result['timestamp'] = timestamp
@@ -2957,7 +2958,8 @@ class okx(Exchange, ImplicitAPI):
2957
2958
  stopLossTriggerPrice = self.safe_value_n(stopLoss, ['triggerPrice', 'stopPrice', 'slTriggerPx'])
2958
2959
  if stopLossTriggerPrice is None:
2959
2960
  raise InvalidOrder(self.id + ' createOrder() requires a trigger price in params["stopLoss"]["triggerPrice"], or params["stopLoss"]["stopPrice"], or params["stopLoss"]["slTriggerPx"] for a stop loss order')
2960
- request['slTriggerPx'] = self.price_to_precision(symbol, stopLossTriggerPrice)
2961
+ slTriggerPx = self.price_to_precision(symbol, stopLossTriggerPrice)
2962
+ request['slTriggerPx'] = slTriggerPx
2961
2963
  stopLossLimitPrice = self.safe_value_n(stopLoss, ['price', 'stopLossPrice', 'slOrdPx'])
2962
2964
  stopLossOrderType = self.safe_string(stopLoss, 'type')
2963
2965
  if stopLossOrderType is not None:
@@ -3023,6 +3025,12 @@ class okx(Exchange, ImplicitAPI):
3023
3025
  # tpOrdKind is 'condition' which is the default
3024
3026
  if twoWayCondition:
3025
3027
  request['ordType'] = 'oco'
3028
+ if side == 'sell':
3029
+ request = self.omit(request, 'tgtCcy')
3030
+ if self.safe_string(request, 'tdMode') == 'cash':
3031
+ # for some reason tdMode = cash throws
3032
+ # {"code":"1","data":[{"algoClOrdId":"","algoId":"","clOrdId":"","sCode":"51000","sMsg":"Parameter tdMode error ","tag":""}],"msg":""}
3033
+ request['tdMode'] = marginMode
3026
3034
  if takeProfitPrice is not None:
3027
3035
  request['tpTriggerPx'] = self.price_to_precision(symbol, takeProfitPrice)
3028
3036
  tpOrdPxReq = '-1'
@@ -3613,6 +3621,84 @@ class okx(Exchange, ImplicitAPI):
3613
3621
  # "uTime": "1621910749815"
3614
3622
  # }
3615
3623
  #
3624
+ # watchOrders & fetchClosedOrders
3625
+ #
3626
+ # {
3627
+ # "algoClOrdId": "",
3628
+ # "algoId": "",
3629
+ # "attachAlgoClOrdId": "",
3630
+ # "attachAlgoOrds": [],
3631
+ # "cancelSource": "",
3632
+ # "cancelSourceReason": "", # not present in WS, but present in fetchClosedOrders
3633
+ # "category": "normal",
3634
+ # "ccy": "", # empty in WS, but eg. `USDT` in fetchClosedOrders
3635
+ # "clOrdId": "",
3636
+ # "cTime": "1751705801423",
3637
+ # "feeCcy": "USDT",
3638
+ # "instId": "LINK-USDT-SWAP",
3639
+ # "instType": "SWAP",
3640
+ # "isTpLimit": "false",
3641
+ # "lever": "3",
3642
+ # "linkedAlgoOrd": {"algoId": ""},
3643
+ # "ordId": "2657625147249614848",
3644
+ # "ordType": "limit",
3645
+ # "posSide": "net",
3646
+ # "px": "13.142",
3647
+ # "pxType": "",
3648
+ # "pxUsd": "",
3649
+ # "pxVol": "",
3650
+ # "quickMgnType": "",
3651
+ # "rebate": "0",
3652
+ # "rebateCcy": "USDT",
3653
+ # "reduceOnly": "true",
3654
+ # "side": "sell",
3655
+ # "slOrdPx": "",
3656
+ # "slTriggerPx": "",
3657
+ # "slTriggerPxType": "",
3658
+ # "source": "",
3659
+ # "stpId": "",
3660
+ # "stpMode": "cancel_maker",
3661
+ # "sz": "0.1",
3662
+ # "tag": "",
3663
+ # "tdMode": "isolated",
3664
+ # "tgtCcy": "",
3665
+ # "tpOrdPx": "",
3666
+ # "tpTriggerPx": "",
3667
+ # "tpTriggerPxType": "",
3668
+ # "uTime": "1751705807467",
3669
+ # "reqId": "", # field present only in WS
3670
+ # "msg": "", # field present only in WS
3671
+ # "amendResult": "", # field present only in WS
3672
+ # "amendSource": "", # field present only in WS
3673
+ # "code": "0", # field present only in WS
3674
+ # "fillFwdPx": "", # field present only in WS
3675
+ # "fillMarkVol": "", # field present only in WS
3676
+ # "fillPxUsd": "", # field present only in WS
3677
+ # "fillPxVol": "", # field present only in WS
3678
+ # "lastPx": "13.142", # field present only in WS
3679
+ # "notionalUsd": "1.314515408", # field present only in WS
3680
+ #
3681
+ # #### 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 ###
3682
+ #
3683
+ # "pnl": "-0.0001",
3684
+ # "accFillSz": "0.1",
3685
+ # "avgPx": "13.142",
3686
+ # "state": "filled",
3687
+ # "fee": "-0.00026284",
3688
+ # "fillPx": "13.142",
3689
+ # "tradeId": "293429690",
3690
+ # "fillSz": "0.1",
3691
+ # "fillTime": "1751705807467",
3692
+ # "fillNotionalUsd": "1.314515408", # field present only in WS
3693
+ # "fillPnl": "-0.0001", # field present only in WS
3694
+ # "fillFee": "-0.00026284", # field present only in WS
3695
+ # "fillFeeCcy": "USDT", # field present only in WS
3696
+ # "execType": "M", # field present only in WS
3697
+ # "fillMarkPx": "13.141", # field present only in WS
3698
+ # "fillIdxPx": "13.147" # field present only in WS
3699
+ # }
3700
+ #
3701
+ #
3616
3702
  # Algo Order fetchOpenOrders, fetchCanceledOrders, fetchClosedOrders
3617
3703
  #
3618
3704
  # {
@@ -7547,6 +7633,76 @@ class okx(Exchange, ImplicitAPI):
7547
7633
  return self.parse_greeks(entry, market)
7548
7634
  return None
7549
7635
 
7636
+ def fetch_all_greeks(self, symbols: Strings = None, params={}) -> List[Greeks]:
7637
+ """
7638
+ fetches all option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract
7639
+
7640
+ https://www.okx.com/docs-v5/en/#public-data-rest-api-get-option-market-data
7641
+
7642
+ :param str[] [symbols]: unified symbols of the markets to fetch greeks for, all markets are returned if not assigned
7643
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7644
+ :param str params['uly']: Underlying, either uly or instFamily is required
7645
+ :param str params['instFamily']: Instrument family, either uly or instFamily is required
7646
+ :returns dict: a `greeks structure <https://docs.ccxt.com/#/?id=greeks-structure>`
7647
+ """
7648
+ self.load_markets()
7649
+ request: dict = {}
7650
+ symbols = self.market_symbols(symbols, None, True, True, True)
7651
+ symbolsLength = None
7652
+ if symbols is not None:
7653
+ symbolsLength = len(symbols)
7654
+ if (symbols is None) or (symbolsLength != 1):
7655
+ uly = self.safe_string(params, 'uly')
7656
+ if uly is not None:
7657
+ request['uly'] = uly
7658
+ instFamily = self.safe_string(params, 'instFamily')
7659
+ if instFamily is not None:
7660
+ request['instFamily'] = instFamily
7661
+ if (uly is None) and (instFamily is None):
7662
+ raise BadRequest(self.id + ' fetchAllGreeks() requires either a uly or instFamily parameter')
7663
+ market = None
7664
+ if symbols is not None:
7665
+ if symbolsLength == 1:
7666
+ market = self.market(symbols[0])
7667
+ marketId = market['id']
7668
+ optionParts = marketId.split('-')
7669
+ request['uly'] = market['info']['uly']
7670
+ request['instFamily'] = market['info']['instFamily']
7671
+ request['expTime'] = self.safe_string(optionParts, 2)
7672
+ params = self.omit(params, ['uly', 'instFamily'])
7673
+ response = self.publicGetPublicOptSummary(self.extend(request, params))
7674
+ #
7675
+ # {
7676
+ # "code": "0",
7677
+ # "data": [
7678
+ # {
7679
+ # "askVol": "0",
7680
+ # "bidVol": "0",
7681
+ # "delta": "0.5105464486882039",
7682
+ # "deltaBS": "0.7325502184143025",
7683
+ # "fwdPx": "37675.80158694987186",
7684
+ # "gamma": "-0.13183515090501083",
7685
+ # "gammaBS": "0.000024139685826358558",
7686
+ # "instId": "BTC-USD-240329-32000-C",
7687
+ # "instType": "OPTION",
7688
+ # "lever": "4.504428015946619",
7689
+ # "markVol": "0.5916253554539876",
7690
+ # "realVol": "0",
7691
+ # "theta": "-0.0004202992014012855",
7692
+ # "thetaBS": "-18.52354631567909",
7693
+ # "ts": "1699586421976",
7694
+ # "uly": "BTC-USD",
7695
+ # "vega": "0.0020207455080045846",
7696
+ # "vegaBS": "74.44022302387287",
7697
+ # "volLv": "0.5948549730405797"
7698
+ # },
7699
+ # ],
7700
+ # "msg": ""
7701
+ # }
7702
+ #
7703
+ data = self.safe_list(response, 'data', [])
7704
+ return self.parse_all_greeks(data, symbols)
7705
+
7550
7706
  def parse_greeks(self, greeks: dict, market: Market = None) -> Greeks:
7551
7707
  #
7552
7708
  # {
ccxt/paradex.py CHANGED
@@ -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
+ 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
+ self.load_markets()
2361
+ symbols = self.market_symbols(symbols, None, True, True, True)
2362
+ request: dict = {
2363
+ 'market': 'ALL',
2364
+ }
2365
+ response = 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
  # {
ccxt/phemex.py CHANGED
@@ -2658,14 +2658,14 @@ class phemex(Exchange, ImplicitAPI):
2658
2658
  triggerDirection = None
2659
2659
  triggerDirection, params = self.handle_param_string(params, 'triggerDirection')
2660
2660
  if triggerDirection is None:
2661
- raise ArgumentsRequired(self.id + " createOrder() also requires a 'triggerDirection' parameter with either 'up' or 'down' value")
2661
+ raise ArgumentsRequired(self.id + " createOrder() also requires a 'triggerDirection' parameter with either 'ascending' or 'descending' value")
2662
2662
  # the flow defined per https://phemex-docs.github.io/#more-order-type-examples
2663
- if triggerDirection == 'up':
2663
+ if triggerDirection == 'ascending' or triggerDirection == 'up':
2664
2664
  if side == 'sell':
2665
2665
  request['ordType'] = 'MarketIfTouched' if (type == 'Market') else 'LimitIfTouched'
2666
2666
  elif side == 'buy':
2667
2667
  request['ordType'] = 'Stop' if (type == 'Market') else 'StopLimit'
2668
- elif triggerDirection == 'down':
2668
+ elif triggerDirection == 'descending' or triggerDirection == 'down':
2669
2669
  if side == 'sell':
2670
2670
  request['ordType'] = 'Stop' if (type == 'Market') else 'StopLimit'
2671
2671
  elif side == 'buy':
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.92'
7
+ __version__ = '4.4.94'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
ccxt/pro/bitstamp.py CHANGED
@@ -10,6 +10,7 @@ from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
11
  from ccxt.base.errors import AuthenticationError
12
12
  from ccxt.base.errors import ArgumentsRequired
13
+ from ccxt.base.precise import Precise
13
14
 
14
15
 
15
16
  class bitstamp(ccxt.async_support.bitstamp):
@@ -296,6 +297,7 @@ class bitstamp(ccxt.async_support.bitstamp):
296
297
  # "price_str":"1000.00"
297
298
  # },
298
299
  # "channel":"private-my_orders_ltcusd-4848701",
300
+ # "event": "order_deleted" # field only present for cancelOrder
299
301
  # }
300
302
  #
301
303
  channel = self.safe_string(message, 'channel')
@@ -307,29 +309,58 @@ class bitstamp(ccxt.async_support.bitstamp):
307
309
  subscription = self.safe_value(client.subscriptions, channel)
308
310
  symbol = self.safe_string(subscription, 'symbol')
309
311
  market = self.market(symbol)
312
+ order['event'] = self.safe_string(message, 'event')
310
313
  parsed = self.parse_ws_order(order, market)
311
314
  stored.append(parsed)
312
315
  client.resolve(self.orders, channel)
313
316
 
314
317
  def parse_ws_order(self, order, market=None):
315
318
  #
316
- # {
317
- # "id":"1463471322288128",
318
- # "id_str":"1463471322288128",
319
- # "order_type":1,
320
- # "datetime":"1646127778",
321
- # "microtimestamp":"1646127777950000",
322
- # "amount":0.05,
323
- # "amount_str":"0.05000000",
324
- # "price":1000,
325
- # "price_str":"1000.00"
319
+ # {
320
+ # "id": "1894876776091648",
321
+ # "id_str": "1894876776091648",
322
+ # "order_type": 0,
323
+ # "order_subtype": 0,
324
+ # "datetime": "1751451375",
325
+ # "microtimestamp": "1751451375070000",
326
+ # "amount": 1.1,
327
+ # "amount_str": "1.10000000",
328
+ # "amount_traded": "0",
329
+ # "amount_at_create": "1.10000000",
330
+ # "price": 10.23,
331
+ # "price_str": "10.23",
332
+ # "is_liquidation": False,
333
+ # "trade_account_id": 0
326
334
  # }
327
335
  #
328
336
  id = self.safe_string(order, 'id_str')
329
- orderType = self.safe_string_lower(order, 'order_type')
337
+ orderTypeRaw = self.safe_string_lower(order, 'order_type')
338
+ side = 'sell' if (orderTypeRaw == '1') else 'buy'
339
+ orderSubTypeRaw = self.safe_string_lower(order, 'order_subtype') # https://www.bitstamp.net/websocket/v2/#:~:text=order_subtype
340
+ orderType: Str = None
341
+ timeInForce: Str = None
342
+ if orderSubTypeRaw == '0':
343
+ orderType = 'limit'
344
+ elif orderSubTypeRaw == '2':
345
+ orderType = 'market'
346
+ elif orderSubTypeRaw == '4':
347
+ orderType = 'limit'
348
+ timeInForce = 'IOC'
349
+ elif orderSubTypeRaw == '6':
350
+ orderType = 'limit'
351
+ timeInForce = 'FOK'
352
+ elif orderSubTypeRaw == '8':
353
+ orderType = 'limit'
354
+ timeInForce = 'GTD'
330
355
  price = self.safe_string(order, 'price_str')
331
356
  amount = self.safe_string(order, 'amount_str')
332
- side = 'sell' if (orderType == '1') else 'buy'
357
+ filled = self.safe_string(order, 'amount_traded')
358
+ event = self.safe_string(order, 'event')
359
+ status = None
360
+ if Precise.string_eq(filled, amount):
361
+ status = 'closed'
362
+ elif event == 'order_deleted':
363
+ status = 'canceled'
333
364
  timestamp = self.safe_timestamp(order, 'datetime')
334
365
  market = self.safe_market(None, market)
335
366
  symbol = market['symbol']
@@ -341,8 +372,8 @@ class bitstamp(ccxt.async_support.bitstamp):
341
372
  'timestamp': timestamp,
342
373
  'datetime': self.iso8601(timestamp),
343
374
  'lastTradeTimestamp': None,
344
- 'type': None,
345
- 'timeInForce': None,
375
+ 'type': orderType,
376
+ 'timeInForce': timeInForce,
346
377
  'postOnly': None,
347
378
  'side': side,
348
379
  'price': price,
@@ -351,9 +382,9 @@ class bitstamp(ccxt.async_support.bitstamp):
351
382
  'amount': amount,
352
383
  'cost': None,
353
384
  'average': None,
354
- 'filled': None,
385
+ 'filled': filled,
355
386
  'remaining': None,
356
- 'status': None,
387
+ 'status': status,
357
388
  'fee': None,
358
389
  'trades': None,
359
390
  }, market)
@@ -417,6 +448,7 @@ class bitstamp(ccxt.async_support.bitstamp):
417
448
  # "price_str":"1000.00"
418
449
  # },
419
450
  # "channel":"private-my_orders_ltcusd-4848701",
451
+ # "event": "order_deleted" # field only present for cancelOrder
420
452
  # }
421
453
  #
422
454
  channel = self.safe_string(message, 'channel')