ccxt 4.3.69__py2.py3-none-any.whl → 4.3.71__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. ccxt/__init__.py +3 -1
  2. ccxt/abstract/coinbaseinternational.py +1 -1
  3. ccxt/abstract/paradex.py +40 -0
  4. ccxt/async_support/__init__.py +3 -1
  5. ccxt/async_support/base/exchange.py +1 -1
  6. ccxt/async_support/blofin.py +63 -6
  7. ccxt/async_support/bybit.py +1 -1
  8. ccxt/async_support/coinbaseinternational.py +155 -2
  9. ccxt/async_support/cryptocom.py +12 -1
  10. ccxt/async_support/paradex.py +1966 -0
  11. ccxt/async_support/poloniex.py +1 -0
  12. ccxt/async_support/woo.py +4 -2
  13. ccxt/base/exchange.py +63 -1
  14. ccxt/blofin.py +63 -6
  15. ccxt/bybit.py +1 -1
  16. ccxt/coinbaseinternational.py +155 -2
  17. ccxt/cryptocom.py +12 -1
  18. ccxt/paradex.py +1966 -0
  19. ccxt/poloniex.py +1 -0
  20. ccxt/pro/__init__.py +5 -1
  21. ccxt/pro/bequant.py +4 -0
  22. ccxt/pro/blofin.py +608 -0
  23. ccxt/pro/coinbaseinternational.py +142 -11
  24. ccxt/pro/cryptocom.py +4 -1
  25. ccxt/pro/hitbtc.py +20 -8
  26. ccxt/pro/okx.py +6 -0
  27. ccxt/pro/paradex.py +340 -0
  28. ccxt/pro/poloniex.py +32 -10
  29. ccxt/pro/woo.py +5 -4
  30. ccxt/static_dependencies/__init__.py +1 -1
  31. ccxt/static_dependencies/lark/__init__.py +38 -0
  32. ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  33. ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  34. ccxt/static_dependencies/lark/ast_utils.py +59 -0
  35. ccxt/static_dependencies/lark/common.py +86 -0
  36. ccxt/static_dependencies/lark/exceptions.py +292 -0
  37. ccxt/static_dependencies/lark/grammar.py +130 -0
  38. ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  39. ccxt/static_dependencies/lark/indenter.py +143 -0
  40. ccxt/static_dependencies/lark/lark.py +658 -0
  41. ccxt/static_dependencies/lark/lexer.py +678 -0
  42. ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  43. ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  44. ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  45. ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  46. ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  47. ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  48. ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  49. ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  50. ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  51. ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  52. ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  53. ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  54. ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  55. ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  56. ccxt/static_dependencies/lark/py.typed +0 -0
  57. ccxt/static_dependencies/lark/reconstruct.py +107 -0
  58. ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  59. ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  60. ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  61. ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  62. ccxt/static_dependencies/lark/tree.py +267 -0
  63. ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  64. ccxt/static_dependencies/lark/tree_templates.py +180 -0
  65. ccxt/static_dependencies/lark/utils.py +343 -0
  66. ccxt/static_dependencies/lark/visitors.py +596 -0
  67. ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  68. ccxt/static_dependencies/marshmallow/base.py +65 -0
  69. ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  70. ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  71. ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  72. ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  73. ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  74. ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  75. ccxt/static_dependencies/marshmallow/py.typed +0 -0
  76. ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  77. ccxt/static_dependencies/marshmallow/types.py +12 -0
  78. ccxt/static_dependencies/marshmallow/utils.py +378 -0
  79. ccxt/static_dependencies/marshmallow/validate.py +678 -0
  80. ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  81. ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  82. ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  83. ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  84. ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  85. ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
  86. ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  87. ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  88. ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  89. ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  90. ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
  91. ccxt/static_dependencies/starknet/__init__.py +0 -0
  92. ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  93. ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  94. ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  95. ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  96. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  97. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  98. ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  99. ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  100. ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  101. ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  102. ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  103. ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  104. ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  105. ccxt/static_dependencies/starknet/common.py +15 -0
  106. ccxt/static_dependencies/starknet/constants.py +39 -0
  107. ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  108. ccxt/static_dependencies/starknet/hash/address.py +79 -0
  109. ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  110. ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  111. ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  112. ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  113. ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  114. ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  115. ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  116. ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  117. ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  118. ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  119. ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  120. ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  121. ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  122. ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  123. ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  124. ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  125. ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  126. ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  127. ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  128. ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  129. ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  130. ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  131. ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  132. ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  133. ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  134. ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  135. ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  136. ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  137. ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  138. ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  139. ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  140. ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  141. ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  142. ccxt/static_dependencies/sympy/__init__.py +0 -0
  143. ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  144. ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  145. ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  146. ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  147. ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  148. ccxt/static_dependencies/typing_extensions/__init__.py +0 -0
  149. ccxt/static_dependencies/typing_extensions/typing_extensions.py +3839 -0
  150. ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  151. ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  152. ccxt/test/tests_async.py +43 -1
  153. ccxt/test/tests_sync.py +43 -1
  154. ccxt/woo.py +4 -2
  155. {ccxt-4.3.69.dist-info → ccxt-4.3.71.dist-info}/METADATA +8 -7
  156. {ccxt-4.3.69.dist-info → ccxt-4.3.71.dist-info}/RECORD +159 -33
  157. {ccxt-4.3.69.dist-info → ccxt-4.3.71.dist-info}/LICENSE.txt +0 -0
  158. {ccxt-4.3.69.dist-info → ccxt-4.3.71.dist-info}/WHEEL +0 -0
  159. {ccxt-4.3.69.dist-info → ccxt-4.3.71.dist-info}/top_level.txt +0 -0
@@ -4,9 +4,9 @@
4
4
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
5
 
6
6
  import ccxt.async_support
7
- from ccxt.async_support.base.ws.cache import ArrayCache
7
+ from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheByTimestamp
8
8
  import hashlib
9
- from ccxt.base.types import Int, Market, OrderBook, Strings, Ticker, FundingRate, FundingRates, Trade
9
+ from ccxt.base.types import Int, Market, OrderBook, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade
10
10
  from ccxt.async_support.base.ws.client import Client
11
11
  from typing import List
12
12
  from ccxt.base.errors import ExchangeError
@@ -27,12 +27,12 @@ class coinbaseinternational(ccxt.async_support.coinbaseinternational):
27
27
  'watchTicker': True,
28
28
  'watchBalance': False,
29
29
  'watchMyTrades': False,
30
- 'watchOHLCV': False,
30
+ 'watchOHLCV': True,
31
31
  'watchOHLCVForSymbols': False,
32
32
  'watchOrders': False,
33
33
  'watchOrdersForSymbols': False,
34
34
  'watchPositions': False,
35
- 'watchTickers': False,
35
+ 'watchTickers': True,
36
36
  'createOrderWs': False,
37
37
  'editOrderWs': False,
38
38
  'cancelOrderWs': False,
@@ -58,6 +58,14 @@ class coinbaseinternational(ccxt.async_support.coinbaseinternational):
58
58
  'tradesLimit': 1000,
59
59
  'ordersLimit': 1000,
60
60
  'myTradesLimit': 1000,
61
+ 'timeframes': {
62
+ '1m': 'CANDLES_ONE_MINUTE',
63
+ '5m': 'CANDLES_FIVE_MINUTES',
64
+ '30m': 'CANDLES_THIRTY_MINUTES',
65
+ '1h': 'CANDLES_ONE_HOUR',
66
+ '2h': 'CANDLES_TWO_HOURS',
67
+ '1d': 'CANDLES_ONE_DAY',
68
+ },
61
69
  },
62
70
  'exceptions': {
63
71
  'exact': {
@@ -80,15 +88,18 @@ class coinbaseinternational(ccxt.async_support.coinbaseinternational):
80
88
  self.check_required_credentials()
81
89
  market = None
82
90
  messageHash = name
83
- productIds = []
91
+ productIds = None
84
92
  if symbols is None:
85
- symbols = self.symbols
93
+ symbols = self.get_active_symbols()
86
94
  symbolsLength = len(symbols)
95
+ messageHashes = []
87
96
  if symbolsLength > 1:
88
97
  parsedSymbols = self.market_symbols(symbols)
89
98
  marketIds = self.market_ids(parsedSymbols)
90
99
  productIds = marketIds
91
- messageHash = messageHash + '::' + ','.join(parsedSymbols)
100
+ for i in range(0, len(parsedSymbols)):
101
+ messageHashes.append(name + '::' + parsedSymbols[i])
102
+ # messageHash = messageHash + '::' + ','.join(parsedSymbols)
92
103
  elif symbolsLength == 1:
93
104
  market = self.market(symbols[0])
94
105
  messageHash = name + '::' + market['symbol']
@@ -101,13 +112,17 @@ class coinbaseinternational(ccxt.async_support.coinbaseinternational):
101
112
  signature = self.hmac(self.encode(auth), self.base64_to_binary(self.secret), hashlib.sha256, 'base64')
102
113
  subscribe: dict = {
103
114
  'type': 'SUBSCRIBE',
104
- 'product_ids': productIds,
115
+ # 'product_ids': productIds,
105
116
  'channels': [name],
106
117
  'time': timestamp,
107
118
  'key': self.apiKey,
108
119
  'passphrase': self.password,
109
120
  'signature': signature,
110
121
  }
122
+ if productIds is not None:
123
+ subscribe['product_ids'] = productIds
124
+ if symbolsLength > 1:
125
+ return await self.watch_multiple(url, messageHashes, self.extend(subscribe, params), messageHashes)
111
126
  return await self.watch(url, messageHash, self.extend(subscribe, params), messageHash)
112
127
 
113
128
  async def subscribe_multiple(self, name: str, symbols: Strings = None, params={}):
@@ -184,6 +199,7 @@ class coinbaseinternational(ccxt.async_support.coinbaseinternational):
184
199
  :see: https://docs.cloud.coinbase.com/intx/docs/websocket-channels#instruments-channel
185
200
  :param str [symbol]: unified symbol of the market to fetch the ticker for
186
201
  :param dict [params]: extra parameters specific to the exchange API endpoint
202
+ :param str [params.channel]: the channel to watch, 'LEVEL1' or 'INSTRUMENTS', default is 'LEVEL1'
187
203
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
188
204
  """
189
205
  await self.load_markets()
@@ -191,6 +207,35 @@ class coinbaseinternational(ccxt.async_support.coinbaseinternational):
191
207
  channel, params = self.handle_option_and_params(params, 'watchTicker', 'channel', 'LEVEL1')
192
208
  return await self.subscribe(channel, [symbol], params)
193
209
 
210
+ def get_active_symbols(self):
211
+ symbols = self.symbols
212
+ output = []
213
+ for i in range(0, len(symbols)):
214
+ symbol = symbols[i]
215
+ market = self.markets[symbol]
216
+ if market['active']:
217
+ output.append(symbol)
218
+ return output
219
+
220
+ async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
221
+ """
222
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
223
+ :see: https://docs.cloud.coinbase.com/intx/docs/websocket-channels#instruments-channel
224
+ :param str[] [symbols]: unified symbol of the market to fetch the ticker for
225
+ :param dict [params]: extra parameters specific to the exchange API endpoint
226
+ :param str [params.channel]: the channel to watch, 'LEVEL1' or 'INSTRUMENTS', default is 'INSTLEVEL1UMENTS'
227
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
228
+ """
229
+ await self.load_markets()
230
+ channel = None
231
+ channel, params = self.handle_option_and_params(params, 'watchTickers', 'channel', 'LEVEL1')
232
+ ticker = await self.subscribe(channel, symbols, params)
233
+ if self.newUpdates:
234
+ result: dict = {}
235
+ result[ticker['symbol']] = ticker
236
+ return result
237
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
238
+
194
239
  def handle_instrument(self, client: Client, message):
195
240
  #
196
241
  # {
@@ -248,6 +293,33 @@ class coinbaseinternational(ccxt.async_support.coinbaseinternational):
248
293
  # "channel":"INSTRUMENTS",
249
294
  # "type":"SNAPSHOT"
250
295
  # }
296
+ # instruments
297
+ # {
298
+ # sequence: 0,
299
+ # instrument_type: 'PERP',
300
+ # instrument_mode: 'standard',
301
+ # base_asset_name: 'BTC',
302
+ # quote_asset_name: 'USDC',
303
+ # base_increment: '0.0001',
304
+ # quote_increment: '0.1',
305
+ # avg_daily_quantity: '502.8845',
306
+ # avg_daily_volume: '3.1495242961566668E7',
307
+ # total30_day_quantity: '15086.535',
308
+ # total30_day_volume: '9.44857288847E8',
309
+ # total24_hour_quantity: '5.0',
310
+ # total24_hour_volume: '337016.5',
311
+ # base_imf: '0.1',
312
+ # min_quantity: '0.0001',
313
+ # position_size_limit: '800',
314
+ # funding_interval: '3600000000000',
315
+ # trading_state: 'trading',
316
+ # last_updated_time: '2024-07-30T15:00:00Z',
317
+ # default_initial_margin: '0.2',
318
+ # base_asset_multiplier: '1.0',
319
+ # channel: 'INSTRUMENTS',
320
+ # type: 'SNAPSHOT',
321
+ # time: '2024-07-30T15:26:56.766Z',
322
+ # }
251
323
  #
252
324
  marketId = self.safe_string(ticker, 'product_id')
253
325
  datetime = self.safe_string(ticker, 'time')
@@ -270,8 +342,8 @@ class coinbaseinternational(ccxt.async_support.coinbaseinternational):
270
342
  'change': None,
271
343
  'percentage': None,
272
344
  'average': None,
273
- 'baseVolume': self.safe_string(ticker, 'total_24_hour_quantity'),
274
- 'quoteVolume': self.safe_string(ticker, 'total_24_hour_volume'),
345
+ 'baseVolume': self.safe_string_2(ticker, 'total_24_hour_quantity', 'total24_hour_quantity'),
346
+ 'quoteVolume': self.safe_string_2(ticker, 'total_24_hour_volume', 'total24_hour_volume'),
275
347
  })
276
348
 
277
349
  def handle_ticker(self, client: Client, message):
@@ -343,6 +415,63 @@ class coinbaseinternational(ccxt.async_support.coinbaseinternational):
343
415
  'previousClose': None,
344
416
  })
345
417
 
418
+ async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
419
+ """
420
+ watches historical candlestick data containing the open, high, low, close price, and the volume of a market
421
+ :see: https://docs.cdp.coinbase.com/intx/docs/websocket-channels#candles-channel
422
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
423
+ :param str timeframe: the length of time each candle represents
424
+ :param int [since]: timestamp in ms of the earliest candle to fetch
425
+ :param int [limit]: the maximum amount of candles to fetch
426
+ :param dict [params]: extra parameters specific to the exchange API endpoint
427
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
428
+ """
429
+ await self.load_markets()
430
+ market = self.market(symbol)
431
+ symbol = market['symbol']
432
+ options = self.safe_dict(self.options, 'timeframes', {})
433
+ interval = self.safe_string(options, timeframe, timeframe)
434
+ ohlcv = await self.subscribe(interval, [symbol], params)
435
+ if self.newUpdates:
436
+ limit = ohlcv.getLimit(symbol, limit)
437
+ return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
438
+
439
+ def handle_ohlcv(self, client: Client, message):
440
+ #
441
+ # {
442
+ # "sequence": 0,
443
+ # "product_id": "BTC-PERP",
444
+ # "channel": "CANDLES_ONE_MINUTE",
445
+ # "type": "SNAPSHOT",
446
+ # "candles": [
447
+ # {
448
+ # "time": "2023-05-10T14:58:47.000Z",
449
+ # "low": "28787.8",
450
+ # "high": "28788.8",
451
+ # "open": "28788.8",
452
+ # "close": "28787.8",
453
+ # "volume": "0.466"
454
+ # },
455
+ # ]
456
+ # }
457
+ #
458
+ messageHash = self.safe_string(message, 'channel')
459
+ marketId = self.safe_string(message, 'product_id')
460
+ market = self.safe_market(marketId)
461
+ symbol = market['symbol']
462
+ timeframe = self.find_timeframe(messageHash)
463
+ self.ohlcvs[symbol] = self.safe_value(self.ohlcvs, symbol, {})
464
+ if self.safe_value(self.ohlcvs[symbol], timeframe) is None:
465
+ limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
466
+ self.ohlcvs[symbol][timeframe] = ArrayCacheByTimestamp(limit)
467
+ stored = self.ohlcvs[symbol][timeframe]
468
+ data = self.safe_list(message, 'candles', [])
469
+ for i in range(0, len(data)):
470
+ tick = data[i]
471
+ parsed = self.parse_ohlcv(tick, market)
472
+ stored.append(parsed)
473
+ client.resolve(stored, messageHash + '::' + symbol)
474
+
346
475
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
347
476
  """
348
477
  get the list of most recent trades for a particular symbol
@@ -606,7 +735,7 @@ class coinbaseinternational(ccxt.async_support.coinbaseinternational):
606
735
  def handle_message(self, client, message):
607
736
  if self.handle_error_message(client, message):
608
737
  return
609
- channel = self.safe_string(message, 'channel')
738
+ channel = self.safe_string(message, 'channel', '')
610
739
  methods: dict = {
611
740
  'SUBSCRIPTIONS': self.handle_subscription_status,
612
741
  'INSTRUMENTS': self.handle_instrument,
@@ -620,6 +749,8 @@ class coinbaseinternational(ccxt.async_support.coinbaseinternational):
620
749
  if type == 'error':
621
750
  errorMessage = self.safe_string(message, 'message')
622
751
  raise ExchangeError(errorMessage)
752
+ if channel.find('CANDLES') > -1:
753
+ self.handle_ohlcv(client, message)
623
754
  method = self.safe_value(methods, channel)
624
755
  if method is not None:
625
756
  method(client, message)
ccxt/pro/cryptocom.py CHANGED
@@ -9,6 +9,7 @@ import hashlib
9
9
  from ccxt.base.types import Balances, Int, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Trade
10
10
  from ccxt.async_support.base.ws.client import Client
11
11
  from typing import List
12
+ from ccxt.base.errors import ExchangeError
12
13
  from ccxt.base.errors import AuthenticationError
13
14
  from ccxt.base.errors import NetworkError
14
15
  from ccxt.base.errors import ChecksumError
@@ -827,6 +828,7 @@ class cryptocom(ccxt.async_support.cryptocom):
827
828
  # "message": "invalid channel {"channels":["trade.BTCUSD-PERP"]}"
828
829
  # }
829
830
  #
831
+ id = self.safe_string(message, 'id')
830
832
  errorCode = self.safe_string(message, 'code')
831
833
  try:
832
834
  if errorCode and errorCode != '0':
@@ -835,6 +837,7 @@ class cryptocom(ccxt.async_support.cryptocom):
835
837
  messageString = self.safe_value(message, 'message')
836
838
  if messageString is not None:
837
839
  self.throw_broadly_matched_exception(self.exceptions['broad'], messageString, feedback)
840
+ raise ExchangeError(feedback)
838
841
  return False
839
842
  except Exception as e:
840
843
  if isinstance(e, AuthenticationError):
@@ -843,7 +846,7 @@ class cryptocom(ccxt.async_support.cryptocom):
843
846
  if messageHash in client.subscriptions:
844
847
  del client.subscriptions[messageHash]
845
848
  else:
846
- client.reject(e)
849
+ client.reject(e, id)
847
850
  return True
848
851
 
849
852
  def handle_subscribe(self, client: Client, message):
ccxt/pro/hitbtc.py CHANGED
@@ -1137,7 +1137,8 @@ class hitbtc(ccxt.async_support.hitbtc):
1137
1137
  return message
1138
1138
 
1139
1139
  def handle_message(self, client: Client, message):
1140
- self.handle_error(client, message)
1140
+ if self.handle_error(client, message):
1141
+ return
1141
1142
  channel = self.safe_string_2(message, 'ch', 'method')
1142
1143
  if channel is not None:
1143
1144
  splitChannel = channel.split('/')
@@ -1206,11 +1207,22 @@ class hitbtc(ccxt.async_support.hitbtc):
1206
1207
  #
1207
1208
  error = self.safe_value(message, 'error')
1208
1209
  if error is not None:
1209
- code = self.safe_value(error, 'code')
1210
- errorMessage = self.safe_string(error, 'message')
1211
- description = self.safe_string(error, 'description')
1212
- feedback = self.id + ' ' + description
1213
- self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
1214
- self.throw_broadly_matched_exception(self.exceptions['broad'], errorMessage, feedback)
1215
- raise ExchangeError(feedback) # unknown message
1210
+ try:
1211
+ code = self.safe_value(error, 'code')
1212
+ errorMessage = self.safe_string(error, 'message')
1213
+ description = self.safe_string(error, 'description')
1214
+ feedback = self.id + ' ' + description
1215
+ self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
1216
+ self.throw_broadly_matched_exception(self.exceptions['broad'], errorMessage, feedback)
1217
+ raise ExchangeError(feedback) # unknown message
1218
+ except Exception as e:
1219
+ if isinstance(e, AuthenticationError):
1220
+ messageHash = 'authenticated'
1221
+ client.reject(e, messageHash)
1222
+ if messageHash in client.subscriptions:
1223
+ del client.subscriptions[messageHash]
1224
+ else:
1225
+ id = self.safe_string(message, 'id')
1226
+ client.reject(e, id)
1227
+ return True
1216
1228
  return None
ccxt/pro/okx.py CHANGED
@@ -1764,6 +1764,12 @@ class okx(ccxt.async_support.okx):
1764
1764
  self.throw_broadly_matched_exception(self.exceptions['broad'], messageString, feedback)
1765
1765
  raise ExchangeError(feedback)
1766
1766
  except Exception as e:
1767
+ # if the message contains an id, it means it is a response to a request
1768
+ # so we only reject that promise, instead of deleting all futures, destroying the authentication future
1769
+ id = self.safe_string(message, 'id')
1770
+ if id is not None:
1771
+ client.reject(e, id)
1772
+ return False
1767
1773
  client.reject(e)
1768
1774
  return False
1769
1775
  return message