ccxt 4.3.94__py2.py3-none-any.whl → 4.3.96__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 (53) hide show
  1. ccxt/__init__.py +1 -5
  2. ccxt/abstract/okx.py +2 -0
  3. ccxt/ascendex.py +8 -6
  4. ccxt/async_support/__init__.py +1 -5
  5. ccxt/async_support/ascendex.py +9 -6
  6. ccxt/async_support/base/exchange.py +1 -4
  7. ccxt/async_support/bingx.py +1 -0
  8. ccxt/async_support/bitfinex.py +4 -2
  9. ccxt/async_support/bitfinex2.py +7 -5
  10. ccxt/async_support/blofin.py +0 -1
  11. ccxt/async_support/btcturk.py +3 -3
  12. ccxt/async_support/bybit.py +7 -2
  13. ccxt/async_support/gate.py +3 -2
  14. ccxt/async_support/gemini.py +3 -2
  15. ccxt/async_support/hyperliquid.py +311 -40
  16. ccxt/async_support/independentreserve.py +5 -3
  17. ccxt/async_support/indodax.py +2 -0
  18. ccxt/async_support/kucoin.py +12 -12
  19. ccxt/async_support/mexc.py +78 -154
  20. ccxt/async_support/okx.py +2 -1
  21. ccxt/async_support/p2b.py +0 -1
  22. ccxt/async_support/tradeogre.py +0 -1
  23. ccxt/base/exchange.py +4 -8
  24. ccxt/bingx.py +1 -0
  25. ccxt/bitfinex.py +3 -2
  26. ccxt/bitfinex2.py +6 -5
  27. ccxt/blofin.py +0 -1
  28. ccxt/btcturk.py +3 -3
  29. ccxt/bybit.py +7 -2
  30. ccxt/gate.py +3 -2
  31. ccxt/gemini.py +3 -2
  32. ccxt/hyperliquid.py +311 -40
  33. ccxt/independentreserve.py +4 -3
  34. ccxt/indodax.py +2 -0
  35. ccxt/kucoin.py +2 -2
  36. ccxt/mexc.py +78 -154
  37. ccxt/okx.py +2 -1
  38. ccxt/p2b.py +0 -1
  39. ccxt/pro/__init__.py +1 -1
  40. ccxt/pro/binance.py +90 -2
  41. ccxt/pro/bybit.py +58 -4
  42. ccxt/pro/cryptocom.py +195 -0
  43. ccxt/pro/okx.py +238 -31
  44. ccxt/test/tests_async.py +3 -0
  45. ccxt/test/tests_sync.py +3 -0
  46. ccxt/tradeogre.py +0 -1
  47. {ccxt-4.3.94.dist-info → ccxt-4.3.96.dist-info}/METADATA +5 -5
  48. {ccxt-4.3.94.dist-info → ccxt-4.3.96.dist-info}/RECORD +51 -53
  49. ccxt/abstract/bitbay.py +0 -53
  50. ccxt/abstract/hitbtc3.py +0 -115
  51. {ccxt-4.3.94.dist-info → ccxt-4.3.96.dist-info}/LICENSE.txt +0 -0
  52. {ccxt-4.3.94.dist-info → ccxt-4.3.96.dist-info}/WHEEL +0 -0
  53. {ccxt-4.3.94.dist-info → ccxt-4.3.96.dist-info}/top_level.txt +0 -0
ccxt/mexc.py CHANGED
@@ -462,164 +462,82 @@ class mexc(Exchange, ImplicitAPI):
462
462
  'LTC': 'LTC',
463
463
  },
464
464
  'networks': {
465
- 'ABBC': 'ABBC',
465
+ 'TRC20': 'TRX',
466
+ 'TON': 'TONCOIN',
467
+ 'AVAXC': 'AVAX_CCHAIN',
468
+ 'ERC20': 'ETH',
466
469
  'ACA': 'ACALA',
467
- 'ADA': 'Cardano(ADA)',
468
- 'AE': 'AE',
469
- 'ALGO': 'Algorand(ALGO)',
470
- 'ALPH': 'Alephium(ALPH)',
471
- 'AME': 'AME',
472
- 'AOK': 'AOK',
473
- 'APT': 'APTOS(APT)',
474
- 'AR': 'AR',
475
- 'ARB': 'Arbitrum One(ARB)',
476
- 'ARBNOVA': 'ARBNOVA',
477
- 'ARBONE': 'ArbitrumOne(ARB)',
478
- 'ARK': 'ARK',
470
+ # 'ADA': 'Cardano(ADA)',
471
+ # 'AE': 'AE',
472
+ # 'ALGO': 'Algorand(ALGO)',
473
+ # 'ALPH': 'Alephium(ALPH)',
474
+ # 'ARB': 'Arbitrum One(ARB)',
475
+ # 'ARBONE': 'ArbitrumOne(ARB)',
479
476
  'ASTR': 'ASTAR', # ASTAREVM is different
480
- 'ATOM': 'Cosmos(ATOM)',
481
- 'AVAXC': 'Avalanche C Chain(AVAX CCHAIN)',
482
- 'AVAXX': 'Avalanche X Chain(AVAX XCHAIN)',
483
- 'AZERO': 'Aleph Zero(AZERO)',
484
- 'BCH': 'Bitcoin Cash(BCH)',
485
- 'BDX': 'BDX',
486
- 'BEAM': 'BEAM',
487
- 'BEP2': 'BNB Beacon Chain(BEP2)',
488
- 'BEP20': 'BNB Smart Chain(BEP20)',
489
- 'BITCI': 'BITCI',
490
- 'BNC': 'BNC',
491
- 'BNCDOT': 'BNCPOLKA',
492
- 'BOBA': 'BOBA',
493
- 'BSC': 'BEP20(BSC)',
494
- 'BSV': 'Bitcoin SV(BSV)',
495
- 'BTC': 'Bitcoin(BTC)',
477
+ # 'ATOM': 'Cosmos(ATOM)',
478
+ # 'AVAXC': 'Avalanche C Chain(AVAX CCHAIN)',
479
+ # 'AVAXX': 'Avalanche X Chain(AVAX XCHAIN)',
480
+ # 'AZERO': 'Aleph Zero(AZERO)',
481
+ # 'BCH': 'Bitcoin Cash(BCH)',
482
+ # 'BNCDOT': 'BNCPOLKA',
483
+ # 'BSV': 'Bitcoin SV(BSV)',
484
+ # 'BTC': 'Bitcoin(BTC)',
496
485
  'BTM': 'BTM2',
497
- 'CELO': 'CELO',
498
- 'CFX': 'CFX',
499
- 'CHZ': 'Chiliz Legacy Chain(CHZ)',
500
- 'CHZ2': 'Chiliz Chain(CHZ2)',
501
- 'CKB': 'CKB',
502
- 'CLORE': 'Clore.ai(CLORE)',
486
+ # 'CHZ': 'Chiliz Legacy Chain(CHZ)',
487
+ # 'CHZ2': 'Chiliz Chain(CHZ2)',
488
+ # 'CLORE': 'Clore.ai(CLORE)',
503
489
  'CRC20': 'CRONOS',
504
- 'CSPR': 'CSPR',
505
- 'DASH': 'DASH',
506
- 'DC': 'Dogechain(DC)',
507
- 'DCR': 'DCR',
508
- 'DNX': 'Dynex(DNX)',
509
- 'DOGE': 'Dogecoin(DOGE)',
510
- 'DOT': 'Polkadot(DOT)',
511
- 'DYM': 'Dymension(DYM)',
512
- 'EDG': 'EDG',
513
- 'EGLD': 'EGLD',
514
- 'EOS': 'EOS',
515
- 'ERC20': 'Ethereum(ERC20)',
516
- 'ETC': 'Ethereum Classic(ETC)',
490
+ # 'DC': 'Dogechain(DC)',
491
+ # 'DNX': 'Dynex(DNX)',
492
+ # 'DOGE': 'Dogecoin(DOGE)',
493
+ # 'DOT': 'Polkadot(DOT)',
494
+ # 'DYM': 'Dymension(DYM)',
517
495
  'ETHF': 'ETF',
518
- 'ETHW': 'ETHW',
519
- 'EVER': 'EVER',
520
- 'FET': 'FET',
521
- 'FIL': 'FIL',
522
- 'FIO': 'FIO',
523
- 'FLOW': 'FLOW',
524
- 'FSN': 'FSN',
525
- 'FTM': 'Fantom(FTM)',
526
- 'FUSE': 'FUSE',
527
- 'GLMR': 'GLMR',
528
- 'GRIN': 'GRIN',
529
- 'HBAR': 'Hedera(HBAR)',
530
- 'HIVE': 'HIVE',
531
496
  'HRC20': 'HECO',
532
- 'HYDRA': 'HYDRA',
533
- 'ICP': 'Internet Computer(ICP)',
534
- 'INDEX': 'Index Chain',
535
- 'IOST': 'IOST',
536
- 'IOTA': 'IOTA',
537
- 'IOTX': 'IOTX',
538
- 'IRIS': 'IRIS',
539
- 'KAR': 'KAR',
540
- 'KAS': 'Kaspa(KAS)',
541
- 'KAVA': 'KAVA',
542
- 'KDA': 'KDA',
543
- 'KILT': 'KILT',
544
- 'KLAY': 'Klaytn(KLAY)',
545
- 'KMA': 'KMA',
546
- 'KSM': 'KSM',
547
- 'LAT': 'LAT',
548
- 'LAVA': 'Elysium(LAVA)',
549
- 'LTC': 'Litecoin(LTC)',
550
- 'LUNA': 'Terra(LUNA)',
551
- 'MASS': 'MASS',
552
- 'MATIC': 'Polygon(MATIC)',
553
- 'MCOIN': 'Mcoin Network',
554
- 'METIS': 'METIS',
555
- 'MINA': 'MINA',
556
- 'MNT': 'Mantle(MNT)',
557
- 'MOVR': 'MOVR',
558
- 'MTRG': 'Meter(MTRG)',
559
- 'NAS': 'NAS',
560
- 'NEAR': 'NEAR Protocol(NEAR)',
561
- 'NEBL': 'NEBL',
562
- 'NEM': 'NEM',
563
- 'NEO': 'NEO',
564
- 'NEO3': 'NEO3',
565
- 'NEOXA': 'Neoxa Network',
566
- 'NULS': 'NULS',
497
+ # 'KLAY': 'Klaytn(KLAY)',
567
498
  'OASIS': 'ROSE',
568
- 'OASYS': 'OASYS',
569
499
  'OKC': 'OKT',
570
- 'OMN': 'Omega Network(OMN)',
571
- 'OMNI': 'OMNI',
572
- 'ONE': 'ONE',
573
- 'ONT': 'ONT',
574
- 'OPTIMISM': 'Optimism(OP)',
575
- 'OSMO': 'OSMO',
576
- 'PLCU': 'PLCU',
577
- 'POKT': 'POKT',
578
- 'QKC': 'QKC',
579
- 'QTUM': 'QTUM',
580
- 'RAP20': 'RAP20' + ' ' + '(Rangers Mainnet)',
581
- 'REI': 'REI',
582
500
  'RSK': 'RBTC',
583
- 'RVN': 'Ravencoin(RVN)',
584
- 'SATOX': 'Satoxcoin(SATOX)',
585
- 'SC': 'SC',
586
- 'SCRT': 'SCRT',
587
- 'SDN': 'SDN',
588
- 'SGB': 'SGB',
589
- 'SOL': 'Solana(SOL)',
590
- 'STAR': 'STAR',
591
- 'STARK': 'Starknet(STARK)',
592
- 'STEEM': 'STEEM',
593
- 'SYS': 'SYS',
594
- 'TAO': 'Bittensor(TAO)',
595
- 'TIA': 'Celestia(TIA)',
596
- 'TOMO': 'TOMO',
597
- 'TON': 'Toncoin(TON)',
598
- 'TRC10': 'TRC10',
599
- 'TRC20': 'Tron(TRC20)',
600
- 'UGAS': 'UGAS(Ultrain)',
601
- 'VET': 'VeChain(VET)',
602
- 'VEX': 'Vexanium(VEX)',
603
- 'VSYS': 'VSYS',
604
- 'WAVES': 'WAVES',
605
- 'WAX': 'WAX',
606
- 'WEMIX': 'WEMIX',
607
- 'XCH': 'Chia(XCH)',
608
- 'XDC': 'XDC',
609
- 'XEC': 'XEC',
610
- 'XLM': 'Stellar(XLM)',
611
- 'XMR': 'Monero(XMR)',
612
- 'XNA': 'Neurai(XNA)',
613
- 'XPR': 'XPR Network',
614
- 'XRD': 'XRD',
615
- 'XRP': 'Ripple(XRP)',
616
- 'XTZ': 'XTZ',
617
- 'XVG': 'XVG',
618
- 'XYM': 'XYM',
619
- 'ZEC': 'ZEC',
620
- 'ZEN': 'ZEN',
621
- 'ZIL': 'Zilliqa(ZIL)',
622
- 'ZTG': 'ZTG',
501
+ # 'RVN': 'Ravencoin(RVN)',
502
+ # 'SATOX': 'Satoxcoin(SATOX)',
503
+ # 'SC': 'SC',
504
+ # 'SCRT': 'SCRT',
505
+ # 'SDN': 'SDN',
506
+ # 'SGB': 'SGB',
507
+ # 'SOL': 'Solana(SOL)',
508
+ # 'STAR': 'STAR',
509
+ # 'STARK': 'Starknet(STARK)',
510
+ # 'STEEM': 'STEEM',
511
+ # 'SYS': 'SYS',
512
+ # 'TAO': 'Bittensor(TAO)',
513
+ # 'TIA': 'Celestia(TIA)',
514
+ # 'TOMO': 'TOMO',
515
+ # 'TON': 'Toncoin(TON)',
516
+ # 'TRC10': 'TRC10',
517
+ # 'TRC20': 'Tron(TRC20)',
518
+ # 'UGAS': 'UGAS(Ultrain)',
519
+ # 'VET': 'VeChain(VET)',
520
+ # 'VEX': 'Vexanium(VEX)',
521
+ # 'VSYS': 'VSYS',
522
+ # 'WAVES': 'WAVES',
523
+ # 'WAX': 'WAX',
524
+ # 'WEMIX': 'WEMIX',
525
+ # 'XCH': 'Chia(XCH)',
526
+ # 'XDC': 'XDC',
527
+ # 'XEC': 'XEC',
528
+ # 'XLM': 'Stellar(XLM)',
529
+ # 'XMR': 'Monero(XMR)',
530
+ # 'XNA': 'Neurai(XNA)',
531
+ # 'XPR': 'XPR Network',
532
+ # 'XRD': 'XRD',
533
+ # 'XRP': 'Ripple(XRP)',
534
+ # 'XTZ': 'XTZ',
535
+ # 'XVG': 'XVG',
536
+ # 'XYM': 'XYM',
537
+ # 'ZEC': 'ZEC',
538
+ # 'ZEN': 'ZEN',
539
+ # 'ZIL': 'Zilliqa(ZIL)',
540
+ # 'ZTG': 'ZTG',
623
541
  # todo: uncomment below after concensus
624
542
  # 'ALAYA': 'ATP',
625
543
  # 'ANDUSCHAIN': 'DEB',
@@ -891,6 +809,8 @@ class mexc(Exchange, ImplicitAPI):
891
809
  def fetch_status(self, params={}):
892
810
  """
893
811
  the latest known information on the availability of the exchange API
812
+ :see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#test-connectivity
813
+ :see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#get-the-server-time
894
814
  :param dict [params]: extra parameters specific to the exchange API endpoint
895
815
  :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
896
816
  """
@@ -924,6 +844,8 @@ class mexc(Exchange, ImplicitAPI):
924
844
  def fetch_time(self, params={}):
925
845
  """
926
846
  fetches the current integer timestamp in milliseconds from the exchange server
847
+ :see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#check-server-time
848
+ :see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#get-the-server-time
927
849
  :param dict [params]: extra parameters specific to the exchange API endpoint
928
850
  :returns int: the current integer timestamp in milliseconds from the exchange server
929
851
  """
@@ -1011,7 +933,7 @@ class mexc(Exchange, ImplicitAPI):
1011
933
  chains = self.safe_value(currency, 'networkList', [])
1012
934
  for j in range(0, len(chains)):
1013
935
  chain = chains[j]
1014
- networkId = self.safe_string_2(chain, 'network', 'netWork')
936
+ networkId = self.safe_string_2(chain, 'netWork', 'network')
1015
937
  network = self.network_id_to_code(networkId)
1016
938
  isDepositEnabled = self.safe_bool(chain, 'depositEnable', False)
1017
939
  isWithdrawEnabled = self.safe_bool(chain, 'withdrawEnable', False)
@@ -1080,6 +1002,8 @@ class mexc(Exchange, ImplicitAPI):
1080
1002
  def fetch_markets(self, params={}) -> List[Market]:
1081
1003
  """
1082
1004
  retrieves data on all markets for mexc
1005
+ :see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#exchange-information
1006
+ :see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#get-the-contract-information
1083
1007
  :param dict [params]: extra parameters specific to the exchange API endpoint
1084
1008
  :returns dict[]: an array of objects representing market data
1085
1009
  """
@@ -4120,7 +4044,7 @@ class mexc(Exchange, ImplicitAPI):
4120
4044
  #
4121
4045
  address = self.safe_string(depositAddress, 'address')
4122
4046
  currencyId = self.safe_string(depositAddress, 'coin')
4123
- networkId = self.safe_string(depositAddress, 'network')
4047
+ networkId = self.safe_string(depositAddress, 'netWork')
4124
4048
  self.check_address(address)
4125
4049
  return {
4126
4050
  'currency': self.safe_currency_code(currencyId, currency),
@@ -4844,14 +4768,14 @@ class mexc(Exchange, ImplicitAPI):
4844
4768
  :param dict [params]: extra parameters specific to the exchange API endpoint
4845
4769
  :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
4846
4770
  """
4771
+ self.load_markets()
4772
+ currency = self.currency(code)
4847
4773
  tag, params = self.handle_withdraw_tag_and_params(tag, params)
4848
4774
  networks = self.safe_dict(self.options, 'networks', {})
4849
4775
  network = self.safe_string_2(params, 'network', 'netWork') # self line allows the user to specify either ERC20 or ETH
4850
4776
  network = self.safe_string(networks, network, network) # handle ETH > ERC-20 alias
4851
- network = self.network_id_to_code(network)
4777
+ network = self.network_code_to_id(network, currency['code'])
4852
4778
  self.check_address(address)
4853
- self.load_markets()
4854
- currency = self.currency(code)
4855
4779
  request: dict = {
4856
4780
  'coin': currency['id'],
4857
4781
  'address': address,
ccxt/okx.py CHANGED
@@ -133,7 +133,6 @@ class okx(Exchange, ImplicitAPI):
133
133
  'fetchOrderBooks': False,
134
134
  'fetchOrders': False,
135
135
  'fetchOrderTrades': True,
136
- 'fetchPermissions': None,
137
136
  'fetchPosition': True,
138
137
  'fetchPositionHistory': 'emulated',
139
138
  'fetchPositions': True,
@@ -348,6 +347,7 @@ class okx(Exchange, ImplicitAPI):
348
347
  'account/account-position-risk': 2,
349
348
  'account/bills': 5 / 3,
350
349
  'account/bills-archive': 5 / 3,
350
+ 'account/bills-history-archive': 2,
351
351
  'account/config': 4,
352
352
  'account/max-size': 1,
353
353
  'account/max-avail-size': 1,
@@ -502,6 +502,7 @@ class okx(Exchange, ImplicitAPI):
502
502
  'account/fixed-loan/amend-borrowing-order': 5,
503
503
  'account/fixed-loan/manual-reborrow': 5,
504
504
  'account/fixed-loan/repay-borrowing-order': 5,
505
+ 'account/bills-history-archive': 72000, # 12 req/day
505
506
  # subaccount
506
507
  'users/subaccount/modify-apikey': 10,
507
508
  'asset/subaccount/transfer': 10,
ccxt/p2b.py CHANGED
@@ -83,7 +83,6 @@ class p2b(Exchange, ImplicitAPI):
83
83
  'fetchOrderBooks': False,
84
84
  'fetchOrders': True,
85
85
  'fetchOrderTrades': True,
86
- 'fetchPermissions': False,
87
86
  'fetchPosition': False,
88
87
  'fetchPositionHistory': False,
89
88
  'fetchPositionMode': False,
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.94'
7
+ __version__ = '4.3.96'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
ccxt/pro/binance.py CHANGED
@@ -959,13 +959,21 @@ class binance(ccxt.async_support.binance):
959
959
  error = UnsubscribeError(self.id + ' ' + subHash)
960
960
  client.reject(error, subHash)
961
961
  client.resolve(True, unsubHash)
962
- self.clean_cache(subscription)
962
+ self.clean_cache(subscription)
963
963
 
964
964
  def clean_cache(self, subscription: dict):
965
965
  topic = self.safe_string(subscription, 'topic')
966
966
  symbols = self.safe_list(subscription, 'symbols', [])
967
967
  symbolsLength = len(symbols)
968
- if symbolsLength > 0:
968
+ if topic == 'ohlcv':
969
+ symbolsAndTimeFrames = self.safe_list(subscription, 'symbolsAndTimeframes', [])
970
+ for i in range(0, len(symbolsAndTimeFrames)):
971
+ symbolAndTimeFrame = symbolsAndTimeFrames[i]
972
+ symbol = self.safe_string(symbolAndTimeFrame, 0)
973
+ timeframe = self.safe_string(symbolAndTimeFrame, 1)
974
+ if timeframe in self.ohlcvs[symbol]:
975
+ del self.ohlcvs[symbol][timeframe]
976
+ elif symbolsLength > 0:
969
977
  for i in range(0, len(symbols)):
970
978
  symbol = symbols[i]
971
979
  if topic == 'trade':
@@ -1388,6 +1396,86 @@ class binance(ccxt.async_support.binance):
1388
1396
  filtered = self.filter_by_since_limit(candles, since, limit, 0, True)
1389
1397
  return self.create_ohlcv_object(symbol, timeframe, filtered)
1390
1398
 
1399
+ async def un_watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], params={}):
1400
+ """
1401
+ unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1402
+ :see: https://binance-docs.github.io/apidocs/spot/en/#kline-candlestick-data
1403
+ :see: https://binance-docs.github.io/apidocs/futures/en/#kline-candlestick-data
1404
+ :see: https://binance-docs.github.io/apidocs/delivery/en/#kline-candlestick-data
1405
+ :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
1406
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1407
+ :param dict [params.timezone]: if provided, kline intervals are interpreted in that timezone instead of UTC, example '+08:00'
1408
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
1409
+ """
1410
+ await self.load_markets()
1411
+ klineType = None
1412
+ klineType, params = self.handle_param_string_2(params, 'channel', 'name', 'kline')
1413
+ symbols = self.get_list_from_object_values(symbolsAndTimeframes, 0)
1414
+ marketSymbols = self.market_symbols(symbols, None, False, False, True)
1415
+ firstMarket = self.market(marketSymbols[0])
1416
+ type = firstMarket['type']
1417
+ if firstMarket['contract']:
1418
+ type = 'future' if firstMarket['linear'] else 'delivery'
1419
+ isSpot = (type == 'spot')
1420
+ timezone = None
1421
+ timezone, params = self.handle_param_string(params, 'timezone', None)
1422
+ isUtc8 = (timezone is not None) and ((timezone == '+08:00') or Precise.string_eq(timezone, '8'))
1423
+ rawHashes = []
1424
+ subMessageHashes = []
1425
+ messageHashes = []
1426
+ for i in range(0, len(symbolsAndTimeframes)):
1427
+ symAndTf = symbolsAndTimeframes[i]
1428
+ symbolString = symAndTf[0]
1429
+ timeframeString = symAndTf[1]
1430
+ interval = self.safe_string(self.timeframes, timeframeString, timeframeString)
1431
+ market = self.market(symbolString)
1432
+ marketId = market['lowercaseId']
1433
+ if klineType == 'indexPriceKline':
1434
+ # weird behavior for index price kline we can't use the perp suffix
1435
+ marketId = marketId.replace('_perp', '')
1436
+ shouldUseUTC8 = (isUtc8 and isSpot)
1437
+ suffix = '@+08:00'
1438
+ utcSuffix = suffix if shouldUseUTC8 else ''
1439
+ rawHashes.append(marketId + '@' + klineType + '_' + interval + utcSuffix)
1440
+ subMessageHashes.append('ohlcv::' + market['symbol'] + '::' + timeframeString)
1441
+ messageHashes.append('unsubscribe::ohlcv::' + market['symbol'] + '::' + timeframeString)
1442
+ url = self.urls['api']['ws'][type] + '/' + self.stream(type, 'multipleOHLCV')
1443
+ requestId = self.request_id(url)
1444
+ request = {
1445
+ 'method': 'UNSUBSCRIBE',
1446
+ 'params': rawHashes,
1447
+ 'id': requestId,
1448
+ }
1449
+ subscribe = {
1450
+ 'unsubscribe': True,
1451
+ 'id': str(requestId),
1452
+ 'symbols': symbols,
1453
+ 'symbolsAndTimeframes': symbolsAndTimeframes,
1454
+ 'subMessageHashes': subMessageHashes,
1455
+ 'messageHashes': messageHashes,
1456
+ 'topic': 'ohlcv',
1457
+ }
1458
+ params = self.omit(params, 'callerMethodName')
1459
+ return await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes, subscribe)
1460
+
1461
+ async def un_watch_ohlcv(self, symbol: str, timeframe='1m', params={}) -> Any:
1462
+ """
1463
+ unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1464
+ :see: https://binance-docs.github.io/apidocs/spot/en/#kline-candlestick-data
1465
+ :see: https://binance-docs.github.io/apidocs/futures/en/#kline-candlestick-data
1466
+ :see: https://binance-docs.github.io/apidocs/delivery/en/#kline-candlestick-data
1467
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
1468
+ :param str timeframe: the length of time each candle represents
1469
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1470
+ :param dict [params.timezone]: if provided, kline intervals are interpreted in that timezone instead of UTC, example '+08:00'
1471
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
1472
+ """
1473
+ await self.load_markets()
1474
+ market = self.market(symbol)
1475
+ symbol = market['symbol']
1476
+ params['callerMethodName'] = 'watchOHLCV'
1477
+ return await self.un_watch_ohlcv_for_symbols([[symbol, timeframe]], params)
1478
+
1391
1479
  def handle_ohlcv(self, client: Client, message):
1392
1480
  #
1393
1481
  # {
ccxt/pro/bybit.py CHANGED
@@ -609,6 +609,53 @@ class bybit(ccxt.async_support.bybit):
609
609
  filtered = self.filter_by_since_limit(stored, since, limit, 0, True)
610
610
  return self.create_ohlcv_object(symbol, timeframe, filtered)
611
611
 
612
+ async def un_watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], params={}):
613
+ """
614
+ unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
615
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/public/kline
616
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
617
+ :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
618
+ :param dict [params]: extra parameters specific to the exchange API endpoint
619
+ :returns dict: A list of candles ordered, open, high, low, close, volume
620
+ """
621
+ await self.load_markets()
622
+ symbols = self.get_list_from_object_values(symbolsAndTimeframes, 0)
623
+ marketSymbols = self.market_symbols(symbols, None, False, True, True)
624
+ firstSymbol = marketSymbols[0]
625
+ url = await self.get_url_by_market_type(firstSymbol, False, 'watchOHLCVForSymbols', params)
626
+ rawHashes = []
627
+ subMessageHashes = []
628
+ messageHashes = []
629
+ for i in range(0, len(symbolsAndTimeframes)):
630
+ data = symbolsAndTimeframes[i]
631
+ symbolString = self.safe_string(data, 0)
632
+ market = self.market(symbolString)
633
+ symbolString = market['symbol']
634
+ unfiedTimeframe = self.safe_string(data, 1)
635
+ timeframeId = self.safe_string(self.timeframes, unfiedTimeframe, unfiedTimeframe)
636
+ rawHashes.append('kline.' + timeframeId + '.' + market['id'])
637
+ subMessageHashes.append('ohlcv::' + symbolString + '::' + unfiedTimeframe)
638
+ messageHashes.append('unsubscribe::ohlcv::' + symbolString + '::' + unfiedTimeframe)
639
+ subExtension = {
640
+ 'symbolsAndTimeframes': symbolsAndTimeframes,
641
+ }
642
+ return await self.un_watch_topics(url, 'ohlcv', symbols, messageHashes, subMessageHashes, rawHashes, params, subExtension)
643
+
644
+ async def un_watch_ohlcv(self, symbol: str, timeframe='1m', params={}) -> Any:
645
+ """
646
+ unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
647
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/public/kline
648
+ :see: https://bybit-exchange.github.io/docs/v5/websocket/public/etp-kline
649
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
650
+ :param str timeframe: the length of time each candle represents
651
+ :param int [since]: timestamp in ms of the earliest candle to fetch
652
+ :param int [limit]: the maximum amount of candles to fetch
653
+ :param dict [params]: extra parameters specific to the exchange API endpoint
654
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
655
+ """
656
+ params['callerMethodName'] = 'watchOHLCV'
657
+ return await self.un_watch_ohlcv_for_symbols([[symbol, timeframe]], params)
658
+
612
659
  def handle_ohlcv(self, client: Client, message):
613
660
  #
614
661
  # {
@@ -1997,7 +2044,7 @@ class bybit(ccxt.async_support.bybit):
1997
2044
  message = self.extend(request, params)
1998
2045
  return await self.watch_multiple(url, messageHashes, message, messageHashes)
1999
2046
 
2000
- async def un_watch_topics(self, url: str, topic: str, symbols: List[str], messageHashes: List[str], subMessageHashes: List[str], topics, params={}):
2047
+ async def un_watch_topics(self, url: str, topic: str, symbols: List[str], messageHashes: List[str], subMessageHashes: List[str], topics, params={}, subExtension={}):
2001
2048
  reqId = self.request_id()
2002
2049
  request: dict = {
2003
2050
  'op': 'unsubscribe',
@@ -2012,7 +2059,7 @@ class bybit(ccxt.async_support.bybit):
2012
2059
  'symbols': symbols,
2013
2060
  }
2014
2061
  message = self.extend(request, params)
2015
- return await self.watch_multiple(url, messageHashes, message, messageHashes, subscription)
2062
+ return await self.watch_multiple(url, messageHashes, message, messageHashes, self.extend(subscription, subExtension))
2016
2063
 
2017
2064
  async def authenticate(self, url, params={}):
2018
2065
  self.check_required_credentials()
@@ -2270,14 +2317,21 @@ class bybit(ccxt.async_support.bybit):
2270
2317
  error = UnsubscribeError(self.id + ' ' + messageHash)
2271
2318
  client.reject(error, subHash)
2272
2319
  client.resolve(True, unsubHash)
2273
- self.clean_cache(subscription)
2320
+ self.clean_cache(subscription)
2274
2321
  return message
2275
2322
 
2276
2323
  def clean_cache(self, subscription: dict):
2277
2324
  topic = self.safe_string(subscription, 'topic')
2278
2325
  symbols = self.safe_list(subscription, 'symbols', [])
2279
2326
  symbolsLength = len(symbols)
2280
- if symbolsLength > 0:
2327
+ if topic == 'ohlcv':
2328
+ symbolsAndTimeFrames = self.safe_list(subscription, 'symbolsAndTimeframes', [])
2329
+ for i in range(0, len(symbolsAndTimeFrames)):
2330
+ symbolAndTimeFrame = symbolsAndTimeFrames[i]
2331
+ symbol = self.safe_string(symbolAndTimeFrame, 0)
2332
+ timeframe = self.safe_string(symbolAndTimeFrame, 1)
2333
+ del self.ohlcvs[symbol][timeframe]
2334
+ elif symbolsLength > 0:
2281
2335
  for i in range(0, len(symbols)):
2282
2336
  symbol = symbols[i]
2283
2337
  if topic == 'trade':