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/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,
@@ -3613,6 +3614,84 @@ class okx(Exchange, ImplicitAPI):
3613
3614
  # "uTime": "1621910749815"
3614
3615
  # }
3615
3616
  #
3617
+ # watchOrders & fetchClosedOrders
3618
+ #
3619
+ # {
3620
+ # "algoClOrdId": "",
3621
+ # "algoId": "",
3622
+ # "attachAlgoClOrdId": "",
3623
+ # "attachAlgoOrds": [],
3624
+ # "cancelSource": "",
3625
+ # "cancelSourceReason": "", # not present in WS, but present in fetchClosedOrders
3626
+ # "category": "normal",
3627
+ # "ccy": "", # empty in WS, but eg. `USDT` in fetchClosedOrders
3628
+ # "clOrdId": "",
3629
+ # "cTime": "1751705801423",
3630
+ # "feeCcy": "USDT",
3631
+ # "instId": "LINK-USDT-SWAP",
3632
+ # "instType": "SWAP",
3633
+ # "isTpLimit": "false",
3634
+ # "lever": "3",
3635
+ # "linkedAlgoOrd": {"algoId": ""},
3636
+ # "ordId": "2657625147249614848",
3637
+ # "ordType": "limit",
3638
+ # "posSide": "net",
3639
+ # "px": "13.142",
3640
+ # "pxType": "",
3641
+ # "pxUsd": "",
3642
+ # "pxVol": "",
3643
+ # "quickMgnType": "",
3644
+ # "rebate": "0",
3645
+ # "rebateCcy": "USDT",
3646
+ # "reduceOnly": "true",
3647
+ # "side": "sell",
3648
+ # "slOrdPx": "",
3649
+ # "slTriggerPx": "",
3650
+ # "slTriggerPxType": "",
3651
+ # "source": "",
3652
+ # "stpId": "",
3653
+ # "stpMode": "cancel_maker",
3654
+ # "sz": "0.1",
3655
+ # "tag": "",
3656
+ # "tdMode": "isolated",
3657
+ # "tgtCcy": "",
3658
+ # "tpOrdPx": "",
3659
+ # "tpTriggerPx": "",
3660
+ # "tpTriggerPxType": "",
3661
+ # "uTime": "1751705807467",
3662
+ # "reqId": "", # field present only in WS
3663
+ # "msg": "", # field present only in WS
3664
+ # "amendResult": "", # field present only in WS
3665
+ # "amendSource": "", # field present only in WS
3666
+ # "code": "0", # field present only in WS
3667
+ # "fillFwdPx": "", # field present only in WS
3668
+ # "fillMarkVol": "", # field present only in WS
3669
+ # "fillPxUsd": "", # field present only in WS
3670
+ # "fillPxVol": "", # field present only in WS
3671
+ # "lastPx": "13.142", # field present only in WS
3672
+ # "notionalUsd": "1.314515408", # field present only in WS
3673
+ #
3674
+ # #### 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 ###
3675
+ #
3676
+ # "pnl": "-0.0001",
3677
+ # "accFillSz": "0.1",
3678
+ # "avgPx": "13.142",
3679
+ # "state": "filled",
3680
+ # "fee": "-0.00026284",
3681
+ # "fillPx": "13.142",
3682
+ # "tradeId": "293429690",
3683
+ # "fillSz": "0.1",
3684
+ # "fillTime": "1751705807467",
3685
+ # "fillNotionalUsd": "1.314515408", # field present only in WS
3686
+ # "fillPnl": "-0.0001", # field present only in WS
3687
+ # "fillFee": "-0.00026284", # field present only in WS
3688
+ # "fillFeeCcy": "USDT", # field present only in WS
3689
+ # "execType": "M", # field present only in WS
3690
+ # "fillMarkPx": "13.141", # field present only in WS
3691
+ # "fillIdxPx": "13.147" # field present only in WS
3692
+ # }
3693
+ #
3694
+ #
3616
3695
  # Algo Order fetchOpenOrders, fetchCanceledOrders, fetchClosedOrders
3617
3696
  #
3618
3697
  # {
@@ -7547,6 +7626,76 @@ class okx(Exchange, ImplicitAPI):
7547
7626
  return self.parse_greeks(entry, market)
7548
7627
  return None
7549
7628
 
7629
+ def fetch_all_greeks(self, symbols: Strings = None, params={}) -> List[Greeks]:
7630
+ """
7631
+ fetches all option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract
7632
+
7633
+ https://www.okx.com/docs-v5/en/#public-data-rest-api-get-option-market-data
7634
+
7635
+ :param str[] [symbols]: unified symbols of the markets to fetch greeks for, all markets are returned if not assigned
7636
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7637
+ :param str params['uly']: Underlying, either uly or instFamily is required
7638
+ :param str params['instFamily']: Instrument family, either uly or instFamily is required
7639
+ :returns dict: a `greeks structure <https://docs.ccxt.com/#/?id=greeks-structure>`
7640
+ """
7641
+ self.load_markets()
7642
+ request: dict = {}
7643
+ symbols = self.market_symbols(symbols, None, True, True, True)
7644
+ symbolsLength = None
7645
+ if symbols is not None:
7646
+ symbolsLength = len(symbols)
7647
+ if (symbols is None) or (symbolsLength != 1):
7648
+ uly = self.safe_string(params, 'uly')
7649
+ if uly is not None:
7650
+ request['uly'] = uly
7651
+ instFamily = self.safe_string(params, 'instFamily')
7652
+ if instFamily is not None:
7653
+ request['instFamily'] = instFamily
7654
+ if (uly is None) and (instFamily is None):
7655
+ raise BadRequest(self.id + ' fetchAllGreeks() requires either a uly or instFamily parameter')
7656
+ market = None
7657
+ if symbols is not None:
7658
+ if symbolsLength == 1:
7659
+ market = self.market(symbols[0])
7660
+ marketId = market['id']
7661
+ optionParts = marketId.split('-')
7662
+ request['uly'] = market['info']['uly']
7663
+ request['instFamily'] = market['info']['instFamily']
7664
+ request['expTime'] = self.safe_string(optionParts, 2)
7665
+ params = self.omit(params, ['uly', 'instFamily'])
7666
+ response = self.publicGetPublicOptSummary(self.extend(request, params))
7667
+ #
7668
+ # {
7669
+ # "code": "0",
7670
+ # "data": [
7671
+ # {
7672
+ # "askVol": "0",
7673
+ # "bidVol": "0",
7674
+ # "delta": "0.5105464486882039",
7675
+ # "deltaBS": "0.7325502184143025",
7676
+ # "fwdPx": "37675.80158694987186",
7677
+ # "gamma": "-0.13183515090501083",
7678
+ # "gammaBS": "0.000024139685826358558",
7679
+ # "instId": "BTC-USD-240329-32000-C",
7680
+ # "instType": "OPTION",
7681
+ # "lever": "4.504428015946619",
7682
+ # "markVol": "0.5916253554539876",
7683
+ # "realVol": "0",
7684
+ # "theta": "-0.0004202992014012855",
7685
+ # "thetaBS": "-18.52354631567909",
7686
+ # "ts": "1699586421976",
7687
+ # "uly": "BTC-USD",
7688
+ # "vega": "0.0020207455080045846",
7689
+ # "vegaBS": "74.44022302387287",
7690
+ # "volLv": "0.5948549730405797"
7691
+ # },
7692
+ # ],
7693
+ # "msg": ""
7694
+ # }
7695
+ #
7696
+ data = self.safe_list(response, 'data', [])
7697
+ return self.parse_all_greeks(data, symbols)
7698
+
7550
7699
  def parse_greeks(self, greeks: dict, market: Market = None) -> Greeks:
7551
7700
  #
7552
7701
  # {
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.93'
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')
ccxt/pro/bybit.py CHANGED
@@ -2350,6 +2350,7 @@ class bybit(ccxt.async_support.bybit):
2350
2350
  for j in range(0, len(messageHashes)):
2351
2351
  unsubHash = messageHashes[j]
2352
2352
  subHash = subMessageHashes[j]
2353
- self.clean_unsubscription(client, subHash, unsubHash)
2353
+ usePrefix = (subHash == 'orders') or (subHash == 'myTrades')
2354
+ self.clean_unsubscription(client, subHash, unsubHash, usePrefix)
2354
2355
  self.clean_cache(subscription)
2355
2356
  return message
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ccxt
3
- Version: 4.4.92
3
+ Version: 4.4.93
4
4
  Summary: A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges
5
5
  Home-page: https://ccxt.com
6
6
  Author: Igor Kroitor
@@ -269,13 +269,13 @@ console.log(version, Object.keys(exchanges));
269
269
 
270
270
  All-in-one browser bundle (dependencies included), served from a CDN of your choice:
271
271
 
272
- * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.4.92/dist/ccxt.browser.min.js
273
- * unpkg: https://unpkg.com/ccxt@4.4.92/dist/ccxt.browser.min.js
272
+ * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.4.93/dist/ccxt.browser.min.js
273
+ * unpkg: https://unpkg.com/ccxt@4.4.93/dist/ccxt.browser.min.js
274
274
 
275
275
  CDNs are not updated in real-time and may have delays. Defaulting to the most recent version without specifying the version number is not recommended. Please, keep in mind that we are not responsible for the correct operation of those CDN servers.
276
276
 
277
277
  ```HTML
278
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.4.92/dist/ccxt.browser.min.js"></script>
278
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.4.93/dist/ccxt.browser.min.js"></script>
279
279
  ```
280
280
 
281
281
  Creates a global `ccxt` object: