ccxt 4.3.68__py2.py3-none-any.whl → 4.3.70__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.

Potentially problematic release.


This version of ccxt might be problematic. Click here for more details.

Files changed (68) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/coinbaseinternational.py +1 -1
  3. ccxt/async_support/__init__.py +1 -1
  4. ccxt/async_support/base/exchange.py +1 -1
  5. ccxt/async_support/binance.py +2 -2
  6. ccxt/async_support/bingx.py +129 -73
  7. ccxt/async_support/bitget.py +2 -2
  8. ccxt/async_support/bitmart.py +2 -2
  9. ccxt/async_support/bitrue.py +2 -2
  10. ccxt/async_support/blofin.py +63 -6
  11. ccxt/async_support/btcbox.py +1 -1
  12. ccxt/async_support/bybit.py +3 -3
  13. ccxt/async_support/coinbaseinternational.py +227 -3
  14. ccxt/async_support/coinex.py +2 -2
  15. ccxt/async_support/coinlist.py +2 -2
  16. ccxt/async_support/cryptocom.py +12 -1
  17. ccxt/async_support/deribit.py +2 -2
  18. ccxt/async_support/digifinex.py +2 -2
  19. ccxt/async_support/hyperliquid.py +0 -2
  20. ccxt/async_support/kucoin.py +11 -5
  21. ccxt/async_support/latoken.py +2 -2
  22. ccxt/async_support/mexc.py +2 -2
  23. ccxt/async_support/okx.py +2 -2
  24. ccxt/async_support/oxfun.py +1 -1
  25. ccxt/async_support/phemex.py +2 -2
  26. ccxt/async_support/poloniex.py +34 -33
  27. ccxt/async_support/poloniexfutures.py +26 -26
  28. ccxt/async_support/woo.py +2 -2
  29. ccxt/base/exchange.py +334 -117
  30. ccxt/base/types.py +21 -3
  31. ccxt/binance.py +2 -2
  32. ccxt/bingx.py +129 -73
  33. ccxt/bitget.py +2 -2
  34. ccxt/bitmart.py +2 -2
  35. ccxt/bitrue.py +2 -2
  36. ccxt/blofin.py +63 -6
  37. ccxt/btcbox.py +1 -1
  38. ccxt/bybit.py +3 -3
  39. ccxt/coinbaseinternational.py +227 -3
  40. ccxt/coinex.py +2 -2
  41. ccxt/coinlist.py +2 -2
  42. ccxt/cryptocom.py +12 -1
  43. ccxt/deribit.py +2 -2
  44. ccxt/digifinex.py +2 -2
  45. ccxt/hyperliquid.py +0 -2
  46. ccxt/kucoin.py +11 -5
  47. ccxt/latoken.py +2 -2
  48. ccxt/mexc.py +2 -2
  49. ccxt/okx.py +2 -2
  50. ccxt/oxfun.py +1 -1
  51. ccxt/phemex.py +2 -2
  52. ccxt/poloniex.py +34 -33
  53. ccxt/poloniexfutures.py +26 -26
  54. ccxt/pro/__init__.py +3 -1
  55. ccxt/pro/blofin.py +608 -0
  56. ccxt/pro/coinbaseinternational.py +142 -11
  57. ccxt/pro/cryptocom.py +4 -1
  58. ccxt/pro/hitbtc.py +20 -8
  59. ccxt/pro/okx.py +6 -0
  60. ccxt/pro/poloniex.py +45 -23
  61. ccxt/pro/poloniexfutures.py +5 -5
  62. ccxt/pro/woo.py +5 -4
  63. ccxt/woo.py +2 -2
  64. {ccxt-4.3.68.dist-info → ccxt-4.3.70.dist-info}/METADATA +7 -7
  65. {ccxt-4.3.68.dist-info → ccxt-4.3.70.dist-info}/RECORD +68 -67
  66. {ccxt-4.3.68.dist-info → ccxt-4.3.70.dist-info}/LICENSE.txt +0 -0
  67. {ccxt-4.3.68.dist-info → ccxt-4.3.70.dist-info}/WHEEL +0 -0
  68. {ccxt-4.3.68.dist-info → ccxt-4.3.70.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
ccxt/pro/poloniex.py CHANGED
@@ -86,7 +86,7 @@ class poloniex(ccxt.async_support.poloniex):
86
86
  """
87
87
  * @ignore
88
88
  authenticates the user to access private web socket channels
89
- :see: https://docs.poloniex.com/#authenticated-channels-market-data-authentication
89
+ :see: https://api-docs.poloniex.com/spot/websocket/authentication
90
90
  :returns dict: response from exchange
91
91
  """
92
92
  self.check_required_credentials()
@@ -184,7 +184,7 @@ class poloniex(ccxt.async_support.poloniex):
184
184
 
185
185
  async def create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
186
186
  """
187
- :see: https://docs.poloniex.com/#authenticated-channels-trade-requests-create-order
187
+ :see: https://api-docs.poloniex.com/spot/websocket/trade-request#create-order
188
188
  create a trade order
189
189
  :param str symbol: unified symbol of the market to create an order in
190
190
  :param str type: 'market' or 'limit'
@@ -243,7 +243,7 @@ class poloniex(ccxt.async_support.poloniex):
243
243
 
244
244
  async def cancel_order_ws(self, id: str, symbol: Str = None, params={}):
245
245
  """
246
- :see: https://docs.poloniex.com/#authenticated-channels-trade-requests-cancel-multiple-orders
246
+ :see: https://api-docs.poloniex.com/spot/websocket/trade-request#cancel-multiple-orders
247
247
  cancel multiple orders
248
248
  :param str id: order id
249
249
  :param str [symbol]: unified market symbol
@@ -259,7 +259,7 @@ class poloniex(ccxt.async_support.poloniex):
259
259
 
260
260
  async def cancel_orders_ws(self, ids: List[str], symbol: Str = None, params={}):
261
261
  """
262
- :see: https://docs.poloniex.com/#authenticated-channels-trade-requests-cancel-multiple-orders
262
+ :see: https://api-docs.poloniex.com/spot/websocket/trade-request#cancel-multiple-orders
263
263
  cancel multiple orders
264
264
  :param str[] ids: order ids
265
265
  :param str symbol: unified market symbol, default is None
@@ -276,7 +276,7 @@ class poloniex(ccxt.async_support.poloniex):
276
276
 
277
277
  async def cancel_all_orders_ws(self, symbol: Str = None, params={}):
278
278
  """
279
- :see: https://docs.poloniex.com/#authenticated-channels-trade-requests-cancel-all-orders
279
+ :see: https://api-docs.poloniex.com/spot/websocket/trade-request#cancel-all-orders
280
280
  cancel all open orders of a type. Only applicable to Option in Portfolio Margin mode, and MMP privilege is required.
281
281
  :param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
282
282
  :param dict [params]: extra parameters specific to the poloniex api endpoint
@@ -310,7 +310,7 @@ class poloniex(ccxt.async_support.poloniex):
310
310
  async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
311
311
  """
312
312
  watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
313
- :see: https://docs.poloniex.com/#public-channels-market-data-candlesticks
313
+ :see: https://api-docs.poloniex.com/spot/websocket/market-data#candlesticks
314
314
  :param str symbol: unified symbol of the market to fetch OHLCV data for
315
315
  :param str timeframe: the length of time each candle represents
316
316
  :param int [since]: timestamp in ms of the earliest candle to fetch
@@ -331,7 +331,7 @@ class poloniex(ccxt.async_support.poloniex):
331
331
  async def watch_ticker(self, symbol: str, params={}) -> Ticker:
332
332
  """
333
333
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
334
- :see: https://docs.poloniex.com/#public-channels-market-data-ticker
334
+ :see: https://api-docs.poloniex.com/spot/websocket/market-data#ticker
335
335
  :param str symbol: unified symbol of the market to fetch the ticker for
336
336
  :param dict [params]: extra parameters specific to the exchange API endpoint
337
337
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -344,7 +344,7 @@ class poloniex(ccxt.async_support.poloniex):
344
344
  async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
345
345
  """
346
346
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
347
- :see: https://docs.poloniex.com/#public-channels-market-data-ticker
347
+ :see: https://api-docs.poloniex.com/spot/websocket/market-data#ticker
348
348
  :param str symbol: unified symbol of the market to fetch the ticker for
349
349
  :param dict [params]: extra parameters specific to the exchange API endpoint
350
350
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -360,7 +360,7 @@ class poloniex(ccxt.async_support.poloniex):
360
360
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
361
361
  """
362
362
  get the list of most recent trades for a particular symbol
363
- :see: https://docs.poloniex.com/#public-channels-market-data-trades
363
+ :see: https://api-docs.poloniex.com/spot/websocket/market-data#trades
364
364
  :param str symbol: unified symbol of the market to fetch trades for
365
365
  :param int [since]: timestamp in ms of the earliest trade to fetch
366
366
  :param int [limit]: the maximum amount of trades to fetch
@@ -378,7 +378,7 @@ class poloniex(ccxt.async_support.poloniex):
378
378
  async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
379
379
  """
380
380
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
381
- :see: https://docs.poloniex.com/#public-channels-market-data-book-level-2
381
+ :see: https://api-docs.poloniex.com/spot/websocket/market-data#book-level-2
382
382
  :param str symbol: unified symbol of the market to fetch the order book for
383
383
  :param int [limit]: not used by poloniex watchOrderBook
384
384
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -394,7 +394,7 @@ class poloniex(ccxt.async_support.poloniex):
394
394
  async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
395
395
  """
396
396
  watches information on multiple orders made by the user
397
- :see: https://docs.poloniex.com/#authenticated-channels-market-data-orders
397
+ :see: https://api-docs.poloniex.com/spot/websocket/order
398
398
  :param str symbol: unified market symbol of the market orders were made in
399
399
  :param int [since]: not used by poloniex watchOrders
400
400
  :param int [limit]: not used by poloniex watchOrders
@@ -415,7 +415,7 @@ class poloniex(ccxt.async_support.poloniex):
415
415
  async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
416
416
  """
417
417
  watches information on multiple trades made by the user using orders stream
418
- :see: https://docs.poloniex.com/#authenticated-channels-market-data-orders
418
+ :see: https://api-docs.poloniex.com/spot/websocket/order
419
419
  :param str symbol: unified market symbol of the market orders were made in
420
420
  :param int [since]: not used by poloniex watchMyTrades
421
421
  :param int [limit]: not used by poloniex watchMyTrades
@@ -437,7 +437,7 @@ class poloniex(ccxt.async_support.poloniex):
437
437
  async def watch_balance(self, params={}) -> Balances:
438
438
  """
439
439
  watch balance and get the amount of funds available for trading or funds locked in orders
440
- :see: https://docs.poloniex.com/#authenticated-channels-market-data-balances
440
+ :see: https://api-docs.poloniex.com/spot/websocket/balance
441
441
  :param dict [params]: extra parameters specific to the exchange API endpoint
442
442
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
443
443
  """
@@ -1100,13 +1100,7 @@ class poloniex(ccxt.async_support.poloniex):
1100
1100
  if type == 'auth':
1101
1101
  self.handle_authenticate(client, message)
1102
1102
  elif type is None:
1103
- data = self.safe_value(message, 'data')
1104
- item = self.safe_value(data, 0)
1105
- orderId = self.safe_string(item, 'orderId')
1106
- if orderId == '0':
1107
- self.handle_error_message(client, item)
1108
- else:
1109
- self.handle_order_request(client, message)
1103
+ self.handle_order_request(client, message)
1110
1104
  else:
1111
1105
  data = self.safe_value(message, 'data', [])
1112
1106
  dataLength = len(data)
@@ -1131,12 +1125,40 @@ class poloniex(ccxt.async_support.poloniex):
1131
1125
  # "event": "error",
1132
1126
  # "message": "Platform in maintenance mode"
1133
1127
  # }
1128
+ # {
1129
+ # "id":"1722386782048",
1130
+ # "data":[
1131
+ # {
1132
+ # "orderId":0,
1133
+ # "clientOrderId":null,
1134
+ # "message":"available insufficient",
1135
+ # "code":21721
1136
+ # }
1137
+ # ]
1138
+ # }
1134
1139
  #
1140
+ id = self.safe_string(message, 'id')
1135
1141
  event = self.safe_string(message, 'event')
1136
- orderId = self.safe_string(message, 'orderId')
1142
+ data = self.safe_list(message, 'data')
1143
+ first = self.safe_dict(data, 0)
1144
+ orderId = self.safe_string(first, 'orderId')
1137
1145
  if (event == 'error') or (orderId == '0'):
1138
- error = self.safe_string(message, 'message')
1139
- raise ExchangeError(self.id + ' error: ' + self.json(error))
1146
+ try:
1147
+ error = self.safe_string(first, 'message')
1148
+ code = self.safe_string(first, 'code')
1149
+ feedback = self.id + ' ' + self.json(message)
1150
+ self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
1151
+ self.throw_broadly_matched_exception(self.exceptions['broad'], error, feedback)
1152
+ raise ExchangeError(feedback)
1153
+ except Exception as e:
1154
+ if isinstance(e, AuthenticationError):
1155
+ messageHash = 'authenticated'
1156
+ client.reject(e, messageHash)
1157
+ if messageHash in client.subscriptions:
1158
+ del client.subscriptions[messageHash]
1159
+ else:
1160
+ client.reject(e, id)
1161
+ return True
1140
1162
  return False
1141
1163
 
1142
1164
  def handle_authenticate(self, client: Client, message):
@@ -234,7 +234,7 @@ class poloniexfutures(ccxt.async_support.poloniexfutures):
234
234
  async def watch_ticker(self, symbol: str, params={}) -> Ticker:
235
235
  """
236
236
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
237
- :see: https://futures-docs.poloniex.com/#get-real-time-symbol-ticker
237
+ :see: https://api-docs.poloniex.com/futures/websocket/public#get-real-time-symbol-ticker
238
238
  :param str symbol: unified symbol of the market to fetch the ticker for
239
239
  :param dict [params]: extra parameters specific to the exchange API endpoint
240
240
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -247,7 +247,7 @@ class poloniexfutures(ccxt.async_support.poloniexfutures):
247
247
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
248
248
  """
249
249
  get the list of most recent trades for a particular symbol
250
- :see: https://futures-docs.poloniex.com/#full-matching-engine-data-level-3
250
+ :see: https://api-docs.poloniex.com/futures/websocket/public#full-matching-engine-datalevel-3
251
251
  :param str symbol: unified symbol of the market to fetch trades for
252
252
  :param int [since]: timestamp in ms of the earliest trade to fetch
253
253
  :param int [limit]: the maximum amount of trades to fetch
@@ -267,7 +267,7 @@ class poloniexfutures(ccxt.async_support.poloniexfutures):
267
267
  async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
268
268
  """
269
269
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
270
- :see: https://futures-docs.poloniex.com/#level-2-market-data
270
+ :see: https://api-docs.poloniex.com/futures/websocket/public#level-2-market-data
271
271
  :param str symbol: unified symbol of the market to fetch the order book for
272
272
  :param int [limit]: not used by poloniexfutures watchOrderBook
273
273
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -293,7 +293,7 @@ class poloniexfutures(ccxt.async_support.poloniexfutures):
293
293
  async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
294
294
  """
295
295
  watches information on multiple orders made by the user
296
- :see: https://futures-docs.poloniex.com/#private-messages
296
+ :see: https://api-docs.poloniex.com/futures/websocket/user-messages#private-messages
297
297
  :param str symbol: filter by unified market symbol of the market orders were made in
298
298
  :param int [since]: the earliest time in ms to fetch orders for
299
299
  :param int [limit]: the maximum number of order structures to retrieve
@@ -316,7 +316,7 @@ class poloniexfutures(ccxt.async_support.poloniexfutures):
316
316
  async def watch_balance(self, params={}) -> Balances:
317
317
  """
318
318
  watch balance and get the amount of funds available for trading or funds locked in orders
319
- :see: https://futures-docs.poloniex.com/#account-balance-events
319
+ :see: https://api-docs.poloniex.com/futures/websocket/user-messages#account-balance-events
320
320
  :param dict [params]: extra parameters specific to the exchange API endpoint
321
321
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
322
322
  """
ccxt/pro/woo.py CHANGED
@@ -34,7 +34,7 @@ class woo(ccxt.async_support.woo):
34
34
  'api': {
35
35
  'ws': {
36
36
  'public': 'wss://wss.woo.org/ws/stream',
37
- 'private': 'wss://wss.woo.network/v2/ws/private/stream',
37
+ 'private': 'wss://wss.woo.org/v2/ws/private/stream',
38
38
  },
39
39
  },
40
40
  'test': {
@@ -79,7 +79,8 @@ class woo(ccxt.async_support.woo):
79
79
  return newValue
80
80
 
81
81
  async def watch_public(self, messageHash, message):
82
- url = self.urls['api']['ws']['public'] + '/' + self.uid
82
+ urlUid = '/' + self.uid if (self.uid) else ''
83
+ url = self.urls['api']['ws']['public'] + urlUid
83
84
  requestId = self.request_id(url)
84
85
  subscribe: dict = {
85
86
  'id': requestId,
@@ -456,7 +457,7 @@ class woo(ccxt.async_support.woo):
456
457
  marketId = self.safe_string(trade, 'symbol')
457
458
  market = self.safe_market(marketId, market)
458
459
  symbol = market['symbol']
459
- price = self.safe_string(trade, 'executedPrice', 'price')
460
+ price = self.safe_string_2(trade, 'executedPrice', 'price')
460
461
  amount = self.safe_string_2(trade, 'executedQuantity', 'size')
461
462
  cost = Precise.string_mul(price, amount)
462
463
  side = self.safe_string_lower(trade, 'side')
@@ -492,7 +493,7 @@ class woo(ccxt.async_support.woo):
492
493
  def check_required_uid(self, error=True):
493
494
  if not self.uid:
494
495
  if error:
495
- raise AuthenticationError(self.id + ' requires `uid` credential')
496
+ raise AuthenticationError(self.id + ' requires `uid` credential(woox calls it `application_id`)')
496
497
  else:
497
498
  return False
498
499
  return True
ccxt/woo.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.woo import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Account, Balances, Bool, Conversion, Currencies, Currency, Int, Leverage, MarginModification, Market, MarketType, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Trade, TradingFees, Transaction, TransferEntry, TransferEntries
9
+ from ccxt.base.types import Account, Balances, Bool, Conversion, Currencies, Currency, Int, Leverage, MarginModification, Market, MarketType, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Trade, TradingFees, Transaction, TransferEntry
10
10
  from typing import List
11
11
  from typing import Any
12
12
  from ccxt.base.errors import ExchangeError
@@ -2184,7 +2184,7 @@ class woo(Exchange, ImplicitAPI):
2184
2184
  transfer['toAccount'] = toAccount
2185
2185
  return transfer
2186
2186
 
2187
- def fetch_transfers(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> TransferEntries:
2187
+ def fetch_transfers(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[TransferEntry]:
2188
2188
  """
2189
2189
  fetch a history of internal transfers made on an account
2190
2190
  :see: https://docs.woo.org/#get-transfer-history