ccxt 4.1.87 → 4.1.89

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 (101) hide show
  1. package/CHANGELOG.md +8309 -5710
  2. package/README.md +10 -9
  3. package/changelog.js +101 -0
  4. package/dist/ccxt.browser.js +8628 -4849
  5. package/dist/ccxt.browser.min.js +3 -3
  6. package/dist/cjs/ccxt.js +6 -1
  7. package/dist/cjs/src/base/Exchange.js +95 -27
  8. package/dist/cjs/src/base/ws/Client.js +3 -3
  9. package/dist/cjs/src/base/ws/Future.js +9 -2
  10. package/dist/cjs/src/base/ws/WsClient.js +1 -1
  11. package/dist/cjs/src/bigone.js +8 -1
  12. package/dist/cjs/src/binance.js +4 -105
  13. package/dist/cjs/src/bit2c.js +8 -2
  14. package/dist/cjs/src/bitget.js +3455 -2480
  15. package/dist/cjs/src/bitmart.js +35 -9
  16. package/dist/cjs/src/coinbase.js +2 -0
  17. package/dist/cjs/src/coinbasepro.js +0 -43
  18. package/dist/cjs/src/coinex.js +14 -1
  19. package/dist/cjs/src/coinsph.js +0 -29
  20. package/dist/cjs/src/cryptocom.js +22 -10
  21. package/dist/cjs/src/gate.js +37 -39
  22. package/dist/cjs/src/gemini.js +1 -0
  23. package/dist/cjs/src/novadax.js +28 -16
  24. package/dist/cjs/src/okcoin.js +80 -21
  25. package/dist/cjs/src/phemex.js +105 -29
  26. package/dist/cjs/src/pro/binance.js +18 -215
  27. package/dist/cjs/src/pro/bitget.js +780 -736
  28. package/dist/cjs/src/pro/bitmart.js +8 -10
  29. package/dist/cjs/src/pro/bitmex.js +9 -34
  30. package/dist/cjs/src/pro/bitpanda.js +4 -4
  31. package/dist/cjs/src/pro/bybit.js +21 -97
  32. package/dist/cjs/src/pro/coinbasepro.js +36 -40
  33. package/dist/cjs/src/pro/cryptocom.js +10 -26
  34. package/dist/cjs/src/pro/gate.js +20 -17
  35. package/dist/cjs/src/pro/kucoin.js +39 -39
  36. package/dist/cjs/src/pro/kucoinfutures.js +40 -36
  37. package/dist/cjs/src/pro/okx.js +16 -29
  38. package/dist/cjs/src/tokocrypto.js +28 -14
  39. package/dist/cjs/src/woo.js +41 -14
  40. package/js/ccxt.d.ts +8 -2
  41. package/js/ccxt.js +6 -2
  42. package/js/src/abstract/bitget.d.ts +1 -1
  43. package/js/src/abstract/coinbasepro.d.ts +69 -0
  44. package/js/src/abstract/coinbasepro.js +11 -0
  45. package/js/src/abstract/phemex.d.ts +1 -0
  46. package/js/src/base/Exchange.d.ts +2 -3
  47. package/js/src/base/Exchange.js +96 -28
  48. package/js/src/base/ws/Client.d.ts +2 -2
  49. package/js/src/base/ws/Client.js +4 -4
  50. package/js/src/base/ws/Future.d.ts +5 -2
  51. package/js/src/base/ws/Future.js +8 -2
  52. package/js/src/base/ws/WsClient.d.ts +1 -1
  53. package/js/src/base/ws/WsClient.js +2 -2
  54. package/js/src/bigone.js +9 -2
  55. package/js/src/binance.d.ts +0 -9
  56. package/js/src/binance.js +4 -105
  57. package/js/src/bit2c.js +8 -2
  58. package/js/src/bitget.d.ts +13 -11
  59. package/js/src/bitget.js +3455 -2480
  60. package/js/src/bitmart.js +35 -9
  61. package/js/src/coinbase.js +2 -0
  62. package/js/src/coinbasepro.d.ts +0 -4
  63. package/js/src/coinbasepro.js +1 -44
  64. package/js/src/coinex.js +14 -1
  65. package/js/src/coinsph.d.ts +0 -1
  66. package/js/src/coinsph.js +0 -29
  67. package/js/src/cryptocom.js +22 -10
  68. package/js/src/gate.js +37 -39
  69. package/js/src/gemini.js +1 -0
  70. package/js/src/novadax.js +28 -16
  71. package/js/src/okcoin.d.ts +1 -0
  72. package/js/src/okcoin.js +81 -22
  73. package/js/src/phemex.d.ts +2 -108
  74. package/js/src/phemex.js +105 -29
  75. package/js/src/pro/binance.d.ts +0 -2
  76. package/js/src/pro/binance.js +19 -216
  77. package/js/src/pro/bitget.d.ts +3 -5
  78. package/js/src/pro/bitget.js +780 -736
  79. package/js/src/pro/bitmart.js +8 -10
  80. package/js/src/pro/bitmex.js +9 -34
  81. package/js/src/pro/bitpanda.d.ts +1 -1
  82. package/js/src/pro/bitpanda.js +4 -4
  83. package/js/src/pro/bybit.d.ts +1 -2
  84. package/js/src/pro/bybit.js +21 -97
  85. package/js/src/pro/coinbasepro.d.ts +2 -2
  86. package/js/src/pro/coinbasepro.js +36 -40
  87. package/js/src/pro/cryptocom.d.ts +1 -1
  88. package/js/src/pro/cryptocom.js +10 -26
  89. package/js/src/pro/gate.d.ts +1 -0
  90. package/js/src/pro/gate.js +20 -17
  91. package/js/src/pro/kucoin.d.ts +1 -0
  92. package/js/src/pro/kucoin.js +39 -39
  93. package/js/src/pro/kucoinfutures.d.ts +2 -1
  94. package/js/src/pro/kucoinfutures.js +40 -36
  95. package/js/src/pro/okx.d.ts +1 -1
  96. package/js/src/pro/okx.js +16 -29
  97. package/js/src/tokocrypto.js +28 -14
  98. package/js/src/woo.d.ts +1 -0
  99. package/js/src/woo.js +42 -15
  100. package/package.json +2 -2
  101. package/skip-tests.json +3 -14
@@ -139,6 +139,26 @@ export default class kucoinfutures extends kucoinfuturesRest {
139
139
  }
140
140
  return await this.watch(url, messageHash, message, subscriptionHash, subscription);
141
141
  }
142
+ async subscribeMultiple(url, messageHashes, topic, subscriptionHashes, subscription, params = {}) {
143
+ const requestId = this.requestId().toString();
144
+ const request = {
145
+ 'id': requestId,
146
+ 'type': 'subscribe',
147
+ 'topic': topic,
148
+ 'response': true,
149
+ };
150
+ const message = this.extend(request, params);
151
+ const subscriptionRequest = {
152
+ 'id': requestId,
153
+ };
154
+ if (subscription === undefined) {
155
+ subscription = subscriptionRequest;
156
+ }
157
+ else {
158
+ subscription = this.extend(subscriptionRequest, subscription);
159
+ }
160
+ return await this.watchMultiple(url, messageHashes, message, subscriptionHashes, subscription);
161
+ }
142
162
  async watchTicker(symbol, params = {}) {
143
163
  /**
144
164
  * @method
@@ -373,17 +393,7 @@ export default class kucoinfutures extends kucoinfuturesRest {
373
393
  * @param {object} [params] extra parameters specific to the exchange API endpoint
374
394
  * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
375
395
  */
376
- await this.loadMarkets();
377
- const url = await this.negotiate(false);
378
- const market = this.market(symbol);
379
- symbol = market['symbol'];
380
- const topic = '/contractMarket/execution:' + market['id'];
381
- const messageHash = 'trades:' + symbol;
382
- const trades = await this.subscribe(url, messageHash, topic, undefined, params);
383
- if (this.newUpdates) {
384
- limit = trades.getLimit(symbol, limit);
385
- }
386
- return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
396
+ return await this.watchTradesForSymbols([symbol], since, limit, params);
387
397
  }
388
398
  async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
389
399
  /**
@@ -406,8 +416,15 @@ export default class kucoinfutures extends kucoinfuturesRest {
406
416
  symbols = this.marketSymbols(symbols);
407
417
  const marketIds = this.marketIds(symbols);
408
418
  const topic = '/contractMarket/execution:' + marketIds.join(',');
409
- const messageHash = 'multipleTrades::' + symbols.join(',');
410
- const trades = await this.subscribe(url, messageHash, topic, params);
419
+ const subscriptionHashes = [];
420
+ const messageHashes = [];
421
+ for (let i = 0; i < symbols.length; i++) {
422
+ const symbol = symbols[i];
423
+ const marketId = marketIds[i];
424
+ messageHashes.push('trades:' + symbol);
425
+ subscriptionHashes.push('/contractMarket/execution:' + marketId);
426
+ }
427
+ const trades = await this.subscribeMultiple(url, messageHashes, topic, subscriptionHashes, params);
411
428
  if (this.newUpdates) {
412
429
  const first = this.safeValue(trades, 0);
413
430
  const tradeSymbol = this.safeString(first, 'symbol');
@@ -448,7 +465,6 @@ export default class kucoinfutures extends kucoinfuturesRest {
448
465
  trades.append(trade);
449
466
  const messageHash = 'trades:' + symbol;
450
467
  client.resolve(trades, messageHash);
451
- this.resolvePromiseIfMessagehashMatches(client, 'multipleTrades::', symbol, trades);
452
468
  return message;
453
469
  }
454
470
  async watchOrderBook(symbol, limit = undefined, params = {}) {
@@ -468,24 +484,7 @@ export default class kucoinfutures extends kucoinfuturesRest {
468
484
  * @param {object} [params] extra parameters specific to the exchange API endpoint
469
485
  * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
470
486
  */
471
- if (limit !== undefined) {
472
- if ((limit !== 20) && (limit !== 100)) {
473
- throw new ExchangeError(this.id + " watchOrderBook 'limit' argument must be undefined, 20 or 100");
474
- }
475
- }
476
- await this.loadMarkets();
477
- const url = await this.negotiate(false);
478
- const market = this.market(symbol);
479
- symbol = market['symbol'];
480
- const topic = '/contractMarket/level2:' + market['id'];
481
- const messageHash = 'orderbook:' + symbol;
482
- const subscription = {
483
- 'method': this.handleOrderBookSubscription,
484
- 'symbol': symbol,
485
- 'limit': limit,
486
- };
487
- const orderbook = await this.subscribe(url, messageHash, topic, subscription, params);
488
- return orderbook.limit();
487
+ return await this.watchOrderBookForSymbols([symbol], limit, params);
489
488
  }
490
489
  async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
491
490
  /**
@@ -511,13 +510,20 @@ export default class kucoinfutures extends kucoinfuturesRest {
511
510
  const marketIds = this.marketIds(symbols);
512
511
  const url = await this.negotiate(false);
513
512
  const topic = '/contractMarket/level2:' + marketIds.join(',');
514
- const messageHash = 'multipleOrderbook::' + symbols.join(',');
515
513
  const subscription = {
516
514
  'method': this.handleOrderBookSubscription,
517
515
  'symbols': symbols,
518
516
  'limit': limit,
519
517
  };
520
- const orderbook = await this.subscribe(url, messageHash, topic, subscription, params);
518
+ const subscriptionHashes = [];
519
+ const messageHashes = [];
520
+ for (let i = 0; i < symbols.length; i++) {
521
+ const symbol = symbols[i];
522
+ const marketId = marketIds[i];
523
+ messageHashes.push('orderbook:' + symbol);
524
+ subscriptionHashes.push('/contractMarket/level2:' + marketId);
525
+ }
526
+ const orderbook = await this.subscribeMultiple(url, messageHashes, topic, subscriptionHashes, subscription, params);
521
527
  return orderbook.limit();
522
528
  }
523
529
  handleDelta(orderbook, delta) {
@@ -598,7 +604,6 @@ export default class kucoinfutures extends kucoinfuturesRest {
598
604
  }
599
605
  this.handleDelta(storedOrderBook, data);
600
606
  client.resolve(storedOrderBook, messageHash);
601
- this.resolvePromiseIfMessagehashMatches(client, 'multipleOrderbook::', symbol, storedOrderBook);
602
607
  }
603
608
  getCacheIndex(orderbook, cache) {
604
609
  const firstDelta = this.safeValue(cache, 0);
@@ -648,7 +653,6 @@ export default class kucoinfutures extends kucoinfuturesRest {
648
653
  if (method !== undefined) {
649
654
  method.call(this, client, message, subscription);
650
655
  }
651
- return message;
652
656
  }
653
657
  handleSystemStatus(client, message) {
654
658
  //
@@ -8,7 +8,7 @@ export default class okx extends okxRest {
8
8
  subscribe(access: any, messageHash: any, channel: any, symbol: any, params?: {}): Promise<any>;
9
9
  watchTrades(symbol: string, since?: Int, limit?: Int, params?: {}): Promise<Trade[]>;
10
10
  watchTradesForSymbols(symbols: string[], since?: Int, limit?: Int, params?: {}): Promise<Trade[]>;
11
- handleTrades(client: Client, message: any): any;
11
+ handleTrades(client: Client, message: any): void;
12
12
  watchTicker(symbol: string, params?: {}): Promise<Ticker>;
13
13
  watchTickers(symbols?: Strings, params?: {}): Promise<Tickers>;
14
14
  handleTicker(client: Client, message: any): any;
package/js/src/pro/okx.js CHANGED
@@ -168,13 +168,7 @@ export default class okx extends okxRest {
168
168
  * @param {object} [params] extra parameters specific to the exchange API endpoint
169
169
  * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
170
170
  */
171
- await this.loadMarkets();
172
- symbol = this.symbol(symbol);
173
- const trades = await this.subscribe('public', 'trades', 'trades', symbol, params);
174
- if (this.newUpdates) {
175
- limit = trades.getLimit(symbol, limit);
176
- }
177
- return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
171
+ return await this.watchTradesForSymbols([symbol], since, limit, params);
178
172
  }
179
173
  async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
180
174
  /**
@@ -195,8 +189,11 @@ export default class okx extends okxRest {
195
189
  symbols = this.marketSymbols(symbols);
196
190
  const channel = 'trades';
197
191
  const topics = [];
192
+ const messageHashes = [];
198
193
  for (let i = 0; i < symbols.length; i++) {
199
- const marketId = this.marketId(symbols[i]);
194
+ const symbol = symbols[i];
195
+ messageHashes.push(channel + ':' + symbol);
196
+ const marketId = this.marketId(symbol);
200
197
  const topic = {
201
198
  'channel': channel,
202
199
  'instId': marketId,
@@ -207,9 +204,8 @@ export default class okx extends okxRest {
207
204
  'op': 'subscribe',
208
205
  'args': topics,
209
206
  };
210
- const messageHash = 'multipleTrades::' + symbols.join(',');
211
207
  const url = this.getUrl(channel, 'public');
212
- const trades = await this.watch(url, messageHash, request, messageHash);
208
+ const trades = await this.watchMultiple(url, messageHashes, request, messageHashes);
213
209
  if (this.newUpdates) {
214
210
  const first = this.safeValue(trades, 0);
215
211
  const tradeSymbol = this.safeString(first, 'symbol');
@@ -235,13 +231,13 @@ export default class okx extends okxRest {
235
231
  //
236
232
  const arg = this.safeValue(message, 'arg', {});
237
233
  const channel = this.safeString(arg, 'channel');
234
+ const marketId = this.safeString(arg, 'instId');
235
+ const symbol = this.safeSymbol(marketId);
238
236
  const data = this.safeValue(message, 'data', []);
239
237
  const tradesLimit = this.safeInteger(this.options, 'tradesLimit', 1000);
240
238
  for (let i = 0; i < data.length; i++) {
241
239
  const trade = this.parseTrade(data[i]);
242
- const symbol = trade['symbol'];
243
- const marketId = this.safeString(trade['info'], 'instId');
244
- const messageHash = channel + ':' + marketId;
240
+ const messageHash = channel + ':' + symbol;
245
241
  let stored = this.safeValue(this.trades, symbol);
246
242
  if (stored === undefined) {
247
243
  stored = new ArrayCache(tradesLimit);
@@ -249,9 +245,7 @@ export default class okx extends okxRest {
249
245
  }
250
246
  stored.append(trade);
251
247
  client.resolve(stored, messageHash);
252
- this.resolvePromiseIfMessagehashMatches(client, 'multipleTrades::', symbol, stored);
253
248
  }
254
- return message;
255
249
  }
256
250
  async watchTicker(symbol, params = {}) {
257
251
  /**
@@ -415,7 +409,6 @@ export default class okx extends okxRest {
415
409
  * @param {object} [params] extra parameters specific to the exchange API endpoint
416
410
  * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
417
411
  */
418
- const options = this.safeValue(this.options, 'watchOrderBook', {});
419
412
  //
420
413
  // bbo-tbt
421
414
  // 1. Newly added channel that sends tick-by-tick Level 1 data
@@ -439,12 +432,7 @@ export default class okx extends okxRest {
439
432
  // 2. Public depth channel, verification not required
440
433
  // 3. Data feeds will be delivered every 100ms (vs. every 200ms now)
441
434
  //
442
- const depth = this.safeString(options, 'depth', 'books');
443
- if ((depth === 'books-l2-tbt') || (depth === 'books50-l2-tbt')) {
444
- await this.authenticate({ 'access': 'public' });
445
- }
446
- const orderbook = await this.subscribe('public', depth, depth, symbol, params);
447
- return orderbook.limit();
435
+ return await this.watchOrderBookForSymbols([symbol], limit, params);
448
436
  }
449
437
  async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
450
438
  /**
@@ -464,8 +452,11 @@ export default class okx extends okxRest {
464
452
  await this.authenticate({ 'access': 'public' });
465
453
  }
466
454
  const topics = [];
455
+ const messageHashes = [];
467
456
  for (let i = 0; i < symbols.length; i++) {
468
- const marketId = this.marketId(symbols[i]);
457
+ const symbol = symbols[i];
458
+ messageHashes.push(depth + ':' + symbol);
459
+ const marketId = this.marketId(symbol);
469
460
  const topic = {
470
461
  'channel': depth,
471
462
  'instId': marketId,
@@ -477,8 +468,7 @@ export default class okx extends okxRest {
477
468
  'args': topics,
478
469
  };
479
470
  const url = this.getUrl(depth, 'public');
480
- const messageHash = 'multipleOrderbooks::' + symbols.join(',');
481
- const orderbook = await this.watch(url, messageHash, request, messageHash);
471
+ const orderbook = await this.watchMultiple(url, messageHashes, request, messageHashes);
482
472
  return orderbook.limit();
483
473
  }
484
474
  handleDelta(bookside, delta) {
@@ -651,7 +641,7 @@ export default class okx extends okxRest {
651
641
  'books50-l2-tbt': 50,
652
642
  };
653
643
  const limit = this.safeInteger(depths, channel);
654
- const messageHash = channel + ':' + marketId;
644
+ const messageHash = channel + ':' + symbol;
655
645
  if (action === 'snapshot') {
656
646
  for (let i = 0; i < data.length; i++) {
657
647
  const update = data[i];
@@ -660,7 +650,6 @@ export default class okx extends okxRest {
660
650
  orderbook['symbol'] = symbol;
661
651
  this.handleOrderBookMessage(client, update, orderbook, messageHash);
662
652
  client.resolve(orderbook, messageHash);
663
- this.resolvePromiseIfMessagehashMatches(client, 'multipleOrderbooks::', symbol, orderbook);
664
653
  }
665
654
  }
666
655
  else if (action === 'update') {
@@ -670,7 +659,6 @@ export default class okx extends okxRest {
670
659
  const update = data[i];
671
660
  this.handleOrderBookMessage(client, update, orderbook, messageHash);
672
661
  client.resolve(orderbook, messageHash);
673
- this.resolvePromiseIfMessagehashMatches(client, 'multipleOrderbooks::', symbol, orderbook);
674
662
  }
675
663
  }
676
664
  }
@@ -686,7 +674,6 @@ export default class okx extends okxRest {
686
674
  const snapshot = this.parseOrderBook(update, symbol, timestamp, 'bids', 'asks', 0, 1);
687
675
  orderbook.reset(snapshot);
688
676
  client.resolve(orderbook, messageHash);
689
- this.resolvePromiseIfMessagehashMatches(client, 'multipleOrderbooks::', symbol, orderbook);
690
677
  }
691
678
  }
692
679
  return message;
@@ -38,6 +38,9 @@ export default class tokocrypto extends Exchange {
38
38
  'cancelOrder': true,
39
39
  'cancelOrders': undefined,
40
40
  'createDepositAddress': false,
41
+ 'createMarketBuyOrderWithCost': true,
42
+ 'createMarketOrderWithCost': false,
43
+ 'createMarketSellOrderWithCost': false,
41
44
  'createOrder': true,
42
45
  'createReduceOnlyOrder': undefined,
43
46
  'createStopLimitOrder': true,
@@ -1580,6 +1583,7 @@ export default class tokocrypto extends Exchange {
1580
1583
  * @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1581
1584
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1582
1585
  * @param {float} [params.triggerPrice] the price at which a trigger order would be triggered
1586
+ * @param {float} [params.cost] for spot market buy orders, the quote quantity that can be used as an alternative for the amount
1583
1587
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1584
1588
  */
1585
1589
  await this.loadMarkets();
@@ -1659,20 +1663,30 @@ export default class tokocrypto extends Exchange {
1659
1663
  // LIMIT_MAKER quantity, price
1660
1664
  //
1661
1665
  if (uppercaseType === 'MARKET') {
1662
- const quoteOrderQtyInner = this.safeValue2(params, 'quoteOrderQty', 'cost');
1663
- if (this.options['createMarketBuyOrderRequiresPrice'] && (side === 'buy') && (price === undefined) && (quoteOrderQtyInner === undefined)) {
1664
- throw new InvalidOrder(this.id + ' createOrder() requires price argument for market buy orders on spot markets to calculate the total amount to spend (amount * price), alternatively set the createMarketBuyOrderRequiresPrice option to false and pass in the cost to spend into the amount parameter');
1665
- }
1666
- const precision = market['precision']['price'];
1667
- if (quoteOrderQtyInner !== undefined) {
1668
- request['quoteOrderQty'] = this.decimalToPrecision(quoteOrderQtyInner, TRUNCATE, precision, this.precisionMode);
1669
- params = this.omit(params, ['quoteOrderQty', 'cost']);
1670
- }
1671
- else if (price !== undefined) {
1672
- const amountString = this.numberToString(amount);
1673
- const priceString = this.numberToString(price);
1674
- const quoteOrderQty = Precise.stringMul(amountString, priceString);
1675
- request['quoteOrderQty'] = this.decimalToPrecision(quoteOrderQty, TRUNCATE, precision, this.precisionMode);
1666
+ if (side === 'buy') {
1667
+ const precision = market['precision']['price'];
1668
+ let quoteAmount = undefined;
1669
+ let createMarketBuyOrderRequiresPrice = true;
1670
+ [createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true);
1671
+ const cost = this.safeNumber2(params, 'cost', 'quoteOrderQty');
1672
+ params = this.omit(params, ['cost', 'quoteOrderQty']);
1673
+ if (cost !== undefined) {
1674
+ quoteAmount = cost;
1675
+ }
1676
+ else if (createMarketBuyOrderRequiresPrice) {
1677
+ if (price === undefined) {
1678
+ throw new InvalidOrder(this.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend (amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to false and pass the cost to spend (quote quantity) in the amount argument');
1679
+ }
1680
+ else {
1681
+ const amountString = this.numberToString(amount);
1682
+ const priceString = this.numberToString(price);
1683
+ quoteAmount = Precise.stringMul(amountString, priceString);
1684
+ }
1685
+ }
1686
+ else {
1687
+ quoteAmount = amount;
1688
+ }
1689
+ request['quoteOrderQty'] = this.decimalToPrecision(quoteAmount, TRUNCATE, precision, this.precisionMode);
1676
1690
  }
1677
1691
  else {
1678
1692
  quantityIsRequired = true;
package/js/src/woo.d.ts CHANGED
@@ -13,6 +13,7 @@ export default class woo extends Exchange {
13
13
  parseTokenAndFeeTemp(item: any, feeTokenKey: any, feeAmountKey: any): any;
14
14
  fetchTradingFees(params?: {}): Promise<{}>;
15
15
  fetchCurrencies(params?: {}): Promise<{}>;
16
+ createMarketBuyOrderWithCost(symbol: string, cost: any, params?: {}): Promise<Order>;
16
17
  createOrder(symbol: string, type: OrderType, side: OrderSide, amount: any, price?: any, params?: {}): Promise<Order>;
17
18
  editOrder(id: string, symbol: any, type: any, side: any, amount?: any, price?: any, params?: {}): Promise<Order>;
18
19
  cancelOrder(id: string, symbol?: Str, params?: {}): Promise<any>;
package/js/src/woo.js CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  // ---------------------------------------------------------------------------
8
8
  import Exchange from './abstract/woo.js';
9
- import { AuthenticationError, RateLimitExceeded, BadRequest, ExchangeError, InvalidOrder, ArgumentsRequired } from './base/errors.js';
9
+ import { AuthenticationError, RateLimitExceeded, BadRequest, ExchangeError, InvalidOrder, ArgumentsRequired, NotSupported } from './base/errors.js';
10
10
  import { Precise } from './base/Precise.js';
11
11
  import { TICK_SIZE } from './base/functions/number.js';
12
12
  import { sha256 } from './static_dependencies/noble-hashes/sha256.js';
@@ -40,7 +40,10 @@ export default class woo extends Exchange {
40
40
  'closeAllPositions': false,
41
41
  'closePosition': false,
42
42
  'createDepositAddress': false,
43
+ 'createMarketBuyOrderWithCost': true,
43
44
  'createMarketOrder': false,
45
+ 'createMarketOrderWithCost': false,
46
+ 'createMarketSellOrderWithCost': false,
44
47
  'createOrder': true,
45
48
  'createReduceOnlyOrder': true,
46
49
  'createStopLimitOrder': false,
@@ -742,6 +745,25 @@ export default class woo extends Exchange {
742
745
  }
743
746
  return result;
744
747
  }
748
+ async createMarketBuyOrderWithCost(symbol, cost, params = {}) {
749
+ /**
750
+ * @method
751
+ * @name woo#createMarketBuyOrderWithCost
752
+ * @description create a market buy order by providing the symbol and cost
753
+ * @see https://docs.woo.org/#send-order
754
+ * @param {string} symbol unified symbol of the market to create an order in
755
+ * @param {float} cost how much you want to trade in units of the quote currency
756
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
757
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
758
+ */
759
+ await this.loadMarkets();
760
+ const market = this.market(symbol);
761
+ if (!market['spot']) {
762
+ throw new NotSupported(this.id + ' createMarketBuyOrderWithCost() supports spot orders only');
763
+ }
764
+ params['createMarketBuyOrderRequiresPrice'] = false;
765
+ return await this.createOrder(symbol, 'market', 'buy', cost, undefined, params);
766
+ }
745
767
  async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
746
768
  /**
747
769
  * @method
@@ -761,9 +783,11 @@ export default class woo extends Exchange {
761
783
  * @param {object} [params.stopLoss] *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered (perpetual swap markets only)
762
784
  * @param {float} [params.stopLoss.triggerPrice] stop loss trigger price
763
785
  * @param {float} [params.algoType] 'STOP'or 'TRAILING_STOP' or 'OCO' or 'CLOSE_POSITION'
786
+ * @param {float} [params.cost] *spot market buy only* the quote quantity that can be used as an alternative for the amount
764
787
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
765
788
  */
766
789
  const reduceOnly = this.safeValue2(params, 'reduceOnly', 'reduce_only');
790
+ params = this.omit(params, ['reduceOnly', 'reduce_only']);
767
791
  const orderType = type.toUpperCase();
768
792
  await this.loadMarkets();
769
793
  const market = this.market(symbol);
@@ -806,26 +830,29 @@ export default class woo extends Exchange {
806
830
  if (isMarket && !isStop) {
807
831
  // for market buy it requires the amount of quote currency to spend
808
832
  if (market['spot'] && orderSide === 'BUY') {
809
- const cost = this.safeNumber(params, 'cost');
810
- if (this.safeValue(this.options, 'createMarketBuyOrderRequiresPrice', true)) {
811
- if (cost === undefined) {
812
- if (price === undefined) {
813
- throw new InvalidOrder(this.id + " createOrder() requires the price argument for market buy orders to calculate total order cost. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or alternatively, supply the total cost value in the 'order_amount' in exchange-specific parameters");
814
- }
815
- else {
816
- const amountString = this.numberToString(amount);
817
- const priceString = this.numberToString(price);
818
- const orderAmount = Precise.stringMul(amountString, priceString);
819
- request['order_amount'] = this.costToPrecision(symbol, orderAmount);
820
- }
833
+ let quoteAmount = undefined;
834
+ let createMarketBuyOrderRequiresPrice = true;
835
+ [createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true);
836
+ const cost = this.safeNumber2(params, 'cost', 'order_amount');
837
+ params = this.omit(params, ['cost', 'order_amount']);
838
+ if (cost !== undefined) {
839
+ quoteAmount = this.costToPrecision(symbol, cost);
840
+ }
841
+ else if (createMarketBuyOrderRequiresPrice) {
842
+ if (price === undefined) {
843
+ throw new InvalidOrder(this.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend (amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to false and pass the cost to spend (quote quantity) in the amount argument');
821
844
  }
822
845
  else {
823
- request['order_amount'] = this.costToPrecision(symbol, cost);
846
+ const amountString = this.numberToString(amount);
847
+ const priceString = this.numberToString(price);
848
+ const costRequest = Precise.stringMul(amountString, priceString);
849
+ quoteAmount = this.costToPrecision(symbol, costRequest);
824
850
  }
825
851
  }
826
852
  else {
827
- request['order_amount'] = this.costToPrecision(symbol, amount);
853
+ quoteAmount = this.costToPrecision(symbol, amount);
828
854
  }
855
+ request['order_amount'] = quoteAmount;
829
856
  }
830
857
  else {
831
858
  request['order_quantity'] = this.amountToPrecision(symbol, amount);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ccxt",
3
- "version": "4.1.87",
4
- "description": "A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 130+ exchanges",
3
+ "version": "4.1.89",
4
+ "description": "A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges",
5
5
  "unpkg": "dist/ccxt.browser.js",
6
6
  "type": "module",
7
7
  "exports": {
package/skip-tests.json CHANGED
@@ -350,7 +350,9 @@
350
350
  },
351
351
  "fetchTickers": {
352
352
  "quoteVolume": "quoteVolume >= baseVolume * low is failing",
353
- "baseVolume": "quoteVolume >= baseVolume * low is failing"
353
+ "baseVolume": "quoteVolume >= baseVolume * low is failing",
354
+ "bid": "bid ask crossed",
355
+ "ask": "bid ask crossed"
354
356
  },
355
357
  "fetchTicker": {
356
358
  "quoteVolume": "quoteVolume >= baseVolume * low is failing",
@@ -467,19 +469,6 @@
467
469
  "fetchOHLCV": "open might be greater than high"
468
470
  }
469
471
  },
470
- "bittrex": {
471
- "skipWs": true,
472
- "skipMethods": {
473
- "fetchStatus": "frequent rate limit for this endpoint",
474
- "fetchTickers": "bid might be set to 0",
475
- "fetchTicker": "same",
476
- "fetchCurrencies": {
477
- "withdraw": "not provided",
478
- "deposit": "not provided",
479
- "networks":"missing"
480
- }
481
- }
482
- },
483
472
  "btcbox": {
484
473
  "skipMethods": {
485
474
  "loadMarkets": {