ccxt 4.3.95__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.
@@ -83,7 +83,6 @@ class tradeogre(Exchange, ImplicitAPI):
83
83
  'fetchOrderBooks': False,
84
84
  'fetchOrders': False,
85
85
  'fetchOrderTrades': False,
86
- 'fetchPermissions': False,
87
86
  'fetchPosition': False,
88
87
  'fetchPositionHistory': False,
89
88
  'fetchPositionMode': False,
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.95'
7
+ __version__ = '4.3.96'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -1930,7 +1930,6 @@ class Exchange(object):
1930
1930
  'fetchOrdersWs': None,
1931
1931
  'fetchOrderTrades': None,
1932
1932
  'fetchOrderWs': None,
1933
- 'fetchPermissions': None,
1934
1933
  'fetchPosition': None,
1935
1934
  'fetchPositionHistory': None,
1936
1935
  'fetchPositionsHistory': None,
@@ -4138,9 +4137,6 @@ class Exchange(object):
4138
4137
  self.cancel_order_ws(id, symbol)
4139
4138
  return self.create_order_ws(symbol, type, side, amount, price, params)
4140
4139
 
4141
- def fetch_permissions(self, params={}):
4142
- raise NotSupported(self.id + ' fetchPermissions() is not supported yet')
4143
-
4144
4140
  def fetch_position(self, symbol: str, params={}):
4145
4141
  raise NotSupported(self.id + ' fetchPosition() is not supported yet')
4146
4142
 
ccxt/bingx.py CHANGED
@@ -479,6 +479,7 @@ class bingx(Exchange, ImplicitAPI):
479
479
  },
480
480
  'commonCurrencies': {
481
481
  'SNOW': 'Snowman', # Snowman vs SnowSwap conflict
482
+ 'OMNI': 'OmniCat',
482
483
  },
483
484
  'options': {
484
485
  'defaultType': 'spot',
ccxt/blofin.py CHANGED
@@ -109,7 +109,6 @@ class blofin(Exchange, ImplicitAPI):
109
109
  'fetchOrderBooks': False,
110
110
  'fetchOrders': False,
111
111
  'fetchOrderTrades': True,
112
- 'fetchPermissions': None,
113
112
  'fetchPosition': True,
114
113
  'fetchPositions': True,
115
114
  'fetchPositionsForSymbol': False,
ccxt/bybit.py CHANGED
@@ -5502,11 +5502,16 @@ class bybit(Exchange, ImplicitAPI):
5502
5502
  :param str code: unified currency code, default is None
5503
5503
  :param int [since]: timestamp in ms of the earliest ledger entry, default is None
5504
5504
  :param int [limit]: max number of ledger entrys to return, default is None
5505
- :param dict [params]: extra parameters specific to the exchange API endpoint
5505
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
5506
5506
  :param str [params.subType]: if inverse will use v5/account/contract-transaction-log
5507
+ :param dict [params]: extra parameters specific to the exchange API endpoint
5507
5508
  :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
5508
5509
  """
5509
5510
  self.load_markets()
5511
+ paginate = False
5512
+ paginate, params = self.handle_option_and_params(params, 'fetchLedger', 'paginate')
5513
+ if paginate:
5514
+ return self.fetch_paginated_call_cursor('fetchLedger', code, since, limit, params, 'nextPageCursor', 'cursor', None, 50)
5510
5515
  request: dict = {
5511
5516
  # 'coin': currency['id'],
5512
5517
  # 'currency': currency['id'], # alias
@@ -5550,7 +5555,7 @@ class bybit(Exchange, ImplicitAPI):
5550
5555
  else:
5551
5556
  response = self.privateGetV5AccountTransactionLog(self.extend(request, params))
5552
5557
  else:
5553
- response = self.privateGetV2PrivateWalletFundRecords(self.extend(request, params))
5558
+ response = self.privateGetV5AccountContractTransactionLog(self.extend(request, params))
5554
5559
  #
5555
5560
  # {
5556
5561
  # "ret_code": 0,
ccxt/hyperliquid.py CHANGED
@@ -69,7 +69,7 @@ class hyperliquid(Exchange, ImplicitAPI):
69
69
  'fetchCurrencies': True,
70
70
  'fetchDepositAddress': False,
71
71
  'fetchDepositAddresses': False,
72
- 'fetchDeposits': False,
72
+ 'fetchDeposits': True,
73
73
  'fetchDepositWithdrawFee': 'emulated',
74
74
  'fetchDepositWithdrawFees': False,
75
75
  'fetchFundingHistory': False,
@@ -79,7 +79,7 @@ class hyperliquid(Exchange, ImplicitAPI):
79
79
  'fetchIndexOHLCV': False,
80
80
  'fetchIsolatedBorrowRate': False,
81
81
  'fetchIsolatedBorrowRates': False,
82
- 'fetchLedger': False,
82
+ 'fetchLedger': True,
83
83
  'fetchLeverage': False,
84
84
  'fetchLeverageTiers': False,
85
85
  'fetchLiquidations': False,
@@ -111,7 +111,7 @@ class hyperliquid(Exchange, ImplicitAPI):
111
111
  'fetchTransfer': False,
112
112
  'fetchTransfers': False,
113
113
  'fetchWithdrawal': False,
114
- 'fetchWithdrawals': False,
114
+ 'fetchWithdrawals': True,
115
115
  'reduceMargin': True,
116
116
  'repayCrossMargin': False,
117
117
  'repayIsolatedMargin': False,
@@ -1882,10 +1882,7 @@ class hyperliquid(Exchange, ImplicitAPI):
1882
1882
  coin = self.safe_string(entry, 'coin')
1883
1883
  marketId = None
1884
1884
  if coin is not None:
1885
- if coin.find('/') > -1:
1886
- marketId = coin
1887
- else:
1888
- marketId = coin + '/USDC:USDC'
1885
+ marketId = self.coin_to_market_id(coin)
1889
1886
  if self.safe_string(entry, 'id') is None:
1890
1887
  market = self.safe_market(marketId, None)
1891
1888
  else:
@@ -2013,7 +2010,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2013
2010
  price = self.safe_string(trade, 'px')
2014
2011
  amount = self.safe_string(trade, 'sz')
2015
2012
  coin = self.safe_string(trade, 'coin')
2016
- marketId = coin + '/USDC:USDC'
2013
+ marketId = self.coin_to_market_id(coin)
2017
2014
  market = self.safe_market(marketId, None)
2018
2015
  symbol = market['symbol']
2019
2016
  id = self.safe_string(trade, 'tid')
@@ -2147,7 +2144,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2147
2144
  #
2148
2145
  entry = self.safe_dict(position, 'position', {})
2149
2146
  coin = self.safe_string(entry, 'coin')
2150
- marketId = coin + '/USDC:USDC'
2147
+ marketId = self.coin_to_market_id(coin)
2151
2148
  market = self.safe_market(marketId, None)
2152
2149
  symbol = market['symbol']
2153
2150
  leverage = self.safe_dict(entry, 'leverage', {})
@@ -2433,11 +2430,13 @@ class hyperliquid(Exchange, ImplicitAPI):
2433
2430
  """
2434
2431
  make a withdrawal(only support USDC)
2435
2432
  :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#initiate-a-withdrawal-request
2433
+ :see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#deposit-or-withdraw-from-a-vault
2436
2434
  :param str code: unified currency code
2437
2435
  :param float amount: the amount to withdraw
2438
2436
  :param str address: the address to withdraw to
2439
2437
  :param str tag:
2440
2438
  :param dict [params]: extra parameters specific to the exchange API endpoint
2439
+ :param str [params.vaultAddress]: vault address withdraw from
2441
2440
  :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
2442
2441
  """
2443
2442
  self.check_required_credentials()
@@ -2447,24 +2446,38 @@ class hyperliquid(Exchange, ImplicitAPI):
2447
2446
  code = code.upper()
2448
2447
  if code != 'USDC':
2449
2448
  raise NotSupported(self.id + 'withdraw() only support USDC')
2450
- isSandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
2449
+ vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
2450
+ params = self.omit(params, 'vaultAddress')
2451
2451
  nonce = self.milliseconds()
2452
- payload: dict = {
2453
- 'hyperliquidChain': 'Testnet' if isSandboxMode else 'Mainnet',
2454
- 'destination': address,
2455
- 'amount': str(amount),
2456
- 'time': nonce,
2457
- }
2458
- sig = self.build_withdraw_sig(payload)
2459
- request: dict = {
2460
- 'action': {
2452
+ action: dict = {}
2453
+ sig = None
2454
+ if vaultAddress is not None:
2455
+ action = {
2456
+ 'type': 'vaultTransfer',
2457
+ 'vaultAddress': '0x' + vaultAddress,
2458
+ 'isDeposit': False,
2459
+ 'usd': amount,
2460
+ }
2461
+ sig = self.sign_l1_action(action, nonce)
2462
+ else:
2463
+ isSandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
2464
+ payload: dict = {
2465
+ 'hyperliquidChain': 'Testnet' if isSandboxMode else 'Mainnet',
2466
+ 'destination': address,
2467
+ 'amount': str(amount),
2468
+ 'time': nonce,
2469
+ }
2470
+ sig = self.build_withdraw_sig(payload)
2471
+ action = {
2461
2472
  'hyperliquidChain': payload['hyperliquidChain'],
2462
2473
  'signatureChainId': '0x66eee', # check self out
2463
2474
  'destination': address,
2464
2475
  'amount': str(amount),
2465
2476
  'time': nonce,
2466
2477
  'type': 'withdraw3',
2467
- },
2478
+ }
2479
+ request: dict = {
2480
+ 'action': action,
2468
2481
  'nonce': nonce,
2469
2482
  'signature': sig,
2470
2483
  }
@@ -2475,27 +2488,51 @@ class hyperliquid(Exchange, ImplicitAPI):
2475
2488
  #
2476
2489
  # {status: 'ok', response: {type: 'default'}}
2477
2490
  #
2491
+ # fetchDeposits / fetchWithdrawals
2492
+ # {
2493
+ # "time":1724762307531,
2494
+ # "hash":"0x620a234a7e0eb7930575040f59482a01050058b0802163b4767bfd9033e77781",
2495
+ # "delta":{
2496
+ # "type":"accountClassTransfer",
2497
+ # "usdc":"50.0",
2498
+ # "toPerp":false
2499
+ # }
2500
+ # }
2501
+ #
2502
+ timestamp = self.safe_integer(transaction, 'time')
2503
+ delta = self.safe_dict(transaction, 'delta', {})
2504
+ fee = None
2505
+ feeCost = self.safe_integer(delta, 'fee')
2506
+ if feeCost is not None:
2507
+ fee = {
2508
+ 'currency': 'USDC',
2509
+ 'cost': feeCost,
2510
+ }
2511
+ internal = None
2512
+ type = self.safe_string(delta, 'type')
2513
+ if type is not None:
2514
+ internal = (type == 'internalTransfer')
2478
2515
  return {
2479
2516
  'info': transaction,
2480
2517
  'id': None,
2481
- 'txid': None,
2482
- 'timestamp': None,
2483
- 'datetime': None,
2518
+ 'txid': self.safe_string(transaction, 'hash'),
2519
+ 'timestamp': timestamp,
2520
+ 'datetime': self.iso8601(timestamp),
2484
2521
  'network': None,
2485
2522
  'address': None,
2486
- 'addressTo': None,
2487
- 'addressFrom': None,
2523
+ 'addressTo': self.safe_string(delta, 'destination'),
2524
+ 'addressFrom': self.safe_string(delta, 'user'),
2488
2525
  'tag': None,
2489
2526
  'tagTo': None,
2490
2527
  'tagFrom': None,
2491
2528
  'type': None,
2492
- 'amount': None,
2529
+ 'amount': self.safe_integer(delta, 'usdc'),
2493
2530
  'currency': None,
2494
2531
  'status': self.safe_string(transaction, 'status'),
2495
2532
  'updated': None,
2496
2533
  'comment': None,
2497
- 'internal': None,
2498
- 'fee': None,
2534
+ 'internal': internal,
2535
+ 'fee': fee,
2499
2536
  }
2500
2537
 
2501
2538
  def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
@@ -2602,6 +2639,183 @@ class hyperliquid(Exchange, ImplicitAPI):
2602
2639
  'tierBased': None,
2603
2640
  }
2604
2641
 
2642
+ def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
2643
+ """
2644
+ fetch the history of changes, actions done by the user or operations that altered the balance of the user
2645
+ :param str code: unified currency code
2646
+ :param int [since]: timestamp in ms of the earliest ledger entry
2647
+ :param int [limit]: max number of ledger entrys to return
2648
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2649
+ :param int [params.until]: timestamp in ms of the latest ledger entry
2650
+ :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
2651
+ """
2652
+ self.load_markets()
2653
+ userAddress = None
2654
+ userAddress, params = self.handle_public_address('fetchLedger', params)
2655
+ request: dict = {
2656
+ 'type': 'userNonFundingLedgerUpdates',
2657
+ 'user': userAddress,
2658
+ }
2659
+ if since is not None:
2660
+ request['startTime'] = since
2661
+ until = self.safe_integer(params, 'until')
2662
+ if until is not None:
2663
+ request['endTime'] = until
2664
+ params = self.omit(params, ['until'])
2665
+ response = self.publicPostInfo(self.extend(request, params))
2666
+ #
2667
+ # [
2668
+ # {
2669
+ # "time":1724762307531,
2670
+ # "hash":"0x620a234a7e0eb7930575040f59482a01050058b0802163b4767bfd9033e77781",
2671
+ # "delta":{
2672
+ # "type":"accountClassTransfer",
2673
+ # "usdc":"50.0",
2674
+ # "toPerp":false
2675
+ # }
2676
+ # }
2677
+ # ]
2678
+ #
2679
+ return self.parse_ledger(response, None, since, limit)
2680
+
2681
+ def parse_ledger_entry(self, item: dict, currency: Currency = None):
2682
+ #
2683
+ # {
2684
+ # "time":1724762307531,
2685
+ # "hash":"0x620a234a7e0eb7930575040f59482a01050058b0802163b4767bfd9033e77781",
2686
+ # "delta":{
2687
+ # "type":"accountClassTransfer",
2688
+ # "usdc":"50.0",
2689
+ # "toPerp":false
2690
+ # }
2691
+ # }
2692
+ #
2693
+ timestamp = self.safe_integer(item, 'time')
2694
+ delta = self.safe_dict(item, 'delta', {})
2695
+ fee = None
2696
+ feeCost = self.safe_integer(delta, 'fee')
2697
+ if feeCost is not None:
2698
+ fee = {
2699
+ 'currency': 'USDC',
2700
+ 'cost': feeCost,
2701
+ }
2702
+ type = self.safe_string(delta, 'type')
2703
+ amount = self.safe_string(delta, 'usdc')
2704
+ return {
2705
+ 'id': self.safe_string(item, 'hash'),
2706
+ 'direction': None,
2707
+ 'account': None,
2708
+ 'referenceAccount': self.safe_string(delta, 'user'),
2709
+ 'referenceId': self.safe_string(item, 'hash'),
2710
+ 'type': self.parse_ledger_entry_type(type),
2711
+ 'currency': None,
2712
+ 'amount': self.parse_number(amount),
2713
+ 'timestamp': timestamp,
2714
+ 'datetime': self.iso8601(timestamp),
2715
+ 'before': None,
2716
+ 'after': None,
2717
+ 'status': None,
2718
+ 'fee': fee,
2719
+ 'info': item,
2720
+ }
2721
+
2722
+ def parse_ledger_entry_type(self, type):
2723
+ ledgerType: dict = {
2724
+ 'internalTransfer': 'transfer',
2725
+ 'accountClassTransfer': 'transfer',
2726
+ }
2727
+ return self.safe_string(ledgerType, type, type)
2728
+
2729
+ def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
2730
+ """
2731
+ fetch all deposits made to an account
2732
+ :param str code: unified currency code
2733
+ :param int [since]: the earliest time in ms to fetch deposits for
2734
+ :param int [limit]: the maximum number of deposits structures to retrieve
2735
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2736
+ :param int [params.until]: the latest time in ms to fetch withdrawals for
2737
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2738
+ """
2739
+ self.load_markets()
2740
+ userAddress = None
2741
+ userAddress, params = self.handle_public_address('fetchDepositsWithdrawals', params)
2742
+ request: dict = {
2743
+ 'type': 'userNonFundingLedgerUpdates',
2744
+ 'user': userAddress,
2745
+ }
2746
+ if since is not None:
2747
+ request['startTime'] = since
2748
+ until = self.safe_integer(params, 'until')
2749
+ if until is not None:
2750
+ request['endTime'] = until
2751
+ params = self.omit(params, ['until'])
2752
+ response = self.publicPostInfo(self.extend(request, params))
2753
+ #
2754
+ # [
2755
+ # {
2756
+ # "time":1724762307531,
2757
+ # "hash":"0x620a234a7e0eb7930575040f59482a01050058b0802163b4767bfd9033e77781",
2758
+ # "delta":{
2759
+ # "type":"accountClassTransfer",
2760
+ # "usdc":"50.0",
2761
+ # "toPerp":false
2762
+ # }
2763
+ # }
2764
+ # ]
2765
+ #
2766
+ records = self.extract_type_from_delta(response)
2767
+ deposits = self.filter_by_array(records, 'type', ['deposit'], False)
2768
+ return self.parse_transactions(deposits, None, since, limit)
2769
+
2770
+ def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2771
+ """
2772
+ fetch all withdrawals made from an account
2773
+ :param str code: unified currency code
2774
+ :param int [since]: the earliest time in ms to fetch withdrawals for
2775
+ :param int [limit]: the maximum number of withdrawals structures to retrieve
2776
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2777
+ :param int [params.until]: the latest time in ms to fetch withdrawals for
2778
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2779
+ """
2780
+ self.load_markets()
2781
+ userAddress = None
2782
+ userAddress, params = self.handle_public_address('fetchDepositsWithdrawals', params)
2783
+ request: dict = {
2784
+ 'type': 'userNonFundingLedgerUpdates',
2785
+ 'user': userAddress,
2786
+ }
2787
+ if since is not None:
2788
+ request['startTime'] = since
2789
+ until = self.safe_integer(params, 'until')
2790
+ if until is not None:
2791
+ request['endTime'] = until
2792
+ params = self.omit(params, ['until'])
2793
+ response = self.publicPostInfo(self.extend(request, params))
2794
+ #
2795
+ # [
2796
+ # {
2797
+ # "time":1724762307531,
2798
+ # "hash":"0x620a234a7e0eb7930575040f59482a01050058b0802163b4767bfd9033e77781",
2799
+ # "delta":{
2800
+ # "type":"accountClassTransfer",
2801
+ # "usdc":"50.0",
2802
+ # "toPerp":false
2803
+ # }
2804
+ # }
2805
+ # ]
2806
+ #
2807
+ records = self.extract_type_from_delta(response)
2808
+ withdrawals = self.filter_by_array(records, 'type', ['withdraw'], False)
2809
+ return self.parse_transactions(withdrawals, None, since, limit)
2810
+
2811
+ def extract_type_from_delta(self, data=[]):
2812
+ records = []
2813
+ for i in range(0, len(data)):
2814
+ record = data[i]
2815
+ record['type'] = record['delta']['type']
2816
+ records.append(record)
2817
+ return records
2818
+
2605
2819
  def format_vault_address(self, address: Str = None):
2606
2820
  if address is None:
2607
2821
  return None
@@ -2621,7 +2835,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2621
2835
  raise ArgumentsRequired(self.id + ' ' + methodName + '() requires a user parameter inside \'params\' or the wallet address set')
2622
2836
 
2623
2837
  def coin_to_market_id(self, coin: Str):
2624
- if coin.find('/') > -1:
2838
+ if coin.find('/') > -1 or coin.find('@') > -1:
2625
2839
  return coin # spot
2626
2840
  return coin + '/USDC:USDC'
2627
2841
 
ccxt/kucoin.py CHANGED
@@ -644,6 +644,7 @@ class kucoin(Exchange, ImplicitAPI):
644
644
  'KALT': 'ALT', # ALTLAYER
645
645
  },
646
646
  'options': {
647
+ 'hf': False,
647
648
  'version': 'v1',
648
649
  'symbolSeparator': '-',
649
650
  'fetchMyTradesMethod': 'private_get_fills',
@@ -1228,8 +1229,7 @@ class kucoin(Exchange, ImplicitAPI):
1228
1229
  self.options['hfMigrated'] = (status == 2)
1229
1230
 
1230
1231
  def handle_hf_and_params(self, params={}):
1231
- self.load_migration_status()
1232
- migrated: Bool = self.safe_bool(self.options, 'hfMigrated')
1232
+ migrated: Bool = self.safe_bool_2(self.options, 'hfMigrated', 'hf', False)
1233
1233
  loadedHf: Bool = None
1234
1234
  if migrated is not None:
1235
1235
  if migrated:
ccxt/mexc.py CHANGED
@@ -809,6 +809,8 @@ class mexc(Exchange, ImplicitAPI):
809
809
  def fetch_status(self, params={}):
810
810
  """
811
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
812
814
  :param dict [params]: extra parameters specific to the exchange API endpoint
813
815
  :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
814
816
  """
@@ -842,6 +844,8 @@ class mexc(Exchange, ImplicitAPI):
842
844
  def fetch_time(self, params={}):
843
845
  """
844
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
845
849
  :param dict [params]: extra parameters specific to the exchange API endpoint
846
850
  :returns int: the current integer timestamp in milliseconds from the exchange server
847
851
  """
@@ -998,6 +1002,8 @@ class mexc(Exchange, ImplicitAPI):
998
1002
  def fetch_markets(self, params={}) -> List[Market]:
999
1003
  """
1000
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
1001
1007
  :param dict [params]: extra parameters specific to the exchange API endpoint
1002
1008
  :returns dict[]: an array of objects representing market data
1003
1009
  """
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,
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.95'
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
  # {