ccxt 4.2.89__py2.py3-none-any.whl → 4.2.91__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 (71) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/bingx.py +2 -0
  3. ccxt/abstract/bybit.py +2 -0
  4. ccxt/ascendex.py +1 -0
  5. ccxt/async_support/__init__.py +1 -1
  6. ccxt/async_support/ascendex.py +1 -0
  7. ccxt/async_support/base/exchange.py +13 -1
  8. ccxt/async_support/binance.py +81 -9
  9. ccxt/async_support/bingx.py +94 -1
  10. ccxt/async_support/bitfinex2.py +1 -0
  11. ccxt/async_support/bitget.py +2 -0
  12. ccxt/async_support/bitmex.py +1 -0
  13. ccxt/async_support/bitrue.py +1 -0
  14. ccxt/async_support/bybit.py +50 -0
  15. ccxt/async_support/coinbase.py +43 -21
  16. ccxt/async_support/coinbaseinternational.py +1 -0
  17. ccxt/async_support/coinex.py +96 -8
  18. ccxt/async_support/cryptocom.py +1 -0
  19. ccxt/async_support/delta.py +1 -0
  20. ccxt/async_support/digifinex.py +1 -0
  21. ccxt/async_support/exmo.py +1 -0
  22. ccxt/async_support/gate.py +2 -0
  23. ccxt/async_support/gemini.py +11 -9
  24. ccxt/async_support/hitbtc.py +1 -0
  25. ccxt/async_support/htx.py +1 -0
  26. ccxt/async_support/hyperliquid.py +1 -0
  27. ccxt/async_support/kraken.py +11 -8
  28. ccxt/async_support/kucoin.py +1 -0
  29. ccxt/async_support/kucoinfutures.py +32 -4
  30. ccxt/async_support/mexc.py +1 -0
  31. ccxt/async_support/okx.py +173 -38
  32. ccxt/async_support/phemex.py +1 -0
  33. ccxt/async_support/woo.py +1 -0
  34. ccxt/base/exchange.py +53 -14
  35. ccxt/base/types.py +1 -0
  36. ccxt/binance.py +81 -9
  37. ccxt/bingx.py +94 -1
  38. ccxt/bitfinex2.py +1 -0
  39. ccxt/bitget.py +2 -0
  40. ccxt/bitmex.py +1 -0
  41. ccxt/bitrue.py +1 -0
  42. ccxt/bybit.py +50 -0
  43. ccxt/coinbase.py +43 -21
  44. ccxt/coinbaseinternational.py +1 -0
  45. ccxt/coinex.py +96 -8
  46. ccxt/cryptocom.py +1 -0
  47. ccxt/delta.py +1 -0
  48. ccxt/digifinex.py +1 -0
  49. ccxt/exmo.py +1 -0
  50. ccxt/gate.py +2 -0
  51. ccxt/gemini.py +11 -9
  52. ccxt/hitbtc.py +1 -0
  53. ccxt/htx.py +1 -0
  54. ccxt/hyperliquid.py +1 -0
  55. ccxt/kraken.py +11 -8
  56. ccxt/kucoin.py +1 -0
  57. ccxt/kucoinfutures.py +32 -4
  58. ccxt/mexc.py +1 -0
  59. ccxt/okx.py +173 -38
  60. ccxt/phemex.py +1 -0
  61. ccxt/pro/__init__.py +1 -1
  62. ccxt/pro/bitmex.py +35 -17
  63. ccxt/pro/kucoin.py +85 -0
  64. ccxt/pro/kucoinfutures.py +141 -76
  65. ccxt/test/test_async.py +15 -1
  66. ccxt/test/test_sync.py +15 -1
  67. ccxt/woo.py +1 -0
  68. {ccxt-4.2.89.dist-info → ccxt-4.2.91.dist-info}/METADATA +4 -4
  69. {ccxt-4.2.89.dist-info → ccxt-4.2.91.dist-info}/RECORD +71 -71
  70. {ccxt-4.2.89.dist-info → ccxt-4.2.91.dist-info}/WHEEL +0 -0
  71. {ccxt-4.2.89.dist-info → ccxt-4.2.91.dist-info}/top_level.txt +0 -0
ccxt/pro/kucoinfutures.py CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  import ccxt.async_support
7
7
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById
8
- from ccxt.base.types import Balances, Int, Order, OrderBook, Position, Str, Ticker, Trade
8
+ from ccxt.base.types import Balances, Int, Order, OrderBook, Position, Str, Strings, Ticker, Tickers, Trade
9
9
  from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
@@ -19,6 +19,8 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
19
19
  'has': {
20
20
  'ws': True,
21
21
  'watchTicker': True,
22
+ 'watchTickers': True,
23
+ 'watchBidsAsks': True,
22
24
  'watchTrades': True,
23
25
  'watchOrderBook': True,
24
26
  'watchOrders': True,
@@ -48,9 +50,6 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
48
50
  'snapshotDelay': 20,
49
51
  'snapshotMaxRetries': 3,
50
52
  },
51
- 'watchTicker': {
52
- 'name': 'contractMarket/tickerV2', # market/ticker
53
- },
54
53
  'watchPosition': {
55
54
  'fetchPositionSnapshot': True, # or False
56
55
  'awaitPositionSnapshot': True, # whether to wait for the position snapshot before providing updates
@@ -146,7 +145,7 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
146
145
  subscription = self.extend(subscriptionRequest, subscription)
147
146
  return await self.watch(url, messageHash, message, subscriptionHash, subscription)
148
147
 
149
- async def subscribe_multiple(self, url, messageHashes, topic, subscriptionHashes, subscription, params={}):
148
+ async def subscribe_multiple(self, url, messageHashes, topic, subscriptionHashes, subscriptionArgs, params={}):
150
149
  requestId = str(self.request_id())
151
150
  request = {
152
151
  'id': requestId,
@@ -154,20 +153,12 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
154
153
  'topic': topic,
155
154
  'response': True,
156
155
  }
157
- message = self.extend(request, params)
158
- subscriptionRequest = {
159
- 'id': requestId,
160
- }
161
- if subscription is None:
162
- subscription = subscriptionRequest
163
- else:
164
- subscription = self.extend(subscriptionRequest, subscription)
165
- return await self.watch_multiple(url, messageHashes, message, subscriptionHashes, subscription)
156
+ return await self.watch_multiple(url, messageHashes, self.extend(request, params), subscriptionHashes, subscriptionArgs)
166
157
 
167
158
  async def watch_ticker(self, symbol: str, params={}) -> Ticker:
168
159
  """
169
160
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
170
- :see: https://docs.kucoin.com/futures/#get-real-time-symbol-ticker-v2
161
+ :see: https://www.kucoin.com/docs/websocket/futures-trading/public-channels/get-ticker
171
162
  :param str symbol: unified symbol of the market to fetch the ticker for
172
163
  :param dict [params]: extra parameters specific to the exchange API endpoint
173
164
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -175,30 +166,45 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
175
166
  await self.load_markets()
176
167
  market = self.market(symbol)
177
168
  symbol = market['symbol']
178
- url = await self.negotiate(False)
179
- options = self.safe_value(self.options, 'watchTicker', {})
180
- channel = self.safe_string(options, 'name', 'contractMarket/tickerV2')
181
- topic = '/' + channel + ':' + market['id']
182
- messageHash = 'ticker:' + symbol
183
- return await self.subscribe(url, messageHash, topic, None, params)
169
+ params['callerMethodName'] = 'watchTicker'
170
+ tickers = await self.watch_tickers([symbol], params)
171
+ return tickers[symbol]
172
+
173
+ async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
174
+ """
175
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
176
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
177
+ :param dict [params]: extra parameters specific to the exchange API endpoint
178
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
179
+ """
180
+ await self.load_markets()
181
+ ticker = await self.watch_multi_request('watchTickers', '/contractMarket/ticker:', symbols, params)
182
+ if self.newUpdates:
183
+ tickers = {}
184
+ tickers[ticker['symbol']] = ticker
185
+ return tickers
186
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
184
187
 
185
188
  def handle_ticker(self, client: Client, message):
186
189
  #
187
- # market/tickerV2
190
+ # ticker(v1)
188
191
  #
189
192
  # {
190
- # "type": "message",
191
- # "topic": "/contractMarket/tickerV2:ADAUSDTM",
192
- # "subject": "tickerV2",
193
- # "data": {
194
- # "symbol": "ADAUSDTM",
195
- # "sequence": 1668007800439,
196
- # "bestBidSize": 178,
197
- # "bestBidPrice": "0.35959",
198
- # "bestAskPrice": "0.35981",
199
- # "ts": "1668141430037124460",
200
- # "bestAskSize": 134
201
- # }
193
+ # "subject": "ticker",
194
+ # "topic": "/contractMarket/ticker:XBTUSDM",
195
+ # "data": {
196
+ # "symbol": "XBTUSDM", #Market of the symbol
197
+ # "sequence": 45, #Sequence number which is used to judge the continuity of the pushed messages
198
+ # "side": "sell", #Transaction side of the last traded taker order
199
+ # "price": "3600.0", #Filled price
200
+ # "size": 16, #Filled quantity
201
+ # "tradeId": "5c9dcf4170744d6f5a3d32fb", #Order ID
202
+ # "bestBidSize": 795, #Best bid size
203
+ # "bestBidPrice": "3200.0", #Best bid
204
+ # "bestAskPrice": "3600.0", #Best ask size
205
+ # "bestAskSize": 284, #Best ask
206
+ # "ts": 1553846081210004941 #Filled time - nanosecond
207
+ # }
202
208
  # }
203
209
  #
204
210
  data = self.safe_value(message, 'data', {})
@@ -206,9 +212,90 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
206
212
  market = self.safe_market(marketId, None, '-')
207
213
  ticker = self.parse_ticker(data, market)
208
214
  self.tickers[market['symbol']] = ticker
209
- messageHash = 'ticker:' + market['symbol']
210
- client.resolve(ticker, messageHash)
211
- return message
215
+ client.resolve(ticker, self.get_message_hash('ticker', market['symbol']))
216
+
217
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
218
+ """
219
+ :see: https://www.kucoin.com/docs/websocket/futures-trading/public-channels/get-ticker-v2
220
+ watches best bid & ask for symbols
221
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
222
+ :param dict [params]: extra parameters specific to the exchange API endpoint
223
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
224
+ """
225
+ ticker = await self.watch_multi_request('watchBidsAsks', '/contractMarket/tickerV2:', symbols, params)
226
+ if self.newUpdates:
227
+ tickers = {}
228
+ tickers[ticker['symbol']] = ticker
229
+ return tickers
230
+ return self.filter_by_array(self.bidsasks, 'symbol', symbols)
231
+
232
+ async def watch_multi_request(self, methodName, channelName: str, symbols: Strings = None, params={}):
233
+ await self.load_markets()
234
+ methodName, params = self.handle_param_string(params, 'callerMethodName', methodName)
235
+ isBidsAsks = (methodName == 'watchBidsAsks')
236
+ symbols = self.market_symbols(symbols, None, False, True, False)
237
+ length = len(symbols)
238
+ if length > 100:
239
+ raise ArgumentsRequired(self.id + ' ' + methodName + '() accepts a maximum of 100 symbols')
240
+ messageHashes = []
241
+ for i in range(0, len(symbols)):
242
+ symbol = symbols[i]
243
+ market = self.market(symbol)
244
+ prefix = 'bidask' if isBidsAsks else 'ticker'
245
+ messageHashes.append(self.get_message_hash(prefix, market['symbol']))
246
+ url = await self.negotiate(False)
247
+ marketIds = self.market_ids(symbols)
248
+ joined = ','.join(marketIds)
249
+ requestId = str(self.request_id())
250
+ request = {
251
+ 'id': requestId,
252
+ 'type': 'subscribe',
253
+ 'topic': channelName + joined,
254
+ 'response': True,
255
+ }
256
+ subscription = {
257
+ 'id': requestId,
258
+ }
259
+ return await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes, subscription)
260
+
261
+ def handle_bid_ask(self, client: Client, message):
262
+ #
263
+ # arrives one symbol dict
264
+ #
265
+ # {
266
+ # "subject": "tickerV2",
267
+ # "topic": "/contractMarket/tickerV2:XBTUSDM",
268
+ # "data": {
269
+ # "symbol": "XBTUSDM", #Market of the symbol
270
+ # "bestBidSize": 795, # Best bid size
271
+ # "bestBidPrice": 3200.0, # Best bid
272
+ # "bestAskPrice": 3600.0, # Best ask
273
+ # "bestAskSize": 284, # Best ask size
274
+ # "ts": 1553846081210004941 # Filled time - nanosecond
275
+ # }
276
+ # }
277
+ #
278
+ parsedTicker = self.parse_ws_bid_ask(message)
279
+ symbol = parsedTicker['symbol']
280
+ self.bidsasks[symbol] = parsedTicker
281
+ client.resolve(parsedTicker, self.get_message_hash('bidask', symbol))
282
+
283
+ def parse_ws_bid_ask(self, ticker, market=None):
284
+ data = self.safe_dict(ticker, 'data', {})
285
+ marketId = self.safe_string(data, 'symbol')
286
+ market = self.safe_market(marketId, market)
287
+ symbol = self.safe_string(market, 'symbol')
288
+ timestamp = self.safe_integer_product(data, 'ts', 0.000001)
289
+ return self.safe_ticker({
290
+ 'symbol': symbol,
291
+ 'timestamp': timestamp,
292
+ 'datetime': self.iso8601(timestamp),
293
+ 'ask': self.safe_number(data, 'bestAskPrice'),
294
+ 'askVolume': self.safe_number(data, 'bestAskSize'),
295
+ 'bid': self.safe_number(data, 'bestBidPrice'),
296
+ 'bidVolume': self.safe_number(data, 'bestBidSize'),
297
+ 'info': ticker,
298
+ }, market)
212
299
 
213
300
  async def watch_position(self, symbol: Str = None, params={}) -> Position:
214
301
  """
@@ -412,7 +499,7 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
412
499
  marketId = marketIds[i]
413
500
  messageHashes.append('trades:' + symbol)
414
501
  subscriptionHashes.append('/contractMarket/execution:' + marketId)
415
- trades = await self.subscribe_multiple(url, messageHashes, topic, subscriptionHashes, params)
502
+ trades = await self.subscribe_multiple(url, messageHashes, topic, subscriptionHashes, None, params)
416
503
  if self.newUpdates:
417
504
  first = self.safe_value(trades, 0)
418
505
  tradeSymbol = self.safe_string(first, 'symbol')
@@ -489,9 +576,7 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
489
576
  marketIds = self.market_ids(symbols)
490
577
  url = await self.negotiate(False)
491
578
  topic = '/contractMarket/level2:' + ','.join(marketIds)
492
- subscription = {
493
- 'method': self.handle_order_book_subscription,
494
- 'symbols': symbols,
579
+ subscriptionArgs = {
495
580
  'limit': limit,
496
581
  }
497
582
  subscriptionHashes = []
@@ -501,7 +586,7 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
501
586
  marketId = marketIds[i]
502
587
  messageHashes.append('orderbook:' + symbol)
503
588
  subscriptionHashes.append('/contractMarket/level2:' + marketId)
504
- orderbook = await self.subscribe_multiple(url, messageHashes, topic, subscriptionHashes, subscription, params)
589
+ orderbook = await self.subscribe_multiple(url, messageHashes, topic, subscriptionHashes, subscriptionArgs, params)
505
590
  return orderbook.limit()
506
591
 
507
592
  def handle_delta(self, orderbook, delta):
@@ -549,10 +634,12 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
549
634
  marketId = self.safe_string(topicParts, 1)
550
635
  symbol = self.safe_symbol(marketId, None, '-')
551
636
  messageHash = 'orderbook:' + symbol
552
- storedOrderBook = self.safe_value(self.orderbooks, symbol)
637
+ if not (symbol in self.orderbooks):
638
+ subscriptionArgs = self.safe_dict(client.subscriptions, topic, {})
639
+ limit = self.safe_integer(subscriptionArgs, 'limit')
640
+ self.orderbooks[symbol] = self.order_book({}, limit)
641
+ storedOrderBook = self.orderbooks[symbol]
553
642
  nonce = self.safe_integer(storedOrderBook, 'nonce')
554
- if storedOrderBook is None:
555
- return # self shouldn't be needed, but for some reason sometimes self runs before handleOrderBookSubscription in c#
556
643
  deltaEnd = self.safe_integer(data, 'sequence')
557
644
  if nonce is None:
558
645
  cacheLength = len(storedOrderBook.cache)
@@ -590,35 +677,6 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
590
677
  return i
591
678
  return len(cache)
592
679
 
593
- def handle_order_book_subscription(self, client: Client, message, subscription):
594
- limit = self.safe_integer(subscription, 'limit')
595
- symbols = self.safe_value(subscription, 'symbols')
596
- if symbols is None:
597
- symbol = self.safe_string(subscription, 'symbol')
598
- self.orderbooks[symbol] = self.order_book({}, limit)
599
- else:
600
- for i in range(0, len(symbols)):
601
- symbol = symbols[i]
602
- self.orderbooks[symbol] = self.order_book({}, limit)
603
- # moved snapshot initialization to handleOrderBook to fix
604
- # https://github.com/ccxt/ccxt/issues/6820
605
- # the general idea is to fetch the snapshot after the first delta
606
- # but not before, because otherwise we cannot synchronize the feed
607
-
608
- def handle_subscription_status(self, client: Client, message):
609
- #
610
- # {
611
- # "id": "1578090438322",
612
- # "type": "ack"
613
- # }
614
- #
615
- id = self.safe_string(message, 'id')
616
- subscriptionsById = self.index_by(client.subscriptions, 'id')
617
- subscription = self.safe_value(subscriptionsById, id, {})
618
- method = self.safe_value(subscription, 'method')
619
- if method is not None:
620
- method(client, message, subscription)
621
-
622
680
  def handle_system_status(self, client: Client, message):
623
681
  #
624
682
  # todo: answer the question whether handleSystemStatus should be renamed
@@ -864,7 +922,8 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
864
922
  subject = self.safe_string(message, 'subject')
865
923
  methods = {
866
924
  'level2': self.handle_order_book,
867
- 'tickerV2': self.handle_ticker,
925
+ 'ticker': self.handle_ticker,
926
+ 'tickerV2': self.handle_bid_ask,
868
927
  'availableBalance.change': self.handle_balance,
869
928
  'match': self.handle_trade,
870
929
  'orderChange': self.handle_order,
@@ -877,6 +936,13 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
877
936
  if method is not None:
878
937
  method(client, message)
879
938
 
939
+ def get_message_hash(self, elementName: str, symbol: Str = None):
940
+ # elementName can be 'ticker', 'bidask', ...
941
+ if symbol is not None:
942
+ return elementName + '@' + symbol
943
+ else:
944
+ return elementName + 's@all'
945
+
880
946
  def ping(self, client):
881
947
  # kucoin does not support built-in ws protocol-level ping-pong
882
948
  # instead it requires a custom json-based text ping-pong
@@ -914,7 +980,6 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
914
980
  methods = {
915
981
  # 'heartbeat': self.handleHeartbeat,
916
982
  'welcome': self.handle_system_status,
917
- 'ack': self.handle_subscription_status,
918
983
  'message': self.handle_subject,
919
984
  'pong': self.handle_pong,
920
985
  'error': self.handle_error_message,
ccxt/test/test_async.py CHANGED
@@ -1235,7 +1235,7 @@ class testMainClass(baseMainTestClass):
1235
1235
  # -----------------------------------------------------------------------------
1236
1236
  # --- Init of brokerId tests functions-----------------------------------------
1237
1237
  # -----------------------------------------------------------------------------
1238
- 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()]
1238
+ 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()]
1239
1239
  await asyncio.gather(*promises)
1240
1240
  success_message = '[' + self.lang + '][TEST_SUCCESS] brokerId tests passed.'
1241
1241
  dump('[INFO]' + success_message)
@@ -1534,6 +1534,20 @@ class testMainClass(baseMainTestClass):
1534
1534
  await close(exchange)
1535
1535
  return True
1536
1536
 
1537
+ async def test_coinbase_advanced(self):
1538
+ exchange = self.init_offline_exchange('coinbase')
1539
+ id = 'ccxt'
1540
+ assert exchange.options['brokerId'] == id, 'id not in options'
1541
+ request = None
1542
+ try:
1543
+ await exchange.create_order('BTC/USDC', 'limit', 'buy', 1, 20000)
1544
+ except Exception as e:
1545
+ request = json_parse(exchange.last_request_body)
1546
+ client_order_id = request['client_order_id']
1547
+ assert client_order_id.startswith(str(id)), 'clientOrderId does not start with id'
1548
+ await close(exchange)
1549
+ return True
1550
+
1537
1551
  # ***** AUTO-TRANSPILER-END *****
1538
1552
  # *******************************
1539
1553
 
ccxt/test/test_sync.py CHANGED
@@ -1234,7 +1234,7 @@ class testMainClass(baseMainTestClass):
1234
1234
  # -----------------------------------------------------------------------------
1235
1235
  # --- Init of brokerId tests functions-----------------------------------------
1236
1236
  # -----------------------------------------------------------------------------
1237
- 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()]
1237
+ 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()]
1238
1238
  (promises)
1239
1239
  success_message = '[' + self.lang + '][TEST_SUCCESS] brokerId tests passed.'
1240
1240
  dump('[INFO]' + success_message)
@@ -1533,6 +1533,20 @@ class testMainClass(baseMainTestClass):
1533
1533
  close(exchange)
1534
1534
  return True
1535
1535
 
1536
+ def test_coinbase_advanced(self):
1537
+ exchange = self.init_offline_exchange('coinbase')
1538
+ id = 'ccxt'
1539
+ assert exchange.options['brokerId'] == id, 'id not in options'
1540
+ request = None
1541
+ try:
1542
+ exchange.create_order('BTC/USDC', 'limit', 'buy', 1, 20000)
1543
+ except Exception as e:
1544
+ request = json_parse(exchange.last_request_body)
1545
+ client_order_id = request['client_order_id']
1546
+ assert client_order_id.startswith(str(id)), 'clientOrderId does not start with id'
1547
+ close(exchange)
1548
+ return True
1549
+
1536
1550
  # ***** AUTO-TRANSPILER-END *****
1537
1551
  # *******************************
1538
1552
 
ccxt/woo.py CHANGED
@@ -77,6 +77,7 @@ class woo(Exchange, ImplicitAPI):
77
77
  'fetchIndexOHLCV': False,
78
78
  'fetchLedger': True,
79
79
  'fetchLeverage': True,
80
+ 'fetchMarginAdjustmentHistory': False,
80
81
  'fetchMarginMode': False,
81
82
  'fetchMarkets': True,
82
83
  'fetchMarkOHLCV': False,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ccxt
3
- Version: 4.2.89
3
+ Version: 4.2.91
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
@@ -261,13 +261,13 @@ console.log(version, Object.keys(exchanges));
261
261
 
262
262
  All-in-one browser bundle (dependencies included), served from a CDN of your choice:
263
263
 
264
- * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.2.89/dist/ccxt.browser.js
265
- * unpkg: https://unpkg.com/ccxt@4.2.89/dist/ccxt.browser.js
264
+ * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.2.91/dist/ccxt.browser.js
265
+ * unpkg: https://unpkg.com/ccxt@4.2.91/dist/ccxt.browser.js
266
266
 
267
267
  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.
268
268
 
269
269
  ```HTML
270
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.2.89/dist/ccxt.browser.js"></script>
270
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.2.91/dist/ccxt.browser.js"></script>
271
271
  ```
272
272
 
273
273
  Creates a global `ccxt` object: