ccxt 4.3.86__py2.py3-none-any.whl → 4.3.87__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.
ccxt/__init__.py CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  # ----------------------------------------------------------------------------
24
24
 
25
- __version__ = '4.3.86'
25
+ __version__ = '4.3.87'
26
26
 
27
27
  # ----------------------------------------------------------------------------
28
28
 
@@ -80,6 +80,7 @@ from ccxt.base.errors import RequestTimeout # noqa: F4
80
80
  from ccxt.base.errors import BadResponse # noqa: F401
81
81
  from ccxt.base.errors import NullResponse # noqa: F401
82
82
  from ccxt.base.errors import CancelPending # noqa: F401
83
+ from ccxt.base.errors import UnsubscribeError # noqa: F401
83
84
  from ccxt.base.errors import error_hierarchy # noqa: F401
84
85
 
85
86
  from ccxt.ace import ace # noqa: F401
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.86'
7
+ __version__ = '4.3.87'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -59,6 +59,7 @@ from ccxt.base.errors import RequestTimeout # noqa: F4
59
59
  from ccxt.base.errors import BadResponse # noqa: F401
60
60
  from ccxt.base.errors import NullResponse # noqa: F401
61
61
  from ccxt.base.errors import CancelPending # noqa: F401
62
+ from ccxt.base.errors import UnsubscribeError # noqa: F401
62
63
  from ccxt.base.errors import error_hierarchy # noqa: F401
63
64
 
64
65
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  # -----------------------------------------------------------------------------
4
4
 
5
- __version__ = '4.3.86'
5
+ __version__ = '4.3.87'
6
6
 
7
7
  # -----------------------------------------------------------------------------
8
8
 
@@ -749,7 +749,11 @@ class bingx(Exchange, ImplicitAPI):
749
749
  symbol += ':' + settle
750
750
  fees = self.safe_dict(self.fees, type, {})
751
751
  contractSize = self.parse_number('1') if (swap) else None
752
- isActive = self.safe_string(market, 'status') == '1'
752
+ isActive = False
753
+ if (self.safe_string(market, 'apiStateOpen') == 'true') and (self.safe_string(market, 'apiStateClose') == 'true'):
754
+ isActive = True # swap active
755
+ elif self.safe_bool(market, 'apiStateSell') and self.safe_bool(market, 'apiStateBuy'):
756
+ isActive = True # spot active
753
757
  isInverse = None if (spot) else checkIsInverse
754
758
  isLinear = None if (spot) else checkIsLinear
755
759
  timeOnline = self.safe_integer(market, 'timeOnline')
@@ -47,7 +47,6 @@ class hashkey(Exchange, ImplicitAPI):
47
47
  'version': 'v1',
48
48
  'certified': True,
49
49
  'pro': True,
50
- 'hostname': '/api-glb',
51
50
  'has': {
52
51
  'CORS': None,
53
52
  'spot': True,
@@ -168,7 +167,7 @@ class hashkey(Exchange, ImplicitAPI):
168
167
  'www': 'https://global.hashkey.com/',
169
168
  'doc': 'https://hashkeyglobal-apidoc.readme.io/',
170
169
  'fees': 'https://support.global.hashkey.com/hc/en-us/articles/13199900083612-HashKey-Global-Fee-Structure',
171
- 'referral': '',
170
+ 'referral': 'https://global.hashkey.com/en-US/register/invite?invite_code=82FQUN',
172
171
  },
173
172
  'api': {
174
173
  'public': {
@@ -1086,6 +1086,7 @@ class kraken(Exchange, ImplicitAPI):
1086
1086
  :param int [limit]: max number of ledger entrys to return, default is None
1087
1087
  :param dict [params]: extra parameters specific to the exchange API endpoint
1088
1088
  :param int [params.until]: timestamp in ms of the latest ledger entry
1089
+ :param int [params.end]: timestamp in seconds of the latest ledger entry
1089
1090
  :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
1090
1091
  """
1091
1092
  # https://www.kraken.com/features/api#get-ledgers-info
@@ -1097,7 +1098,11 @@ class kraken(Exchange, ImplicitAPI):
1097
1098
  request['asset'] = currency['id']
1098
1099
  if since is not None:
1099
1100
  request['start'] = self.parse_to_int(since / 1000)
1100
- request, params = self.handle_until_option('end', request, params)
1101
+ until = self.safe_string_n(params, ['until', 'till'])
1102
+ if until is not None:
1103
+ params = self.omit(params, ['until', 'till'])
1104
+ untilDivided = Precise.string_div(until, '1000')
1105
+ request['end'] = self.parse_to_int(Precise.string_add(untilDivided, '1'))
1101
1106
  response = await self.privatePostLedgers(self.extend(request, params))
1102
1107
  # { error: [],
1103
1108
  # "result": {ledger: {'LPUAIB-TS774-UKHP7X': { refid: "A2B4HBV-L4MDIE-JU4N3N",
@@ -1995,6 +2000,8 @@ class kraken(Exchange, ImplicitAPI):
1995
2000
  :param int [since]: the earliest time in ms to fetch trades for
1996
2001
  :param int [limit]: the maximum number of trades structures to retrieve
1997
2002
  :param dict [params]: extra parameters specific to the exchange API endpoint
2003
+ :param int [params.until]: timestamp in ms of the latest trade entry
2004
+ :param int [params.end]: timestamp in seconds of the latest trade entry
1998
2005
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1999
2006
  """
2000
2007
  await self.load_markets()
@@ -2007,6 +2014,11 @@ class kraken(Exchange, ImplicitAPI):
2007
2014
  }
2008
2015
  if since is not None:
2009
2016
  request['start'] = self.parse_to_int(since / 1000)
2017
+ until = self.safe_string_n(params, ['until', 'till'])
2018
+ if until is not None:
2019
+ params = self.omit(params, ['until', 'till'])
2020
+ untilDivided = Precise.string_div(until, '1000')
2021
+ request['end'] = self.parse_to_int(Precise.string_add(untilDivided, '1'))
2010
2022
  response = await self.privatePostTradesHistory(self.extend(request, params))
2011
2023
  #
2012
2024
  # {
@@ -2391,6 +2403,8 @@ class kraken(Exchange, ImplicitAPI):
2391
2403
  :param int [since]: the earliest time in ms to fetch deposits for
2392
2404
  :param int [limit]: the maximum number of deposits structures to retrieve
2393
2405
  :param dict [params]: extra parameters specific to the exchange API endpoint
2406
+ :param int [params.until]: timestamp in ms of the latest transaction entry
2407
+ :param int [params.end]: timestamp in seconds of the latest transaction entry
2394
2408
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2395
2409
  """
2396
2410
  # https://www.kraken.com/en-us/help/api#deposit-status
@@ -2400,7 +2414,13 @@ class kraken(Exchange, ImplicitAPI):
2400
2414
  currency = self.currency(code)
2401
2415
  request['asset'] = currency['id']
2402
2416
  if since is not None:
2403
- request['start'] = since
2417
+ sinceString = self.number_to_string(since)
2418
+ request['start'] = Precise.string_div(sinceString, '1000')
2419
+ until = self.safe_string_n(params, ['until', 'till'])
2420
+ if until is not None:
2421
+ params = self.omit(params, ['until', 'till'])
2422
+ untilDivided = Precise.string_div(until, '1000')
2423
+ request['end'] = Precise.string_add(untilDivided, '1')
2404
2424
  response = await self.privatePostDepositStatus(self.extend(request, params))
2405
2425
  #
2406
2426
  # { error: [],
@@ -2446,8 +2466,9 @@ class kraken(Exchange, ImplicitAPI):
2446
2466
  :param int [since]: the earliest time in ms to fetch withdrawals for
2447
2467
  :param int [limit]: the maximum number of withdrawals structures to retrieve
2448
2468
  :param dict [params]: extra parameters specific to the exchange API endpoint
2449
- :param dict [params.end]: End timestamp, withdrawals created strictly after will be not be included in the response
2450
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times
2469
+ :param int [params.until]: timestamp in ms of the latest transaction entry
2470
+ :param int [params.end]: timestamp in seconds of the latest transaction entry
2471
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times
2451
2472
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2452
2473
  """
2453
2474
  await self.load_markets()
@@ -2461,7 +2482,13 @@ class kraken(Exchange, ImplicitAPI):
2461
2482
  currency = self.currency(code)
2462
2483
  request['asset'] = currency['id']
2463
2484
  if since is not None:
2464
- request['since'] = str(since)
2485
+ sinceString = self.number_to_string(since)
2486
+ request['start'] = Precise.string_div(sinceString, '1000')
2487
+ until = self.safe_string_n(params, ['until', 'till'])
2488
+ if until is not None:
2489
+ params = self.omit(params, ['until', 'till'])
2490
+ untilDivided = Precise.string_div(until, '1000')
2491
+ request['end'] = Precise.string_add(untilDivided, '1')
2465
2492
  response = await self.privatePostWithdrawStatus(self.extend(request, params))
2466
2493
  #
2467
2494
  # with no pagination
@@ -1891,7 +1891,7 @@ class upbit(Exchange, ImplicitAPI):
1891
1891
  body = self.json(params)
1892
1892
  headers['Content-Type'] = 'application/json'
1893
1893
  if hasQuery:
1894
- auth = self.urlencode(query)
1894
+ auth = self.rawencode(query)
1895
1895
  if auth is not None:
1896
1896
  hash = self.hash(self.encode(auth), 'sha512')
1897
1897
  request['query_hash'] = hash
ccxt/base/errors.py CHANGED
@@ -51,6 +51,7 @@ error_hierarchy = {
51
51
  },
52
52
  'CancelPending': {},
53
53
  },
54
+ 'UnsubscribeError': {},
54
55
  },
55
56
  }
56
57
 
@@ -211,6 +212,10 @@ class CancelPending(OperationFailed):
211
212
  pass
212
213
 
213
214
 
215
+ class UnsubscribeError(BaseError):
216
+ pass
217
+
218
+
214
219
  __all__ = [
215
220
  'error_hierarchy',
216
221
  'BaseError',
@@ -251,5 +256,6 @@ __all__ = [
251
256
  'RequestTimeout',
252
257
  'BadResponse',
253
258
  'NullResponse',
254
- 'CancelPending'
259
+ 'CancelPending',
260
+ 'UnsubscribeError'
255
261
  ]
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.86'
7
+ __version__ = '4.3.87'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
ccxt/bingx.py CHANGED
@@ -748,7 +748,11 @@ class bingx(Exchange, ImplicitAPI):
748
748
  symbol += ':' + settle
749
749
  fees = self.safe_dict(self.fees, type, {})
750
750
  contractSize = self.parse_number('1') if (swap) else None
751
- isActive = self.safe_string(market, 'status') == '1'
751
+ isActive = False
752
+ if (self.safe_string(market, 'apiStateOpen') == 'true') and (self.safe_string(market, 'apiStateClose') == 'true'):
753
+ isActive = True # swap active
754
+ elif self.safe_bool(market, 'apiStateSell') and self.safe_bool(market, 'apiStateBuy'):
755
+ isActive = True # spot active
752
756
  isInverse = None if (spot) else checkIsInverse
753
757
  isLinear = None if (spot) else checkIsLinear
754
758
  timeOnline = self.safe_integer(market, 'timeOnline')
ccxt/hashkey.py CHANGED
@@ -47,7 +47,6 @@ class hashkey(Exchange, ImplicitAPI):
47
47
  'version': 'v1',
48
48
  'certified': True,
49
49
  'pro': True,
50
- 'hostname': '/api-glb',
51
50
  'has': {
52
51
  'CORS': None,
53
52
  'spot': True,
@@ -168,7 +167,7 @@ class hashkey(Exchange, ImplicitAPI):
168
167
  'www': 'https://global.hashkey.com/',
169
168
  'doc': 'https://hashkeyglobal-apidoc.readme.io/',
170
169
  'fees': 'https://support.global.hashkey.com/hc/en-us/articles/13199900083612-HashKey-Global-Fee-Structure',
171
- 'referral': '',
170
+ 'referral': 'https://global.hashkey.com/en-US/register/invite?invite_code=82FQUN',
172
171
  },
173
172
  'api': {
174
173
  'public': {
ccxt/kraken.py CHANGED
@@ -1086,6 +1086,7 @@ class kraken(Exchange, ImplicitAPI):
1086
1086
  :param int [limit]: max number of ledger entrys to return, default is None
1087
1087
  :param dict [params]: extra parameters specific to the exchange API endpoint
1088
1088
  :param int [params.until]: timestamp in ms of the latest ledger entry
1089
+ :param int [params.end]: timestamp in seconds of the latest ledger entry
1089
1090
  :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
1090
1091
  """
1091
1092
  # https://www.kraken.com/features/api#get-ledgers-info
@@ -1097,7 +1098,11 @@ class kraken(Exchange, ImplicitAPI):
1097
1098
  request['asset'] = currency['id']
1098
1099
  if since is not None:
1099
1100
  request['start'] = self.parse_to_int(since / 1000)
1100
- request, params = self.handle_until_option('end', request, params)
1101
+ until = self.safe_string_n(params, ['until', 'till'])
1102
+ if until is not None:
1103
+ params = self.omit(params, ['until', 'till'])
1104
+ untilDivided = Precise.string_div(until, '1000')
1105
+ request['end'] = self.parse_to_int(Precise.string_add(untilDivided, '1'))
1101
1106
  response = self.privatePostLedgers(self.extend(request, params))
1102
1107
  # { error: [],
1103
1108
  # "result": {ledger: {'LPUAIB-TS774-UKHP7X': { refid: "A2B4HBV-L4MDIE-JU4N3N",
@@ -1995,6 +2000,8 @@ class kraken(Exchange, ImplicitAPI):
1995
2000
  :param int [since]: the earliest time in ms to fetch trades for
1996
2001
  :param int [limit]: the maximum number of trades structures to retrieve
1997
2002
  :param dict [params]: extra parameters specific to the exchange API endpoint
2003
+ :param int [params.until]: timestamp in ms of the latest trade entry
2004
+ :param int [params.end]: timestamp in seconds of the latest trade entry
1998
2005
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1999
2006
  """
2000
2007
  self.load_markets()
@@ -2007,6 +2014,11 @@ class kraken(Exchange, ImplicitAPI):
2007
2014
  }
2008
2015
  if since is not None:
2009
2016
  request['start'] = self.parse_to_int(since / 1000)
2017
+ until = self.safe_string_n(params, ['until', 'till'])
2018
+ if until is not None:
2019
+ params = self.omit(params, ['until', 'till'])
2020
+ untilDivided = Precise.string_div(until, '1000')
2021
+ request['end'] = self.parse_to_int(Precise.string_add(untilDivided, '1'))
2010
2022
  response = self.privatePostTradesHistory(self.extend(request, params))
2011
2023
  #
2012
2024
  # {
@@ -2391,6 +2403,8 @@ class kraken(Exchange, ImplicitAPI):
2391
2403
  :param int [since]: the earliest time in ms to fetch deposits for
2392
2404
  :param int [limit]: the maximum number of deposits structures to retrieve
2393
2405
  :param dict [params]: extra parameters specific to the exchange API endpoint
2406
+ :param int [params.until]: timestamp in ms of the latest transaction entry
2407
+ :param int [params.end]: timestamp in seconds of the latest transaction entry
2394
2408
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2395
2409
  """
2396
2410
  # https://www.kraken.com/en-us/help/api#deposit-status
@@ -2400,7 +2414,13 @@ class kraken(Exchange, ImplicitAPI):
2400
2414
  currency = self.currency(code)
2401
2415
  request['asset'] = currency['id']
2402
2416
  if since is not None:
2403
- request['start'] = since
2417
+ sinceString = self.number_to_string(since)
2418
+ request['start'] = Precise.string_div(sinceString, '1000')
2419
+ until = self.safe_string_n(params, ['until', 'till'])
2420
+ if until is not None:
2421
+ params = self.omit(params, ['until', 'till'])
2422
+ untilDivided = Precise.string_div(until, '1000')
2423
+ request['end'] = Precise.string_add(untilDivided, '1')
2404
2424
  response = self.privatePostDepositStatus(self.extend(request, params))
2405
2425
  #
2406
2426
  # { error: [],
@@ -2446,8 +2466,9 @@ class kraken(Exchange, ImplicitAPI):
2446
2466
  :param int [since]: the earliest time in ms to fetch withdrawals for
2447
2467
  :param int [limit]: the maximum number of withdrawals structures to retrieve
2448
2468
  :param dict [params]: extra parameters specific to the exchange API endpoint
2449
- :param dict [params.end]: End timestamp, withdrawals created strictly after will be not be included in the response
2450
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times
2469
+ :param int [params.until]: timestamp in ms of the latest transaction entry
2470
+ :param int [params.end]: timestamp in seconds of the latest transaction entry
2471
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times
2451
2472
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2452
2473
  """
2453
2474
  self.load_markets()
@@ -2461,7 +2482,13 @@ class kraken(Exchange, ImplicitAPI):
2461
2482
  currency = self.currency(code)
2462
2483
  request['asset'] = currency['id']
2463
2484
  if since is not None:
2464
- request['since'] = str(since)
2485
+ sinceString = self.number_to_string(since)
2486
+ request['start'] = Precise.string_div(sinceString, '1000')
2487
+ until = self.safe_string_n(params, ['until', 'till'])
2488
+ if until is not None:
2489
+ params = self.omit(params, ['until', 'till'])
2490
+ untilDivided = Precise.string_div(until, '1000')
2491
+ request['end'] = Precise.string_add(untilDivided, '1')
2465
2492
  response = self.privatePostWithdrawStatus(self.extend(request, params))
2466
2493
  #
2467
2494
  # with no pagination
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.86'
7
+ __version__ = '4.3.87'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
ccxt/pro/bitget.py CHANGED
@@ -16,6 +16,7 @@ from ccxt.base.errors import ArgumentsRequired
16
16
  from ccxt.base.errors import BadRequest
17
17
  from ccxt.base.errors import RateLimitExceeded
18
18
  from ccxt.base.errors import ChecksumError
19
+ from ccxt.base.errors import UnsubscribeError
19
20
  from ccxt.base.precise import Precise
20
21
 
21
22
 
@@ -133,6 +134,17 @@ class bitget(ccxt.async_support.bitget):
133
134
  }
134
135
  return await self.watch_public(messageHash, args, params)
135
136
 
137
+ async def un_watch_ticker(self, symbol: str, params={}) -> Any:
138
+ """
139
+ unsubscribe from the ticker channel
140
+ :see: https://www.bitget.com/api-doc/spot/websocket/public/Tickers-Channel
141
+ :see: https://www.bitget.com/api-doc/contract/websocket/public/Tickers-Channel
142
+ :param str symbol: unified symbol of the market to unwatch the ticker for
143
+ :returns any: status of the unwatch request
144
+ """
145
+ await self.load_markets()
146
+ return await self.un_watch_channel(symbol, 'ticker', 'ticker', params)
147
+
136
148
  async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
137
149
  """
138
150
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
@@ -338,6 +350,20 @@ class bitget(ccxt.async_support.bitget):
338
350
  limit = ohlcv.getLimit(symbol, limit)
339
351
  return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
340
352
 
353
+ async def un_watch_ohlcv(self, symbol: str, timeframe='1m', params={}) -> Any:
354
+ """
355
+ unsubscribe from the ohlcv channel
356
+ :see: https://www.bitget.com/api-doc/spot/websocket/public/Candlesticks-Channel
357
+ :see: https://www.bitget.com/api-doc/contract/websocket/public/Candlesticks-Channel
358
+ :param str symbol: unified symbol of the market to unwatch the ohlcv for
359
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
360
+ """
361
+ await self.load_markets()
362
+ timeframes = self.safe_dict(self.options, 'timeframes')
363
+ interval = self.safe_string(timeframes, timeframe)
364
+ channel = 'candle' + interval
365
+ return await self.un_watch_channel(symbol, channel, 'candles:' + timeframe, params)
366
+
341
367
  def handle_ohlcv(self, client: Client, message):
342
368
  #
343
369
  # {
@@ -440,13 +466,17 @@ class bitget(ccxt.async_support.bitget):
440
466
  :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
441
467
  """
442
468
  await self.load_markets()
443
- market = self.market(symbol)
444
- messageHash = 'unsubscribe:orderbook:' + market['symbol']
445
469
  channel = 'books'
446
470
  limit = self.safe_integer(params, 'limit')
447
471
  if (limit == 1) or (limit == 5) or (limit == 15):
448
472
  params = self.omit(params, 'limit')
449
473
  channel += str(limit)
474
+ return await self.un_watch_channel(symbol, channel, 'orderbook', params)
475
+
476
+ async def un_watch_channel(self, symbol: str, channel: str, messageHashTopic: str, params={}) -> Any:
477
+ await self.load_markets()
478
+ market = self.market(symbol)
479
+ messageHash = 'unsubscribe:' + messageHashTopic + ':' + market['symbol']
450
480
  instType = None
451
481
  instType, params = self.get_inst_type(market, params)
452
482
  args: dict = {
@@ -648,6 +678,17 @@ class bitget(ccxt.async_support.bitget):
648
678
  limit = trades.getLimit(tradeSymbol, limit)
649
679
  return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
650
680
 
681
+ async def un_watch_trades(self, symbol: str, params={}) -> Any:
682
+ """
683
+ unsubscribe from the trades channel
684
+ :see: https://www.bitget.com/api-doc/spot/websocket/public/Trades-Channel
685
+ :see: https://www.bitget.com/api-doc/contract/websocket/public/New-Trades-Channel
686
+ :param str symbol: unified symbol of the market to unwatch the trades for
687
+ :returns any: status of the unwatch request
688
+ """
689
+ await self.load_markets()
690
+ return await self.un_watch_channel(symbol, 'trade', 'trade', params)
691
+
651
692
  def handle_trades(self, client: Client, message):
652
693
  #
653
694
  # {
@@ -1750,6 +1791,99 @@ class bitget(ccxt.async_support.bitget):
1750
1791
  #
1751
1792
  return message
1752
1793
 
1794
+ def handle_order_book_un_subscription(self, client: Client, message):
1795
+ #
1796
+ # {"event":"unsubscribe","arg":{"instType":"SPOT","channel":"books","instId":"BTCUSDT"}}
1797
+ #
1798
+ arg = self.safe_dict(message, 'arg', {})
1799
+ instType = self.safe_string_lower(arg, 'instType')
1800
+ type = 'spot' if (instType == 'spot') else 'contract'
1801
+ instId = self.safe_string(arg, 'instId')
1802
+ market = self.safe_market(instId, None, None, type)
1803
+ symbol = market['symbol']
1804
+ messageHash = 'unsubscribe:orderbook:' + market['symbol']
1805
+ subMessageHash = 'orderbook:' + symbol
1806
+ if symbol in self.orderbooks:
1807
+ del self.orderbooks[symbol]
1808
+ if subMessageHash in client.subscriptions:
1809
+ del client.subscriptions[subMessageHash]
1810
+ if messageHash in client.subscriptions:
1811
+ del client.subscriptions[messageHash]
1812
+ error = UnsubscribeError(self.id + 'orderbook ' + symbol)
1813
+ client.reject(error, subMessageHash)
1814
+ client.resolve(True, messageHash)
1815
+
1816
+ def handle_trades_un_subscription(self, client: Client, message):
1817
+ #
1818
+ # {"event":"unsubscribe","arg":{"instType":"SPOT","channel":"trade","instId":"BTCUSDT"}}
1819
+ #
1820
+ arg = self.safe_dict(message, 'arg', {})
1821
+ instType = self.safe_string_lower(arg, 'instType')
1822
+ type = 'spot' if (instType == 'spot') else 'contract'
1823
+ instId = self.safe_string(arg, 'instId')
1824
+ market = self.safe_market(instId, None, None, type)
1825
+ symbol = market['symbol']
1826
+ messageHash = 'unsubscribe:trade:' + market['symbol']
1827
+ subMessageHash = 'trade:' + symbol
1828
+ if symbol in self.trades:
1829
+ del self.trades[symbol]
1830
+ if subMessageHash in client.subscriptions:
1831
+ del client.subscriptions[subMessageHash]
1832
+ if messageHash in client.subscriptions:
1833
+ del client.subscriptions[messageHash]
1834
+ error = UnsubscribeError(self.id + 'trades ' + symbol)
1835
+ client.reject(error, subMessageHash)
1836
+ client.resolve(True, messageHash)
1837
+
1838
+ def handle_ticker_un_subscription(self, client: Client, message):
1839
+ #
1840
+ # {"event":"unsubscribe","arg":{"instType":"SPOT","channel":"trade","instId":"BTCUSDT"}}
1841
+ #
1842
+ arg = self.safe_dict(message, 'arg', {})
1843
+ instType = self.safe_string_lower(arg, 'instType')
1844
+ type = 'spot' if (instType == 'spot') else 'contract'
1845
+ instId = self.safe_string(arg, 'instId')
1846
+ market = self.safe_market(instId, None, None, type)
1847
+ symbol = market['symbol']
1848
+ messageHash = 'unsubscribe:ticker:' + market['symbol']
1849
+ subMessageHash = 'ticker:' + symbol
1850
+ if symbol in self.tickers:
1851
+ del self.tickers[symbol]
1852
+ if subMessageHash in client.subscriptions:
1853
+ del client.subscriptions[subMessageHash]
1854
+ if messageHash in client.subscriptions:
1855
+ del client.subscriptions[messageHash]
1856
+ error = UnsubscribeError(self.id + 'ticker ' + symbol)
1857
+ client.reject(error, subMessageHash)
1858
+ client.resolve(True, messageHash)
1859
+
1860
+ def handle_ohlcv_un_subscription(self, client: Client, message):
1861
+ #
1862
+ # {"event":"unsubscribe","arg":{"instType":"SPOT","channel":"candle1m","instId":"BTCUSDT"}}
1863
+ #
1864
+ arg = self.safe_dict(message, 'arg', {})
1865
+ instType = self.safe_string_lower(arg, 'instType')
1866
+ type = 'spot' if (instType == 'spot') else 'contract'
1867
+ instId = self.safe_string(arg, 'instId')
1868
+ channel = self.safe_string(arg, 'channel')
1869
+ interval = channel.replace('candle', '')
1870
+ timeframes = self.safe_value(self.options, 'timeframes')
1871
+ timeframe = self.find_timeframe(interval, timeframes)
1872
+ market = self.safe_market(instId, None, None, type)
1873
+ symbol = market['symbol']
1874
+ messageHash = 'unsubscribe:candles:' + timeframe + ':' + market['symbol']
1875
+ subMessageHash = 'candles:' + timeframe + ':' + symbol
1876
+ if symbol in self.ohlcvs:
1877
+ if timeframe in self.ohlcvs[symbol]:
1878
+ del self.ohlcvs[symbol][timeframe]
1879
+ if subMessageHash in client.subscriptions:
1880
+ del client.subscriptions[subMessageHash]
1881
+ if messageHash in client.subscriptions:
1882
+ del client.subscriptions[messageHash]
1883
+ error = UnsubscribeError(self.id + ' ohlcv ' + timeframe + ' ' + symbol)
1884
+ client.reject(error, subMessageHash)
1885
+ client.resolve(True, messageHash)
1886
+
1753
1887
  def handle_un_subscription_status(self, client: Client, message):
1754
1888
  #
1755
1889
  # {
@@ -1778,18 +1912,11 @@ class bitget(ccxt.async_support.bitget):
1778
1912
  channel = self.safe_string(arg, 'channel')
1779
1913
  if channel == 'books':
1780
1914
  # for now only unWatchOrderBook is supporteod
1781
- instType = self.safe_string_lower(arg, 'instType')
1782
- type = 'spot' if (instType == 'spot') else 'contract'
1783
- instId = self.safe_string(arg, 'instId')
1784
- market = self.safe_market(instId, None, None, type)
1785
- symbol = market['symbol']
1786
- messageHash = 'unsubscribe:orderbook:' + market['symbol']
1787
- subMessageHash = 'orderbook:' + symbol
1788
- if symbol in self.orderbooks:
1789
- del self.orderbooks[symbol]
1790
- if subMessageHash in client.subscriptions:
1791
- del client.subscriptions[subMessageHash]
1792
- if messageHash in client.subscriptions:
1793
- del client.subscriptions[messageHash]
1794
- client.resolve(True, messageHash)
1915
+ self.handle_order_book_un_subscription(client, message)
1916
+ elif channel == 'trade':
1917
+ self.handle_trades_un_subscription(client, message)
1918
+ elif channel == 'ticker':
1919
+ self.handle_ticker_un_subscription(client, message)
1920
+ elif channel.startswith('candle'):
1921
+ self.handle_ohlcv_un_subscription(client, message)
1795
1922
  return message
ccxt/pro/p2b.py CHANGED
@@ -36,6 +36,7 @@ class p2b(ccxt.async_support.p2b):
36
36
  'watchTicker': True,
37
37
  'watchTickers': False, # in the docs but does not return anything when subscribed to
38
38
  'watchTrades': True,
39
+ 'watchTradesForSymbols': True,
39
40
  },
40
41
  'urls': {
41
42
  'api': {
@@ -142,15 +143,37 @@ class p2b(ccxt.async_support.p2b):
142
143
  :param dict [params]: extra parameters specific to the exchange API endpoint
143
144
  :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
144
145
  """
146
+ return await self.watch_trades_for_symbols([symbol], since, limit, params)
147
+
148
+ async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
149
+ """
150
+ get the list of most recent trades for a list of symbols
151
+ :see: https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#deals
152
+ :param str[] symbols: unified symbol of the market to fetch trades for
153
+ :param int [since]: timestamp in ms of the earliest trade to fetch
154
+ :param int [limit]: the maximum amount of trades to fetch
155
+ :param dict [params]: extra parameters specific to the exchange API endpoint
156
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
157
+ """
145
158
  await self.load_markets()
146
- market = self.market(symbol)
147
- request = [
148
- market['id'],
149
- ]
150
- messageHash = 'deals::' + market['symbol']
151
- trades = await self.subscribe('deals.subscribe', messageHash, request, params)
159
+ symbols = self.market_symbols(symbols, None, False, True, True)
160
+ messageHashes = []
161
+ if symbols is not None:
162
+ for i in range(0, len(symbols)):
163
+ messageHashes.append('deals::' + symbols[i])
164
+ marketIds = self.market_ids(symbols)
165
+ url = self.urls['api']['ws']
166
+ subscribe: dict = {
167
+ 'method': 'deals.subscribe',
168
+ 'params': marketIds,
169
+ 'id': self.milliseconds(),
170
+ }
171
+ query = self.extend(subscribe, params)
172
+ trades = await self.watch_multiple(url, messageHashes, query, messageHashes)
152
173
  if self.newUpdates:
153
- limit = trades.getLimit(symbol, limit)
174
+ first = self.safe_value(trades, 0)
175
+ tradeSymbol = self.safe_string(first, 'symbol')
176
+ limit = trades.getLimit(tradeSymbol, limit)
154
177
  return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
155
178
 
156
179
  async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
ccxt/pro/poloniex.py CHANGED
@@ -27,6 +27,7 @@ class poloniex(ccxt.async_support.poloniex):
27
27
  'watchTicker': True,
28
28
  'watchTickers': True,
29
29
  'watchTrades': True,
30
+ 'watchTradesForSymbols': True,
30
31
  'watchBalance': True,
31
32
  'watchStatus': False,
32
33
  'watchOrders': True,
@@ -367,12 +368,40 @@ class poloniex(ccxt.async_support.poloniex):
367
368
  :param dict [params]: extra parameters specific to the exchange API endpoint
368
369
  :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
369
370
  """
371
+ return await self.watch_trades_for_symbols([symbol], since, limit, params)
372
+
373
+ async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
374
+ """
375
+ get the list of most recent trades for a list of symbols
376
+ :see: https://api-docs.poloniex.com/spot/websocket/market-data#trades
377
+ :param str[] symbols: unified symbol of the market to fetch trades for
378
+ :param int [since]: timestamp in ms of the earliest trade to fetch
379
+ :param int [limit]: the maximum amount of trades to fetch
380
+ :param dict [params]: extra parameters specific to the exchange API endpoint
381
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
382
+ """
370
383
  await self.load_markets()
371
- symbol = self.symbol(symbol)
384
+ symbols = self.market_symbols(symbols, None, False, True, True)
372
385
  name = 'trades'
373
- trades = await self.subscribe(name, name, False, [symbol], params)
386
+ url = self.urls['api']['ws']['public']
387
+ marketIds = self.market_ids(symbols)
388
+ subscribe: dict = {
389
+ 'event': 'subscribe',
390
+ 'channel': [
391
+ name,
392
+ ],
393
+ 'symbols': marketIds,
394
+ }
395
+ request = self.extend(subscribe, params)
396
+ messageHashes = []
397
+ if symbols is not None:
398
+ for i in range(0, len(symbols)):
399
+ messageHashes.append(name + '::' + symbols[i])
400
+ trades = await self.watch_multiple(url, messageHashes, request, messageHashes)
374
401
  if self.newUpdates:
375
- limit = trades.getLimit(symbol, limit)
402
+ first = self.safe_value(trades, 0)
403
+ tradeSymbol = self.safe_string(first, 'symbol')
404
+ limit = trades.getLimit(tradeSymbol, limit)
376
405
  return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
377
406
 
378
407
  async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
@@ -33,6 +33,7 @@ class poloniexfutures(ccxt.async_support.poloniexfutures):
33
33
  'watchTicker': True,
34
34
  'watchTickers': False,
35
35
  'watchTrades': True,
36
+ 'watchTradesForSymbols': False,
36
37
  'watchBalance': True,
37
38
  'watchOrders': True,
38
39
  'watchMyTrades': False,
ccxt/pro/probit.py CHANGED
@@ -22,6 +22,7 @@ class probit(ccxt.async_support.probit):
22
22
  'watchTicker': True,
23
23
  'watchTickers': False,
24
24
  'watchTrades': True,
25
+ 'watchTradesForSymbols': False,
25
26
  'watchMyTrades': True,
26
27
  'watchOrders': True,
27
28
  'watchOrderBook': True,
@@ -217,6 +218,7 @@ class probit(ccxt.async_support.probit):
217
218
  async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
218
219
  """
219
220
  get the list of trades associated with the user
221
+ :see: https://docs-en.probit.com/reference/trade_history
220
222
  :param str symbol: unified symbol of the market to fetch trades for
221
223
  :param int [since]: timestamp in ms of the earliest trade to fetch
222
224
  :param int [limit]: the maximum amount of trades to fetch
ccxt/pro/upbit.py CHANGED
@@ -19,6 +19,7 @@ class upbit(ccxt.async_support.upbit):
19
19
  'watchOrderBook': True,
20
20
  'watchTicker': True,
21
21
  'watchTrades': True,
22
+ 'watchTradesForSymbols': True,
22
23
  'watchOrders': True,
23
24
  'watchMyTrades': True,
24
25
  'watchBalance': True,
@@ -79,11 +80,51 @@ class upbit(ccxt.async_support.upbit):
79
80
  :param dict [params]: extra parameters specific to the exchange API endpoint
80
81
  :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
81
82
  """
83
+ return await self.watch_trades_for_symbols([symbol], since, limit, params)
84
+
85
+ async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
86
+ """
87
+ get the list of most recent trades for a list of symbols
88
+ :see: https://global-docs.upbit.com/reference/websocket-trade
89
+ :param str[] symbols: unified symbol of the market to fetch trades for
90
+ :param int [since]: timestamp in ms of the earliest trade to fetch
91
+ :param int [limit]: the maximum amount of trades to fetch
92
+ :param dict [params]: extra parameters specific to the exchange API endpoint
93
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
94
+ """
82
95
  await self.load_markets()
83
- symbol = self.symbol(symbol)
84
- trades = await self.watch_public(symbol, 'trade')
96
+ symbols = self.market_symbols(symbols, None, False, True, True)
97
+ channel = 'trade'
98
+ messageHashes = []
99
+ url = self.implode_params(self.urls['api']['ws'], {
100
+ 'hostname': self.hostname,
101
+ })
102
+ if symbols is not None:
103
+ for i in range(0, len(symbols)):
104
+ market = self.market(symbols[i])
105
+ marketId = market['id']
106
+ symbol = market['symbol']
107
+ self.options[channel] = self.safe_value(self.options, channel, {})
108
+ self.options[channel][symbol] = True
109
+ messageHashes.append(channel + ':' + marketId)
110
+ optionSymbols = list(self.options[channel].keys())
111
+ marketIds = self.market_ids(optionSymbols)
112
+ request = [
113
+ {
114
+ 'ticket': self.uuid(),
115
+ },
116
+ {
117
+ 'type': channel,
118
+ 'codes': marketIds,
119
+ # 'isOnlySnapshot': False,
120
+ # 'isOnlyRealtime': False,
121
+ },
122
+ ]
123
+ trades = await self.watch_multiple(url, messageHashes, request, messageHashes)
85
124
  if self.newUpdates:
86
- limit = trades.getLimit(symbol, limit)
125
+ first = self.safe_value(trades, 0)
126
+ tradeSymbol = self.safe_string(first, 'symbol')
127
+ limit = trades.getLimit(tradeSymbol, limit)
87
128
  return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
88
129
 
89
130
  async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
ccxt/pro/vertex.py CHANGED
@@ -28,6 +28,7 @@ class vertex(ccxt.async_support.vertex):
28
28
  'watchTicker': True,
29
29
  'watchTickers': False,
30
30
  'watchTrades': True,
31
+ 'watchTradesForSymbols': False,
31
32
  'watchPositions': True,
32
33
  },
33
34
  'urls': {
ccxt/pro/wazirx.py CHANGED
@@ -22,6 +22,7 @@ class wazirx(ccxt.async_support.wazirx):
22
22
  'watchTicker': True,
23
23
  'watchTickers': True,
24
24
  'watchTrades': True,
25
+ 'watchTradesForSymbols': False,
25
26
  'watchMyTrades': True,
26
27
  'watchOrders': True,
27
28
  'watchOrderBook': True,
@@ -283,6 +284,7 @@ class wazirx(ccxt.async_support.wazirx):
283
284
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
284
285
  """
285
286
  get the list of most recent trades for a particular symbol
287
+ :see: https://docs.wazirx.com/#trade-streams
286
288
  :param str symbol: unified symbol of the market to fetch trades for
287
289
  :param int [since]: timestamp in ms of the earliest trade to fetch
288
290
  :param int [limit]: the maximum amount of trades to fetch
@@ -371,6 +373,7 @@ class wazirx(ccxt.async_support.wazirx):
371
373
  async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
372
374
  """
373
375
  watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
376
+ :see: https://docs.wazirx.com/#kline-candlestick-stream
374
377
  :param str symbol: unified symbol of the market to fetch OHLCV data for
375
378
  :param str timeframe: the length of time each candle represents
376
379
  :param int [since]: timestamp in ms of the earliest candle to fetch
ccxt/pro/whitebit.py CHANGED
@@ -27,6 +27,7 @@ class whitebit(ccxt.async_support.whitebit):
27
27
  'watchOrders': True,
28
28
  'watchTicker': True,
29
29
  'watchTrades': True,
30
+ 'watchTradesForSymbols': False,
30
31
  },
31
32
  'urls': {
32
33
  'api': {
@@ -67,6 +68,7 @@ class whitebit(ccxt.async_support.whitebit):
67
68
  async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
68
69
  """
69
70
  watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
71
+ :see: https://docs.whitebit.com/public/websocket/#kline
70
72
  :param str symbol: unified symbol of the market to fetch OHLCV data for
71
73
  :param str timeframe: the length of time each candle represents
72
74
  :param int [since]: timestamp in ms of the earliest candle to fetch
@@ -135,6 +137,7 @@ class whitebit(ccxt.async_support.whitebit):
135
137
  async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
136
138
  """
137
139
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
140
+ :see: https://docs.whitebit.com/public/websocket/#market-depth
138
141
  :param str symbol: unified symbol of the market to fetch the order book for
139
142
  :param int [limit]: the maximum amount of order book entries to return
140
143
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -233,6 +236,7 @@ class whitebit(ccxt.async_support.whitebit):
233
236
  async def watch_ticker(self, symbol: str, params={}) -> Ticker:
234
237
  """
235
238
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
239
+ :see: https://docs.whitebit.com/public/websocket/#market-statistics
236
240
  :param str symbol: unified symbol of the market to fetch the ticker for
237
241
  :param dict [params]: extra parameters specific to the exchange API endpoint
238
242
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -295,6 +299,7 @@ class whitebit(ccxt.async_support.whitebit):
295
299
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
296
300
  """
297
301
  get the list of most recent trades for a particular symbol
302
+ :see: https://docs.whitebit.com/public/websocket/#market-trades
298
303
  :param str symbol: unified symbol of the market to fetch trades for
299
304
  :param int [since]: timestamp in ms of the earliest trade to fetch
300
305
  :param int [limit]: the maximum amount of trades to fetch
@@ -356,6 +361,7 @@ class whitebit(ccxt.async_support.whitebit):
356
361
  async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
357
362
  """
358
363
  watches trades made by the user
364
+ :see: https://docs.whitebit.com/private/websocket/#deals
359
365
  :param str symbol: unified market symbol
360
366
  :param int [since]: the earliest time in ms to fetch trades for
361
367
  :param int [limit]: the maximum number of trades structures to retrieve
@@ -449,6 +455,7 @@ class whitebit(ccxt.async_support.whitebit):
449
455
  async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
450
456
  """
451
457
  watches information on multiple orders made by the user
458
+ :see: https://docs.whitebit.com/private/websocket/#orders-pending
452
459
  :param str symbol: unified market symbol of the market orders were made in
453
460
  :param int [since]: the earliest time in ms to fetch orders for
454
461
  :param int [limit]: the maximum number of order structures to retrieve
@@ -612,6 +619,8 @@ class whitebit(ccxt.async_support.whitebit):
612
619
  async def watch_balance(self, params={}) -> Balances:
613
620
  """
614
621
  watch balance and get the amount of funds available for trading or funds locked in orders
622
+ :see: https://docs.whitebit.com/private/websocket/#balance-spot
623
+ :see: https://docs.whitebit.com/private/websocket/#balance-margin
615
624
  :param dict [params]: extra parameters specific to the exchange API endpoint
616
625
  :param str [params.type]: spot or contract if not provided self.options['defaultType'] is used
617
626
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
ccxt/test/tests_async.py CHANGED
@@ -920,6 +920,9 @@ class testMainClass(baseMainTestClass):
920
920
  is_disabled = exchange.safe_bool(result, 'disabled', False)
921
921
  if is_disabled:
922
922
  continue
923
+ is_disabled_c_sharp = exchange.safe_bool(result, 'disabledCS', False)
924
+ if is_disabled_c_sharp and (self.lang == 'C#'):
925
+ continue
923
926
  type = exchange.safe_string(exchange_data, 'outputType')
924
927
  skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
925
928
  await self.test_request_statically(exchange, method, result, type, skip_keys)
@@ -1036,7 +1039,7 @@ class testMainClass(baseMainTestClass):
1036
1039
  # -----------------------------------------------------------------------------
1037
1040
  # --- Init of brokerId tests functions-----------------------------------------
1038
1041
  # -----------------------------------------------------------------------------
1039
- promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational(), self.test_coinbase_advanced(), self.test_woofi_pro(), self.test_oxfun(), self.test_xt(), self.test_vertex(), self.test_paradex()]
1042
+ promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational(), self.test_coinbase_advanced(), self.test_woofi_pro(), self.test_oxfun(), self.test_xt(), self.test_vertex(), self.test_paradex(), self.test_hashkey()]
1040
1043
  await asyncio.gather(*promises)
1041
1044
  success_message = '[' + self.lang + '][TEST_SUCCESS] brokerId tests passed.'
1042
1045
  dump('[INFO]' + success_message)
@@ -1484,3 +1487,17 @@ class testMainClass(baseMainTestClass):
1484
1487
  if not self.is_synchronous:
1485
1488
  await close(exchange)
1486
1489
  return True
1490
+
1491
+ async def test_hashkey(self):
1492
+ exchange = self.init_offline_exchange('hashkey')
1493
+ req_headers = None
1494
+ id = '10000700011'
1495
+ try:
1496
+ await exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1497
+ except Exception as e:
1498
+ # we expect an error here, we're only interested in the headers
1499
+ req_headers = exchange.last_request_headers
1500
+ assert req_headers['INPUT-SOURCE'] == id, 'hashkey - id: ' + id + ' not in headers.'
1501
+ if not self.is_synchronous:
1502
+ await close(exchange)
1503
+ return True
ccxt/test/tests_sync.py CHANGED
@@ -917,6 +917,9 @@ class testMainClass(baseMainTestClass):
917
917
  is_disabled = exchange.safe_bool(result, 'disabled', False)
918
918
  if is_disabled:
919
919
  continue
920
+ is_disabled_c_sharp = exchange.safe_bool(result, 'disabledCS', False)
921
+ if is_disabled_c_sharp and (self.lang == 'C#'):
922
+ continue
920
923
  type = exchange.safe_string(exchange_data, 'outputType')
921
924
  skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
922
925
  self.test_request_statically(exchange, method, result, type, skip_keys)
@@ -1033,7 +1036,7 @@ class testMainClass(baseMainTestClass):
1033
1036
  # -----------------------------------------------------------------------------
1034
1037
  # --- Init of brokerId tests functions-----------------------------------------
1035
1038
  # -----------------------------------------------------------------------------
1036
- promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational(), self.test_coinbase_advanced(), self.test_woofi_pro(), self.test_oxfun(), self.test_xt(), self.test_vertex(), self.test_paradex()]
1039
+ promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational(), self.test_coinbase_advanced(), self.test_woofi_pro(), self.test_oxfun(), self.test_xt(), self.test_vertex(), self.test_paradex(), self.test_hashkey()]
1037
1040
  (promises)
1038
1041
  success_message = '[' + self.lang + '][TEST_SUCCESS] brokerId tests passed.'
1039
1042
  dump('[INFO]' + success_message)
@@ -1481,3 +1484,17 @@ class testMainClass(baseMainTestClass):
1481
1484
  if not self.is_synchronous:
1482
1485
  close(exchange)
1483
1486
  return True
1487
+
1488
+ def test_hashkey(self):
1489
+ exchange = self.init_offline_exchange('hashkey')
1490
+ req_headers = None
1491
+ id = '10000700011'
1492
+ try:
1493
+ exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1494
+ except Exception as e:
1495
+ # we expect an error here, we're only interested in the headers
1496
+ req_headers = exchange.last_request_headers
1497
+ assert req_headers['INPUT-SOURCE'] == id, 'hashkey - id: ' + id + ' not in headers.'
1498
+ if not self.is_synchronous:
1499
+ close(exchange)
1500
+ return True
ccxt/upbit.py CHANGED
@@ -1891,7 +1891,7 @@ class upbit(Exchange, ImplicitAPI):
1891
1891
  body = self.json(params)
1892
1892
  headers['Content-Type'] = 'application/json'
1893
1893
  if hasQuery:
1894
- auth = self.urlencode(query)
1894
+ auth = self.rawencode(query)
1895
1895
  if auth is not None:
1896
1896
  hash = self.hash(self.encode(auth), 'sha512')
1897
1897
  request['query_hash'] = hash
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ccxt
3
- Version: 4.3.86
3
+ Version: 4.3.87
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
@@ -70,6 +70,7 @@ Current feature list:
70
70
 
71
71
 
72
72
  ## Sponsored Promotion
73
+ [![hashkey-campaign](https://github.com/user-attachments/assets/1622ba7d-637d-41e3-9ad4-d61a6ea69881)](https://support.global.hashkey.com/hc/en-us/articles/15485543021468-Trade-Through-CCXT-to-Grab-up-to-1-000-USDT-30-Day-VIP5-Trial)
73
74
 
74
75
  ## See Also
75
76
 
@@ -96,7 +97,7 @@ Current feature list:
96
97
  | [![coinex](https://user-images.githubusercontent.com/51840849/87182089-1e05fa00-c2ec-11ea-8da9-cc73b45abbbc.jpg)](https://www.coinex.com/register?refer_code=yw5fz) | coinex | [CoinEx](https://www.coinex.com/register?refer_code=yw5fz) | [![API Version 2](https://img.shields.io/badge/2-lightgray)](https://docs.coinex.com/api/v2) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) | |
97
98
  | [![cryptocom](https://user-images.githubusercontent.com/1294454/147792121-38ed5e36-c229-48d6-b49a-48d05fc19ed4.jpeg)](https://crypto.com/exch/kdacthrnxt) | cryptocom | [Crypto.com](https://crypto.com/exch/kdacthrnxt) | [![API Version 2](https://img.shields.io/badge/2-lightgray)](https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) | [![Sign up with Crypto.com using CCXT's referral link for a 15% discount!](https://img.shields.io/static/v1?label=Fee&message=%2d15%25&color=orange)](https://crypto.com/exch/kdacthrnxt) |
98
99
  | [![gate](https://user-images.githubusercontent.com/1294454/31784029-0313c702-b509-11e7-9ccc-bc0da6a0e435.jpg)](https://www.gate.io/signup/2436035) | gate | [Gate.io](https://www.gate.io/signup/2436035) | [![API Version 4](https://img.shields.io/badge/4-lightgray)](https://www.gate.io/docs/developers/apiv4/en/) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) | [![Sign up with Gate.io using CCXT's referral link for a 20% discount!](https://img.shields.io/static/v1?label=Fee&message=%2d20%25&color=orange)](https://www.gate.io/signup/2436035) |
99
- | [![hashkey](https://github.com/user-attachments/assets/6dd6127b-cc19-4a13-9b29-a98d81f80e98)](https://global.hashkey.com/) | hashkey | [HashKey Global](https://global.hashkey.com/) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://hashkeyglobal-apidoc.readme.io/) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) | |
100
+ | [![hashkey](https://github.com/user-attachments/assets/6dd6127b-cc19-4a13-9b29-a98d81f80e98)](https://global.hashkey.com/en-US/register/invite?invite_code=82FQUN) | hashkey | [HashKey Global](https://global.hashkey.com/en-US/register/invite?invite_code=82FQUN) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://hashkeyglobal-apidoc.readme.io/) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) | |
100
101
  | [![htx](https://user-images.githubusercontent.com/1294454/76137448-22748a80-604e-11ea-8069-6e389271911d.jpg)](https://www.huobi.com/en-us/v/register/double-invite/?inviter_id=11343840&invite_code=6rmm2223) | htx | [HTX](https://www.huobi.com/en-us/v/register/double-invite/?inviter_id=11343840&invite_code=6rmm2223) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://huobiapi.github.io/docs/spot/v1/en/) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) | [![Sign up with HTX using CCXT's referral link for a 15% discount!](https://img.shields.io/static/v1?label=Fee&message=%2d15%25&color=orange)](https://www.huobi.com/en-us/v/register/double-invite/?inviter_id=11343840&invite_code=6rmm2223) |
101
102
  | [![kucoin](https://user-images.githubusercontent.com/51840849/87295558-132aaf80-c50e-11ea-9801-a2fb0c57c799.jpg)](https://www.kucoin.com/ucenter/signup?rcode=E5wkqe) | kucoin | [KuCoin](https://www.kucoin.com/ucenter/signup?rcode=E5wkqe) | [![API Version 2](https://img.shields.io/badge/2-lightgray)](https://docs.kucoin.com) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) | |
102
103
  | [![kucoinfutures](https://user-images.githubusercontent.com/1294454/147508995-9e35030a-d046-43a1-a006-6fabd981b554.jpg)](https://futures.kucoin.com/?rcode=E5wkqe) | kucoinfutures | [KuCoin Futures](https://futures.kucoin.com/?rcode=E5wkqe) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://docs.kucoin.com/futures) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) | |
@@ -166,7 +167,7 @@ The CCXT library currently supports the following 103 cryptocurrency exchange ma
166
167
  | [![fmfwio](https://user-images.githubusercontent.com/1294454/159177712-b685b40c-5269-4cea-ac83-f7894c49525d.jpg)](https://fmfw.io/referral/da948b21d6c92d69) | fmfwio | [FMFW.io](https://fmfw.io/referral/da948b21d6c92d69) | [![API Version 3](https://img.shields.io/badge/3-lightgray)](https://api.fmfw.io/) | cex | | |
167
168
  | [![gate](https://user-images.githubusercontent.com/1294454/31784029-0313c702-b509-11e7-9ccc-bc0da6a0e435.jpg)](https://www.gate.io/signup/2436035) | gate | [Gate.io](https://www.gate.io/signup/2436035) | [![API Version 4](https://img.shields.io/badge/4-lightgray)](https://www.gate.io/docs/developers/apiv4/en/) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) |
168
169
  | [![gemini](https://user-images.githubusercontent.com/1294454/27816857-ce7be644-6096-11e7-82d6-3c257263229c.jpg)](https://gemini.com/) | gemini | [Gemini](https://gemini.com/) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://docs.gemini.com/rest-api) | cex | | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) |
169
- | [![hashkey](https://github.com/user-attachments/assets/6dd6127b-cc19-4a13-9b29-a98d81f80e98)](https://global.hashkey.com/) | hashkey | [HashKey Global](https://global.hashkey.com/) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://hashkeyglobal-apidoc.readme.io/) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) |
170
+ | [![hashkey](https://github.com/user-attachments/assets/6dd6127b-cc19-4a13-9b29-a98d81f80e98)](https://global.hashkey.com/en-US/register/invite?invite_code=82FQUN) | hashkey | [HashKey Global](https://global.hashkey.com/en-US/register/invite?invite_code=82FQUN) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://hashkeyglobal-apidoc.readme.io/) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) |
170
171
  | [![hitbtc](https://user-images.githubusercontent.com/1294454/27766555-8eaec20e-5edc-11e7-9c5b-6dc69fc42f5e.jpg)](https://hitbtc.com/?ref_id=5a5d39a65d466) | hitbtc | [HitBTC](https://hitbtc.com/?ref_id=5a5d39a65d466) | [![API Version 3](https://img.shields.io/badge/3-lightgray)](https://api.hitbtc.com) | cex | | |
171
172
  | [![hollaex](https://user-images.githubusercontent.com/1294454/75841031-ca375180-5ddd-11ea-8417-b975674c23cb.jpg)](https://pro.hollaex.com/signup?affiliation_code=QSWA6G) | hollaex | [HollaEx](https://pro.hollaex.com/signup?affiliation_code=QSWA6G) | [![API Version 2](https://img.shields.io/badge/2-lightgray)](https://apidocs.hollaex.com) | cex | | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) |
172
173
  | [![htx](https://user-images.githubusercontent.com/1294454/76137448-22748a80-604e-11ea-8069-6e389271911d.jpg)](https://www.huobi.com/en-us/v/register/double-invite/?inviter_id=11343840&invite_code=6rmm2223) | htx | [HTX](https://www.huobi.com/en-us/v/register/double-invite/?inviter_id=11343840&invite_code=6rmm2223) | [![API Version 1](https://img.shields.io/badge/1-lightgray)](https://huobiapi.github.io/docs/spot/v1/en/) | cex | [![CCXT Certified](https://img.shields.io/badge/CCXT-Certified-green.svg)](https://github.com/ccxt/ccxt/wiki/Certification) | [![CCXT Pro](https://img.shields.io/badge/CCXT-Pro-black)](https://ccxt.pro) |
@@ -271,13 +272,13 @@ console.log(version, Object.keys(exchanges));
271
272
 
272
273
  All-in-one browser bundle (dependencies included), served from a CDN of your choice:
273
274
 
274
- * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.3.86/dist/ccxt.browser.min.js
275
- * unpkg: https://unpkg.com/ccxt@4.3.86/dist/ccxt.browser.min.js
275
+ * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.3.87/dist/ccxt.browser.min.js
276
+ * unpkg: https://unpkg.com/ccxt@4.3.87/dist/ccxt.browser.min.js
276
277
 
277
278
  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.
278
279
 
279
280
  ```HTML
280
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.3.86/dist/ccxt.browser.min.js"></script>
281
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.3.87/dist/ccxt.browser.min.js"></script>
281
282
  ```
282
283
 
283
284
  Creates a global `ccxt` object:
@@ -1,4 +1,4 @@
1
- ccxt/__init__.py,sha256=Ezv2iybn70-8xK2_MfT2d-_ptoVvjmslqim9t9hoJww,16598
1
+ ccxt/__init__.py,sha256=tu-EBwRzj_4AK73jwB48l6ruzHdahz7VpqV588J6DLg,16681
2
2
  ccxt/ace.py,sha256=Gee4ymA83iAuBFm3J8NaTb7qmu9buV2trA676KCtSVg,42383
3
3
  ccxt/alpaca.py,sha256=HQuhQZSFGRlT-BaCUSEZmxpzYp6tll2zn63qn3gTmoU,47470
4
4
  ccxt/ascendex.py,sha256=4aEwibO_me6khr66z8JFqDBxe2gtFOWIFBE7ulBEJPs,151933
@@ -8,7 +8,7 @@ ccxt/binance.py,sha256=234uj97QAqu_-AqxFaFczbV4jnXyhemCsq_RxJQgwjw,641408
8
8
  ccxt/binancecoinm.py,sha256=arFnEh8mErSyi23eVPWE4iwoT7PWQyxGGVJCKCy6UJY,1702
9
9
  ccxt/binanceus.py,sha256=hdcT4OnadcdFFFjF3GtM0nWv90jqojqwdVS3xWGuW40,9163
10
10
  ccxt/binanceusdm.py,sha256=bAPcJj5HLxoCdPolriM8sJpoTBwbV78vBTbKRmWhNP4,2632
11
- ccxt/bingx.py,sha256=dYb2tADqgxTglhSBNypxpd9pkLzekejQ1ISvgy3yeYQ,244207
11
+ ccxt/bingx.py,sha256=yTClKbMVv9rh30l0sRuzZJMRyYSjsxO2bzlFztfylBo,244475
12
12
  ccxt/bit2c.py,sha256=KwHefm2dfgcSR5LeGbHpFQlSI3LNot8tmDEgRJc2gBc,37061
13
13
  ccxt/bitbank.py,sha256=bHLOW6EAbNsjK2nXCtmxj23f2geW_-E_xfHXAvARMtw,43534
14
14
  ccxt/bitbay.py,sha256=xAIjzGRDVGwoy-Gygd99H0YN4wiaz_0lR0Z14oxaaxc,478
@@ -59,7 +59,7 @@ ccxt/fmfwio.py,sha256=RbVLvzPwnqfDsE7Ea-N13ISCC82eJVPsXYjrleASmew,1236
59
59
  ccxt/gate.py,sha256=dlKwcUQOvriaUmopMaF4BiziBTFdIoaEgt3-LKS8lk8,327645
60
60
  ccxt/gateio.py,sha256=86AETJWODl_vA5VNeQRHZprmpNIY1HAxCddKZcnKSi8,445
61
61
  ccxt/gemini.py,sha256=ddoOnPZzu-l899JGVw4b9wwT9HI20mVqLz7iihhZxng,80876
62
- ccxt/hashkey.py,sha256=J0xlmi_N_fShOAbXMIZqq8Xy42brzzyMpeVlH6-HPEM,191707
62
+ ccxt/hashkey.py,sha256=AfbhV_QCW31jzy8BFPnmGdhWfXz4WILIl-qh3jB4ZMc,191738
63
63
  ccxt/hitbtc.py,sha256=iqyd0otbWmIHUJiJ6gzIfe34IOa8PCEeS8nG6s6Ogc0,153398
64
64
  ccxt/hitbtc3.py,sha256=qRAr4Zvaju9IQWRZUohdoN7xRnzIMPq8AyYb3gPv-Is,455
65
65
  ccxt/hollaex.py,sha256=2KIbenZ3vcBDN_rs2CxG5_foKLaYxJd73vVV7M8n_8E,76140
@@ -70,7 +70,7 @@ ccxt/hyperliquid.py,sha256=ZHqoPUgMHPRsfEP3TaHhPHSFniAVZj7RBSHcfUxbUwQ,110702
70
70
  ccxt/idex.py,sha256=P2jNsxiwIlMgrfPKbtmjLJQrzFcWp_TjgJaLq793oco,73255
71
71
  ccxt/independentreserve.py,sha256=ChkSnahGsn0aN_cfaAonSk-V2Aa1UB-0cPTa1d3AdI4,37713
72
72
  ccxt/indodax.py,sha256=VdTGxm49I6s-DhT0H1NLFVJ1XYaDWpq51jP2tyK68Ks,54580
73
- ccxt/kraken.py,sha256=67FEfEmLONiFIHGIKKqlGInGHEtj-E1tMJPhuIU3ytM,131190
73
+ ccxt/kraken.py,sha256=G-ZCciNlUz1us3Q9O5HTdJ0qqX-pZuKeJQ_pRScdqpA,132889
74
74
  ccxt/krakenfutures.py,sha256=_-bbgzshifKnbyOB1pSs_bRfRepkRAdiDlsLDRiAw9w,119597
75
75
  ccxt/kucoin.py,sha256=rwv5bdlaeFAMbo2vYpT3_mX_keeJmz5Nk5HF26Br3vA,226576
76
76
  ccxt/kucoinfutures.py,sha256=bINtr0EBupNmE_IufzwRy7GuWHa5JtBmtrPk-WjhCno,124756
@@ -98,7 +98,7 @@ ccxt/probit.py,sha256=MFA0bFG-xEx3ZDQIWebUKaP83mCjYKVcztk3e61Zx8Y,76165
98
98
  ccxt/timex.py,sha256=Un10iGNwAHPifpQftyXdUwoqS-10ho6ZIesz2Ts_Iqg,72068
99
99
  ccxt/tokocrypto.py,sha256=aV-98hzr75iQO3GEmiUyTNufDqHfoze04Z2Fk195B3Q,123192
100
100
  ccxt/tradeogre.py,sha256=DCxTLjtGW7ADRA-jekCkGAn81-GIgdOAxbJFcBLYOFU,24211
101
- ccxt/upbit.py,sha256=W_W8aETJyopwhYfZd2tWvhPvi7BjQ4KSIOdn8nzyWv8,85413
101
+ ccxt/upbit.py,sha256=d03xZjLdhtMrqTVm3VYmvQoT7inmq05bjrUNrJLi_7U,85413
102
102
  ccxt/vertex.py,sha256=YoKnzxhem56C19SckA6yHUPH1bk86PfZ4Z-T01TFygg,121761
103
103
  ccxt/wavesexchange.py,sha256=vmzv9h1QjthvpKUGajQn_tdCJ5tWmzEA6r7ow_y6ASY,114980
104
104
  ccxt/wazirx.py,sha256=LVHNdononi8FrZpT0pYiJoS-NrNi7_uIZ6Qbu8dJRPc,52405
@@ -220,7 +220,7 @@ ccxt/abstract/xt.py,sha256=JkWvsic3L2O968BCr9H5Wd5NIbRE9aTT2A-9WbAtl0c,27146
220
220
  ccxt/abstract/yobit.py,sha256=8ycfCO8ORFly9hc0Aa47sZyX4_ZKPXS9h9yJzI-uQ7Q,1339
221
221
  ccxt/abstract/zaif.py,sha256=m15WHdl3gYy0GOXNZ8NEH8eE7sVh8c0T_ITNuU8vXeU,3935
222
222
  ccxt/abstract/zonda.py,sha256=X-hCW0SdX3YKZWixDyW-O2211M58Rno8kKJ6quY7rw4,7183
223
- ccxt/async_support/__init__.py,sha256=OTMV5dl0WDvk5khviRCYlf1X8txFz3TdcU9btAFysGo,16421
223
+ ccxt/async_support/__init__.py,sha256=Vm7pse5OpPcc48TgmJyEwJf5ATExfELuULdIZ8gYBPE,16504
224
224
  ccxt/async_support/ace.py,sha256=zBmLUKH691a2BH1sPzlJPg-uO7lD6Ys92Rv8WSzNtoo,42607
225
225
  ccxt/async_support/alpaca.py,sha256=495vDvdF1IWlsh9QhUnMtkMuINdD0EzeFGlUVqCf8TE,47682
226
226
  ccxt/async_support/ascendex.py,sha256=LK259BdUqU0_STGRH6DmTgaR-7lXqFpZHFVACf2um5c,152721
@@ -230,7 +230,7 @@ ccxt/async_support/binance.py,sha256=pzuysonW4qV1Q2_bIbNVWqm6SWgkCgKrGolvgqlfOEg
230
230
  ccxt/async_support/binancecoinm.py,sha256=yeE73xG5UXD_X3VPul6DMGnV_mgJfWYskpas1BUDdCU,1740
231
231
  ccxt/async_support/binanceus.py,sha256=c-K3Tk7LaRJjmYdCx8vBOqsx01uXrtvt0PC2ekBiD0g,9177
232
232
  ccxt/async_support/binanceusdm.py,sha256=8ugRkx7vyYmn67wdkEEf2f-DFMGAoC4t09usKlPVNyw,2670
233
- ccxt/async_support/bingx.py,sha256=U6ZHlGHPwJDMjitnXE5SOXFnLeKW-_ac-rJ1KdaT798,245477
233
+ ccxt/async_support/bingx.py,sha256=W9SEVvwqG75vY3mkSnsP1kAWB-aRq-lNWsL-nET8-6w,245745
234
234
  ccxt/async_support/bit2c.py,sha256=1s8GGFqdk9FHfG6-fCmJGePppIpHDHZkjN7u6gPekP8,37273
235
235
  ccxt/async_support/bitbank.py,sha256=To1wSMT8i2bVRZABSXIuB2pyeLhmKkE6CHP4i9LMQQU,43794
236
236
  ccxt/async_support/bitbay.py,sha256=jcaEXi2IhYTva8ezO_SfJhwxEZk7HST4J3NaxD16BQA,492
@@ -281,7 +281,7 @@ ccxt/async_support/fmfwio.py,sha256=lzfSnPrB2ARcC3EIqAuBM4vyg6LJ6n8RE71Zvt3ez1s,
281
281
  ccxt/async_support/gate.py,sha256=Y4dVM0if4e3a3uG_Wgj10t4oWRBHdjt-0Sp0v3yIWNg,329365
282
282
  ccxt/async_support/gateio.py,sha256=6_t032F9p9x5KGTjtSuqGXITzFOx-XAQBYLpsuQjzxw,459
283
283
  ccxt/async_support/gemini.py,sha256=7X5-PE3rPrPycUVXu3FtAcDFjNR3QUwYd6lPRQYQeEw,81389
284
- ccxt/async_support/hashkey.py,sha256=6URrypB6H5FFlV09t_qIorXRK983x2I274kr4qgCvqc,192549
284
+ ccxt/async_support/hashkey.py,sha256=bwQsEvhGU60iy_vlAbLvtx1blhDxS4L3cqoTpk6JNQ8,192580
285
285
  ccxt/async_support/hitbtc.py,sha256=jWmyRAy_wkpEidgjCxU0gWur99YJjYHPjD9CN4vJbUE,154444
286
286
  ccxt/async_support/hitbtc3.py,sha256=dmSYoD2o4av_zzbZI8HNIoj8BWxA7QozsVpy8JaOXzU,469
287
287
  ccxt/async_support/hollaex.py,sha256=msUnnbWLNeCxFW77BnfLoFWBdvQIDwV7Rtbi9TA4TYY,76574
@@ -292,7 +292,7 @@ ccxt/async_support/hyperliquid.py,sha256=Ct1KjpC9j4l-ul0r8RWpeeX-6bCdcXrNrrHpdNz
292
292
  ccxt/async_support/idex.py,sha256=UcAvdMc2CP_6E8lET4rmQiIP-RaUfZHSo6pQeA17v-g,73731
293
293
  ccxt/async_support/independentreserve.py,sha256=fCTAQ1U74KOZHIoYbDxzEly1xSgykcYcdpeiJiCEXkU,37991
294
294
  ccxt/async_support/indodax.py,sha256=S4qV7w3gMTRLnzahoCKR70oeRlpxOV3mXDdJw8XpIo8,54888
295
- ccxt/async_support/kraken.py,sha256=mOu4Ur2r2fs0HX61_SW5cG-IBNXcnDxHpBPDy0uJpz0,131840
295
+ ccxt/async_support/kraken.py,sha256=jSho6sFS0oWj4thiAy5AUENYwv2PUWCrXhv8QTZQicA,133539
296
296
  ccxt/async_support/krakenfutures.py,sha256=stPhBne9pFVlgFkw4mwqtaaI6NTZCAcmOIFVlQSbl8I,120085
297
297
  ccxt/async_support/kucoin.py,sha256=XAOfLEyRUeHfS3pB5elec6F1M_ryPyaEKZle2rPFZDM,227677
298
298
  ccxt/async_support/kucoinfutures.py,sha256=X6TMi-Bjv2mijE8xGbg-qp9Ha8Nl7o1Z5LjEiDgxaJ8,125394
@@ -320,7 +320,7 @@ ccxt/async_support/probit.py,sha256=8XCtYbAIIQNjfdLfMVwjaJ9vM_7QWnEQ86yYZYPlS8M,
320
320
  ccxt/async_support/timex.py,sha256=vRHjqc-6uMgZTY-sFTBApU_QBnrUri8gaHPNw_Na3Jo,72430
321
321
  ccxt/async_support/tokocrypto.py,sha256=nzJhrGTCTWMbbjI4P_IKfO1O84td8pSssCgZhTqQ7o4,123554
322
322
  ccxt/async_support/tradeogre.py,sha256=A4DEbbRL_g_5WAp7WOB96s08-zgXfGQ9lYZnDX5H1eI,24405
323
- ccxt/async_support/upbit.py,sha256=GmhV24xdjd5NSCronYkqLCM8rr_hNdpt4NEDA5jEkLw,85895
323
+ ccxt/async_support/upbit.py,sha256=r-7J61DYPXfCOa2-iks16MIiqF4IjfuIWQURyximwZ4,85895
324
324
  ccxt/async_support/vertex.py,sha256=_KDPAVq5Bew-w77wiGQpivZCGRs6yGKoW9HGh8PhOLc,122261
325
325
  ccxt/async_support/wavesexchange.py,sha256=wHxvsBQydDEYRgeAZKI9WO4TLBKmmSPTLm0eT0pKB5g,115530
326
326
  ccxt/async_support/wazirx.py,sha256=bnUpw9be3o4l2Hxm3jcfNXn5bMyZlgqoG8BGPusuIzs,52707
@@ -332,7 +332,7 @@ ccxt/async_support/yobit.py,sha256=GQhvYrsGHQrVdTrNHQxx9isEGqUABexlllzao9HL3f8,5
332
332
  ccxt/async_support/zaif.py,sha256=-ZTr8M2JaIRCL90VrbCDXBMAsZwbiwsFChSQ2rWODuQ,29044
333
333
  ccxt/async_support/zonda.py,sha256=jncr6Wg12S72CTpu6mCKCse1pm1f8oefVQurQSrFvP0,81733
334
334
  ccxt/async_support/base/__init__.py,sha256=aVYSsFi--b4InRs9zDN_wtCpj8odosAB726JdUHavrk,67
335
- ccxt/async_support/base/exchange.py,sha256=7InrcsiQ_iziBYFQeaz3jh5uQVO91wOQYNEdGLxRSoY,110829
335
+ ccxt/async_support/base/exchange.py,sha256=jgeL-bhvetlM4J6uw4Po0uwYDPkQOOvu-BVnIB0aia8,110829
336
336
  ccxt/async_support/base/throttler.py,sha256=tvDVcdRUVYi8fZRlEcnqtgzcgB_KMUMRs5Pu8tuU-tU,1847
337
337
  ccxt/async_support/base/ws/__init__.py,sha256=uockzpLuwntKGZbs5EOWFe-Zg-k6Cj7GhNJLc_RX0so,1791
338
338
  ccxt/async_support/base/ws/aiohttp_client.py,sha256=5IEiT0elWI9a7Vr-KV0jgmlbpLJWBzIlrLaCkTKGaqY,5752
@@ -345,11 +345,11 @@ ccxt/async_support/base/ws/order_book.py,sha256=uBUaIHhzMRykpmo4BCsdJ-t_HozS6Vxh
345
345
  ccxt/async_support/base/ws/order_book_side.py,sha256=GhnGUt78pJ-AYL_Dq9produGjmBJLCI5FHIRdMz1O-g,6551
346
346
  ccxt/base/__init__.py,sha256=eTx1OE3HJjspFUQjGm6LBhaQiMKJnXjkdP-JUXknyQ0,1320
347
347
  ccxt/base/decimal_to_precision.py,sha256=fgWRBzRTtsf3r2INyS4f7WHlzgjB5YM1ekiwqD21aac,6634
348
- ccxt/base/errors.py,sha256=khy0rlaZGU93pATGenSfHSdYk4f-HCMJpJz3VOTfw0E,4508
349
- ccxt/base/exchange.py,sha256=S-nlGv6bfr6QBro6qnCWVk5w-qiJMvgfM0xEXdco-8o,295934
348
+ ccxt/base/errors.py,sha256=Pad-6ugvGUwhoYuKUliX-N7FTrcnKCQGFjsaq2tMn0I,4610
349
+ ccxt/base/exchange.py,sha256=s-WBW9T0vec0fNdShtzvr2MmJrUs3cNK41cNWK1svYU,295934
350
350
  ccxt/base/precise.py,sha256=koce64Yrp6vFbGijJtUt-QQ6XhJgeGTCksZ871FPp_A,8886
351
351
  ccxt/base/types.py,sha256=TaP_RElKjGEZWuzyp4o4u2YhREyTG3rUeVT6gDffY9A,9613
352
- ccxt/pro/__init__.py,sha256=-TNPFwOmeOBAXR6pKevUnTc5BGNPtSwONwD-L1BPr5U,7710
352
+ ccxt/pro/__init__.py,sha256=iFX-TggS6GMZKPzfKjl73Bk_8b5vyqDCAcgMVw8HnlI,7710
353
353
  ccxt/pro/alpaca.py,sha256=xh1yg1Ok-Zh_Mfx-MBjNrfJDs6MUU0exFfEj3GuQPC4,27631
354
354
  ccxt/pro/ascendex.py,sha256=QueLgISoIxgGSOta2W7En4pwAsEXbTP5q5ef4UjpTQQ,37524
355
355
  ccxt/pro/bequant.py,sha256=33OEUWBi4D9-2w8CmkwN3aF1qS-AlLqX3pxrWwNbXPY,1552
@@ -361,7 +361,7 @@ ccxt/pro/bingx.py,sha256=Ji6EBezDtGbL2en15Syb2G1Ra9RcuJyaef5GxSHho20,54046
361
361
  ccxt/pro/bitcoincom.py,sha256=zAX6hiz4hS6Un8dSGp88rpnvItxQHfNmsfF0IZ2xIVA,1181
362
362
  ccxt/pro/bitfinex.py,sha256=m4ERTUt7QIZhAYu8NP818wOHSLRi2vK-_Z5-LXD8zjA,25257
363
363
  ccxt/pro/bitfinex2.py,sha256=kZVHZwfu1_E27p9Cx55uDVGcEPA6Oy-BQk8t2fbwOmg,43058
364
- ccxt/pro/bitget.py,sha256=r_c6hVH1fwVKLpxgRTZ9r9arIPEr3uRGBgHeI_6ZAtk,78915
364
+ ccxt/pro/bitget.py,sha256=-sK8WqkT1ddS6HLwp0Hr6kGKZ2ELqeW-FOt8IqCStnE,85233
365
365
  ccxt/pro/bithumb.py,sha256=dqYKWebxFg4rsP7jg3oBnCUBcpZAoqAmZsozAU9pYds,16835
366
366
  ccxt/pro/bitmart.py,sha256=LxcP6aiCdwN-euseCMhsXZkhqesPJM-eLh549sGHHfo,62556
367
367
  ccxt/pro/bitmex.py,sha256=dNQf2EAim7kxgCM6I1TgFDl-e2zrXa2veicTEqu8WbQ,73949
@@ -408,16 +408,16 @@ ccxt/pro/okcoin.py,sha256=elwHzrWUSuU7Edp1oisxAnvst5IpxjyzgqLVMEHZWIU,30429
408
408
  ccxt/pro/okx.py,sha256=rKAUOmT-BfnNzd7IPzgkgbeLJN2e29SOdLfrHboFbeM,85537
409
409
  ccxt/pro/onetrading.py,sha256=Qlr6LRRqO8te7QyTIhCk5nXJnupH8MtRWhQnH3Zc9yE,54769
410
410
  ccxt/pro/oxfun.py,sha256=gcmnoD0pzEDVIaiHyuU2ABoQBrxi0CTP62H2xZD0T7g,43943
411
- ccxt/pro/p2b.py,sha256=qulHrptdJ48MtOQ0bOZH3h_An8Ybu14cU6cJrySV5KQ,17897
411
+ ccxt/pro/p2b.py,sha256=K0aQNKqOWCgju0t-Am7mcIcAFXjIxYXiYft1gEOfw10,19227
412
412
  ccxt/pro/paradex.py,sha256=9SkO-QV08sGeh5e349hL36u4snxAYuqjdVvJlKgQhH0,14299
413
413
  ccxt/pro/phemex.py,sha256=ZFQLhlrFKxzoFziHAvM2G1pzf-goRYjdZ-ikVGfeNXw,61107
414
- ccxt/pro/poloniex.py,sha256=e81Vkvg2oRW51nXECf6lF7Cjj5CbHv7Np2QSy6z0h3k,52108
415
- ccxt/pro/poloniexfutures.py,sha256=Iy8Q_Z8I3rUtNcZoxwVzMK2C1qLIiHjFXdZd_rr3Sww,41972
416
- ccxt/pro/probit.py,sha256=ngY30aRwNClc_q_Pirajg4-K-mJ3bvipgD2-jBuPs6g,23110
417
- ccxt/pro/upbit.py,sha256=M3RwAXlK7Mbu8zduZK7eprLOfNgJax_xSPUhzXQ2zfY,22094
418
- ccxt/pro/vertex.py,sha256=sPo6hijgzFUIPqv3OcGuc6gf-MqdmXRRU8Zs13Zskl4,40532
419
- ccxt/pro/wazirx.py,sha256=LXpotTduk3fhtcJP2TWpssiOOAZGxhou5_MTK-0G7n0,30082
420
- ccxt/pro/whitebit.py,sha256=lpIDFgmVXtL77680Rz9hVTEXd3M6TsizhlFb0ruKfEM,35073
414
+ ccxt/pro/poloniex.py,sha256=QKpKOTW73iUQxaFXFZ_0KbyPFJhXtMWNNsfgP-CBeXU,53574
415
+ ccxt/pro/poloniexfutures.py,sha256=a3u8CIc7CuK04jU4PTLPVtGsw7omJ80KRopshziShYU,42020
416
+ ccxt/pro/probit.py,sha256=_oX1OHOd9M5D_fT2w3-zqACXouoUOFsbKxb6Ew3sNOk,23223
417
+ ccxt/pro/upbit.py,sha256=ViN4k89UDZykSOhSF_D0-Lt3ZwYDoBmzITC3oEyUA0s,24055
418
+ ccxt/pro/vertex.py,sha256=n0BFW9So4VxSsjv5vJbFCqeaq8cy-IVe_bw-zB1pC48,40580
419
+ ccxt/pro/wazirx.py,sha256=St9GkOg3vFZ4o3NySL_izzbrs4Kes2-1iS7iznDxZ6o,30247
420
+ ccxt/pro/whitebit.py,sha256=YZw5_BGvLFnadRDjOr5ELW2J6cok83nN77ctfBzfD1I,35689
421
421
  ccxt/pro/woo.py,sha256=TtGZVRdh0IDYICHYTBEgGMBsWm1SoX6aCokw-CMoKy0,48845
422
422
  ccxt/pro/woofipro.py,sha256=T4F82FqZ7BUISorgDVpQlRG5DsKjQ9augsk4Y4uLB4g,49102
423
423
  ccxt/pro/xt.py,sha256=AkO1NpgcKp6RAnB_asqMeYxoIE4psUsNiTHJtKuPxUU,48417
@@ -648,12 +648,12 @@ ccxt/static_dependencies/toolz/curried/operator.py,sha256=ML92mknkAwzBl2NCm-4wer
648
648
  ccxt/static_dependencies/typing_inspect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
649
649
  ccxt/static_dependencies/typing_inspect/typing_inspect.py,sha256=5gIWomLPfuDpgd3gX1GlnX0MuXM3VorR4j2W2qXORiQ,28269
650
650
  ccxt/test/__init__.py,sha256=GKPbEcj0Rrz5HG-GUm-iY1IHhDYmlvcBXZAGk6-m2CI,141
651
- ccxt/test/tests_async.py,sha256=HhP5BucP8hMg70-nacdBoln-hRNgcHCCWYLLYnwgKFk,83640
651
+ ccxt/test/tests_async.py,sha256=yVoLZLPkB-_ay0ab_oCyYOSwkLQkLXkPFj5jHTE3esw,84423
652
652
  ccxt/test/tests_helpers.py,sha256=xhOILoZ_x3RSfQjtKt6AQlkp9DkOtpTQe8GAUUZoM6s,10069
653
653
  ccxt/test/tests_init.py,sha256=eVwwUHujX9t4rjgo4TqEeg7DDhR1Hb_e2SJN8NVGyl0,998
654
- ccxt/test/tests_sync.py,sha256=wPQtbdsGyDh3wlgLCUDbIwQo2S32u2YZXXolvhZWNnU,82720
655
- ccxt-4.3.86.dist-info/LICENSE.txt,sha256=EIb9221AhMHV7xF1_55STFdKTFsnJVJYkRpY2Lnvo5w,1068
656
- ccxt-4.3.86.dist-info/METADATA,sha256=xnU6DYeVs6iB9CTp3PLK9ICEreAHNALZ17kZigjeWR4,118108
657
- ccxt-4.3.86.dist-info/WHEEL,sha256=z9j0xAa_JmUKMpmz72K0ZGALSM_n-wQVmGbleXx2VHg,110
658
- ccxt-4.3.86.dist-info/top_level.txt,sha256=CkQDuCTDKNcImPV60t36G6MdYfxsAPNiSaEwifVoVMo,5
659
- ccxt-4.3.86.dist-info/RECORD,,
654
+ ccxt/test/tests_sync.py,sha256=uu0QsWOuEpkmtV12nIffsiZZFUpM-f1k6W9nlgCDqXs,83485
655
+ ccxt-4.3.87.dist-info/LICENSE.txt,sha256=EIb9221AhMHV7xF1_55STFdKTFsnJVJYkRpY2Lnvo5w,1068
656
+ ccxt-4.3.87.dist-info/METADATA,sha256=qq7mohJ0qkb3LeP60YZIfW0KRAYgnO8Kz8aMYY1nmzQ,118342
657
+ ccxt-4.3.87.dist-info/WHEEL,sha256=z9j0xAa_JmUKMpmz72K0ZGALSM_n-wQVmGbleXx2VHg,110
658
+ ccxt-4.3.87.dist-info/top_level.txt,sha256=CkQDuCTDKNcImPV60t36G6MdYfxsAPNiSaEwifVoVMo,5
659
+ ccxt-4.3.87.dist-info/RECORD,,
File without changes